authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-27 01:14:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-27 01:14:50-07:00
logc8fb36b36cd8368e84752770edf720e6e91ed997
treedb0821f54a28f552240d27becaf4b1538b613d2e
parentf41b9cdb6d7f954495ffca168108ddd38bf27353

stage2: LLVM backend: implement `@tagName` for enums

Introduced a new AIR instruction: `tag_name`. Reasons to do this instead of lowering it in Sema to a switch, function call, array lookup, or if-else tower: * Sema is a bottleneck; do less work in Sema whenever possible. * If any optimization passes run, and the operand to becomes comptime-known, then it could change to have a comptime result value instead of lowering to a function or array or something which would then have to be garbage-collected. * Backends may want to choose to use a function and a switch branch, or they may want to use a different strategy. Codegen for `@tagName` is implemented for the LLVM backend but not any others yet. Introduced some new `Type` tags: * `const_slice_u8_sentinel_0` * `manyptr_const_u8_sentinel_0` The motivation for this was to make typeof() on the tag_name AIR instruction non-allocating. A bunch more enum tests are passing now.

17 files changed, 1083 insertions(+), 706 deletions(-)

src/Air.zig+7
...@@ -496,6 +496,11 @@ pub const Inst = struct {...@@ -496,6 +496,11 @@ pub const Inst = struct {
496 /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`.496 /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`.
497 atomic_rmw,497 atomic_rmw,
498498
499 /// Given an enum tag value, returns the tag name. The enum type may be non-exhaustive.
500 /// Result type is always `[:0]const u8`.
501 /// Uses the `un_op` field.
502 tag_name,
503
499 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {504 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
500 return switch (op) {505 return switch (op) {
501 .lt => .cmp_lt,506 .lt => .cmp_lt,
...@@ -811,6 +816,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -811,6 +816,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
811816
812 .bool_to_int => return Type.initTag(.u1),817 .bool_to_int => return Type.initTag(.u1),
813818
819 .tag_name => return Type.initTag(.const_slice_u8_sentinel_0),
820
814 .call => {821 .call => {
815 const callee_ty = air.typeOf(datas[inst].pl_op.operand);822 const callee_ty = air.typeOf(datas[inst].pl_op.operand);
816 switch (callee_ty.zigTypeTag()) {823 switch (callee_ty.zigTypeTag()) {
src/Liveness.zig+1
...@@ -333,6 +333,7 @@ fn analyzeInst(...@@ -333,6 +333,7 @@ fn analyzeInst(
333 .bool_to_int,333 .bool_to_int,
334 .ret,334 .ret,
335 .ret_load,335 .ret_load,
336 .tag_name,
336 => {337 => {
337 const operand = inst_datas[inst].un_op;338 const operand = inst_datas[inst].un_op;
338 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });339 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
src/Sema.zig+49-2
...@@ -2804,8 +2804,11 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -2804,8 +2804,11 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
2804 const tracy = trace(@src());2804 const tracy = trace(@src());
2805 defer tracy.end();2805 defer tracy.end();
28062806
2807 const zir_bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);2807 const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
2808 return sema.addStrLit(block, bytes);
2809}
28082810
2811fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air.Inst.Ref {
2809 // `zir_bytes` references memory inside the ZIR module, which can get deallocated2812 // `zir_bytes` references memory inside the ZIR module, which can get deallocated
2810 // after semantic analysis is complete, for example in the case of the initialization2813 // after semantic analysis is complete, for example in the case of the initialization
2811 // expression of a variable declaration. We need the memory to be in the new2814 // 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...@@ -10045,8 +10048,50 @@ fn zirUnaryMath(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1004510048
10046fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10049fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
10047 const inst_data = sema.code.instructions.items(.data)[inst].un_node;10050 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
10051 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
10048 const src = inst_data.src();10052 const src = inst_data.src();
10049 return sema.fail(block, src, "TODO: Sema.zirTagName", .{});10053 const operand = sema.resolveInst(inst_data.operand);
10054 const operand_ty = sema.typeOf(operand);
10055
10056 const enum_ty = switch (operand_ty.zigTypeTag()) {
10057 .Enum => operand_ty,
10058 .Union => operand_ty.unionTagType() orelse {
10059 const decl = operand_ty.getOwnerDecl();
10060 const msg = msg: {
10061 const msg = try sema.errMsg(block, src, "union '{s}' is untagged", .{
10062 decl.name,
10063 });
10064 errdefer msg.destroy(sema.gpa);
10065 try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "declared here", .{});
10066 break :msg msg;
10067 };
10068 return sema.failWithOwnedErrorMsg(msg);
10069 },
10070 else => return sema.fail(block, operand_src, "expected enum or union; found {}", .{
10071 operand_ty,
10072 }),
10073 };
10074 const enum_decl = enum_ty.getOwnerDecl();
10075 const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src);
10076 if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| {
10077 const field_index = enum_ty.enumTagFieldIndex(val) orelse {
10078 const msg = msg: {
10079 const msg = try sema.errMsg(block, src, "no field with value {} in enum '{s}'", .{
10080 casted_operand, enum_decl.name,
10081 });
10082 errdefer msg.destroy(sema.gpa);
10083 try sema.mod.errNoteNonLazy(enum_decl.srcLoc(), msg, "declared here", .{});
10084 break :msg msg;
10085 };
10086 return sema.failWithOwnedErrorMsg(msg);
10087 };
10088 const field_name = enum_ty.enumFieldName(field_index);
10089 return sema.addStrLit(block, field_name);
10090 }
10091 // In case the value is runtime-known, we have an AIR instruction for this instead
10092 // of trying to lower it in Sema because an optimization pass may result in the operand
10093 // being comptime-known, which would let us elide the `tag_name` AIR instruction.
10094 return block.addUnOp(.tag_name, casted_operand);
10050}10095}
1005110096
10052fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10097fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -15339,6 +15384,7 @@ fn typeHasOnePossibleValue(...@@ -15339,6 +15384,7 @@ fn typeHasOnePossibleValue(
15339 .array_sentinel,15384 .array_sentinel,
15340 .array_u8_sentinel_0,15385 .array_u8_sentinel_0,
15341 .const_slice_u8,15386 .const_slice_u8,
15387 .const_slice_u8_sentinel_0,
15342 .const_slice,15388 .const_slice,
15343 .mut_slice,15389 .mut_slice,
15344 .anyopaque,15390 .anyopaque,
...@@ -15356,6 +15402,7 @@ fn typeHasOnePossibleValue(...@@ -15356,6 +15402,7 @@ fn typeHasOnePossibleValue(
15356 .var_args_param,15402 .var_args_param,
15357 .manyptr_u8,15403 .manyptr_u8,
15358 .manyptr_const_u8,15404 .manyptr_const_u8,
15405 .manyptr_const_u8_sentinel_0,
15359 .atomic_order,15406 .atomic_order,
15360 .atomic_rmw_op,15407 .atomic_rmw_op,
15361 .calling_convention,15408 .calling_convention,
src/arch/aarch64/CodeGen.zig+138-127
...@@ -504,133 +504,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -504,133 +504,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
504504
505 switch (air_tags[inst]) {505 switch (air_tags[inst]) {
506 // zig fmt: off506 // zig fmt: off
507 .add, .ptr_add => try self.airAdd(inst),507 .add, .ptr_add => try self.airAdd(inst),
508 .addwrap => try self.airAddWrap(inst),508 .addwrap => try self.airAddWrap(inst),
509 .add_sat => try self.airAddSat(inst),509 .add_sat => try self.airAddSat(inst),
510 .sub, .ptr_sub => try self.airSub(inst),510 .sub, .ptr_sub => try self.airSub(inst),
511 .subwrap => try self.airSubWrap(inst),511 .subwrap => try self.airSubWrap(inst),
512 .sub_sat => try self.airSubSat(inst),512 .sub_sat => try self.airSubSat(inst),
513 .mul => try self.airMul(inst),513 .mul => try self.airMul(inst),
514 .mulwrap => try self.airMulWrap(inst),514 .mulwrap => try self.airMulWrap(inst),
515 .mul_sat => try self.airMulSat(inst),515 .mul_sat => try self.airMulSat(inst),
516 .rem => try self.airRem(inst),516 .rem => try self.airRem(inst),
517 .mod => try self.airMod(inst),517 .mod => try self.airMod(inst),
518 .shl, .shl_exact => try self.airShl(inst),518 .shl, .shl_exact => try self.airShl(inst),
519 .shl_sat => try self.airShlSat(inst),519 .shl_sat => try self.airShlSat(inst),
520 .min => try self.airMin(inst),520 .min => try self.airMin(inst),
521 .max => try self.airMax(inst),521 .max => try self.airMax(inst),
522 .slice => try self.airSlice(inst),522 .slice => try self.airSlice(inst),
523523
524 .add_with_overflow => try self.airAddWithOverflow(inst),524 .add_with_overflow => try self.airAddWithOverflow(inst),
525 .sub_with_overflow => try self.airSubWithOverflow(inst),525 .sub_with_overflow => try self.airSubWithOverflow(inst),
526 .mul_with_overflow => try self.airMulWithOverflow(inst),526 .mul_with_overflow => try self.airMulWithOverflow(inst),
527 .shl_with_overflow => try self.airShlWithOverflow(inst),527 .shl_with_overflow => try self.airShlWithOverflow(inst),
528528
529 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),529 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
530530
531 .cmp_lt => try self.airCmp(inst, .lt),531 .cmp_lt => try self.airCmp(inst, .lt),
532 .cmp_lte => try self.airCmp(inst, .lte),532 .cmp_lte => try self.airCmp(inst, .lte),
533 .cmp_eq => try self.airCmp(inst, .eq),533 .cmp_eq => try self.airCmp(inst, .eq),
534 .cmp_gte => try self.airCmp(inst, .gte),534 .cmp_gte => try self.airCmp(inst, .gte),
535 .cmp_gt => try self.airCmp(inst, .gt),535 .cmp_gt => try self.airCmp(inst, .gt),
536 .cmp_neq => try self.airCmp(inst, .neq),536 .cmp_neq => try self.airCmp(inst, .neq),
537537
538 .bool_and => try self.airBoolOp(inst),538 .bool_and => try self.airBoolOp(inst),
539 .bool_or => try self.airBoolOp(inst),539 .bool_or => try self.airBoolOp(inst),
540 .bit_and => try self.airBitAnd(inst),540 .bit_and => try self.airBitAnd(inst),
541 .bit_or => try self.airBitOr(inst),541 .bit_or => try self.airBitOr(inst),
542 .xor => try self.airXor(inst),542 .xor => try self.airXor(inst),
543 .shr => try self.airShr(inst),543 .shr => try self.airShr(inst),
544544
545 .alloc => try self.airAlloc(inst),545 .alloc => try self.airAlloc(inst),
546 .ret_ptr => try self.airRetPtr(inst),546 .ret_ptr => try self.airRetPtr(inst),
547 .arg => try self.airArg(inst),547 .arg => try self.airArg(inst),
548 .assembly => try self.airAsm(inst),548 .assembly => try self.airAsm(inst),
549 .bitcast => try self.airBitCast(inst),549 .bitcast => try self.airBitCast(inst),
550 .block => try self.airBlock(inst),550 .block => try self.airBlock(inst),
551 .br => try self.airBr(inst),551 .br => try self.airBr(inst),
552 .breakpoint => try self.airBreakpoint(),552 .breakpoint => try self.airBreakpoint(),
553 .ret_addr => try self.airRetAddr(),553 .ret_addr => try self.airRetAddr(),
554 .fence => try self.airFence(),554 .fence => try self.airFence(),
555 .call => try self.airCall(inst),555 .call => try self.airCall(inst),
556 .cond_br => try self.airCondBr(inst),556 .cond_br => try self.airCondBr(inst),
557 .dbg_stmt => try self.airDbgStmt(inst),557 .dbg_stmt => try self.airDbgStmt(inst),
558 .fptrunc => try self.airFptrunc(inst),558 .fptrunc => try self.airFptrunc(inst),
559 .fpext => try self.airFpext(inst),559 .fpext => try self.airFpext(inst),
560 .intcast => try self.airIntCast(inst),560 .intcast => try self.airIntCast(inst),
561 .trunc => try self.airTrunc(inst),561 .trunc => try self.airTrunc(inst),
562 .bool_to_int => try self.airBoolToInt(inst),562 .bool_to_int => try self.airBoolToInt(inst),
563 .is_non_null => try self.airIsNonNull(inst),563 .is_non_null => try self.airIsNonNull(inst),
564 .is_non_null_ptr => try self.airIsNonNullPtr(inst),564 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
565 .is_null => try self.airIsNull(inst),565 .is_null => try self.airIsNull(inst),
566 .is_null_ptr => try self.airIsNullPtr(inst),566 .is_null_ptr => try self.airIsNullPtr(inst),
567 .is_non_err => try self.airIsNonErr(inst),567 .is_non_err => try self.airIsNonErr(inst),
568 .is_non_err_ptr => try self.airIsNonErrPtr(inst),568 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
569 .is_err => try self.airIsErr(inst),569 .is_err => try self.airIsErr(inst),
570 .is_err_ptr => try self.airIsErrPtr(inst),570 .is_err_ptr => try self.airIsErrPtr(inst),
571 .load => try self.airLoad(inst),571 .load => try self.airLoad(inst),
572 .loop => try self.airLoop(inst),572 .loop => try self.airLoop(inst),
573 .not => try self.airNot(inst),573 .not => try self.airNot(inst),
574 .ptrtoint => try self.airPtrToInt(inst),574 .ptrtoint => try self.airPtrToInt(inst),
575 .ret => try self.airRet(inst),575 .ret => try self.airRet(inst),
576 .ret_load => try self.airRetLoad(inst),576 .ret_load => try self.airRetLoad(inst),
577 .store => try self.airStore(inst),577 .store => try self.airStore(inst),
578 .struct_field_ptr=> try self.airStructFieldPtr(inst),578 .struct_field_ptr=> try self.airStructFieldPtr(inst),
579 .struct_field_val=> try self.airStructFieldVal(inst),579 .struct_field_val=> try self.airStructFieldVal(inst),
580 .array_to_slice => try self.airArrayToSlice(inst),580 .array_to_slice => try self.airArrayToSlice(inst),
581 .int_to_float => try self.airIntToFloat(inst),581 .int_to_float => try self.airIntToFloat(inst),
582 .float_to_int => try self.airFloatToInt(inst),582 .float_to_int => try self.airFloatToInt(inst),
583 .cmpxchg_strong => try self.airCmpxchg(inst),583 .cmpxchg_strong => try self.airCmpxchg(inst),
584 .cmpxchg_weak => try self.airCmpxchg(inst),584 .cmpxchg_weak => try self.airCmpxchg(inst),
585 .atomic_rmw => try self.airAtomicRmw(inst),585 .atomic_rmw => try self.airAtomicRmw(inst),
586 .atomic_load => try self.airAtomicLoad(inst),586 .atomic_load => try self.airAtomicLoad(inst),
587 .memcpy => try self.airMemcpy(inst),587 .memcpy => try self.airMemcpy(inst),
588 .memset => try self.airMemset(inst),588 .memset => try self.airMemset(inst),
589 .set_union_tag => try self.airSetUnionTag(inst),589 .set_union_tag => try self.airSetUnionTag(inst),
590 .get_union_tag => try self.airGetUnionTag(inst),590 .get_union_tag => try self.airGetUnionTag(inst),
591 .clz => try self.airClz(inst),591 .clz => try self.airClz(inst),
592 .ctz => try self.airCtz(inst),592 .ctz => try self.airCtz(inst),
593 .popcount => try self.airPopcount(inst),593 .popcount => try self.airPopcount(inst),
594594 .tag_name => try self.airTagName(inst),
595 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),595
596 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),596 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
597 .atomic_store_release => try self.airAtomicStore(inst, .Release),597 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
598 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),598 .atomic_store_release => try self.airAtomicStore(inst, .Release),
599599 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
600 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),600
601 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),601 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
602 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),602 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
603 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),603 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
604604 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
605 .switch_br => try self.airSwitch(inst),605
606 .slice_ptr => try self.airSlicePtr(inst),606 .switch_br => try self.airSwitch(inst),
607 .slice_len => try self.airSliceLen(inst),607 .slice_ptr => try self.airSlicePtr(inst),
608608 .slice_len => try self.airSliceLen(inst),
609 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),609
610 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),610 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
611611 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
612 .array_elem_val => try self.airArrayElemVal(inst),612
613 .slice_elem_val => try self.airSliceElemVal(inst),613 .array_elem_val => try self.airArrayElemVal(inst),
614 .slice_elem_ptr => try self.airSliceElemPtr(inst),614 .slice_elem_val => try self.airSliceElemVal(inst),
615 .ptr_elem_val => try self.airPtrElemVal(inst),615 .slice_elem_ptr => try self.airSliceElemPtr(inst),
616 .ptr_elem_ptr => try self.airPtrElemPtr(inst),616 .ptr_elem_val => try self.airPtrElemVal(inst),
617617 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
618 .constant => unreachable, // excluded from function bodies618
619 .const_ty => unreachable, // excluded from function bodies619 .constant => unreachable, // excluded from function bodies
620 .unreach => self.finishAirBookkeeping(),620 .const_ty => unreachable, // excluded from function bodies
621621 .unreach => self.finishAirBookkeeping(),
622 .optional_payload => try self.airOptionalPayload(inst),622
623 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),623 .optional_payload => try self.airOptionalPayload(inst),
624 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),624 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
625 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),625 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
626 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),626 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
627 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),627 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
628 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),628 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
629629 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
630 .wrap_optional => try self.airWrapOptional(inst),630
631 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),631 .wrap_optional => try self.airWrapOptional(inst),
632 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),632 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
633 // zig fmt: on633 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
634 // zig fmt: on
634 }635 }
635 if (std.debug.runtime_safety) {636 if (std.debug.runtime_safety) {
636 if (self.air_bookkeeping < old_air_bookkeeping + 1) {637 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
...@@ -2546,6 +2547,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -2546,6 +2547,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
2546 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});2547 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
2547}2548}
25482549
2550fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
2551 const un_op = self.air.instructions.items(.data)[inst].un_op;
2552 const operand = try self.resolveInst(un_op);
2553 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
2554 _ = operand;
2555 return self.fail("TODO implement airTagName for aarch64", .{});
2556 };
2557 return self.finishAir(inst, result, .{ un_op, .none, .none });
2558}
2559
2549fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {2560fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
2550 // First section of indexes correspond to a set number of constant values.2561 // First section of indexes correspond to a set number of constant values.
2551 const ref_int = @enumToInt(inst);2562 const ref_int = @enumToInt(inst);
src/arch/arm/CodeGen.zig+138-127
...@@ -502,133 +502,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -502,133 +502,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
502502
503 switch (air_tags[inst]) {503 switch (air_tags[inst]) {
504 // zig fmt: off504 // zig fmt: off
505 .add, .ptr_add => try self.airAdd(inst),505 .add, .ptr_add => try self.airAdd(inst),
506 .addwrap => try self.airAddWrap(inst),506 .addwrap => try self.airAddWrap(inst),
507 .add_sat => try self.airAddSat(inst),507 .add_sat => try self.airAddSat(inst),
508 .sub, .ptr_sub => try self.airSub(inst),508 .sub, .ptr_sub => try self.airSub(inst),
509 .subwrap => try self.airSubWrap(inst),509 .subwrap => try self.airSubWrap(inst),
510 .sub_sat => try self.airSubSat(inst),510 .sub_sat => try self.airSubSat(inst),
511 .mul => try self.airMul(inst),511 .mul => try self.airMul(inst),
512 .mulwrap => try self.airMulWrap(inst),512 .mulwrap => try self.airMulWrap(inst),
513 .mul_sat => try self.airMulSat(inst),513 .mul_sat => try self.airMulSat(inst),
514 .rem => try self.airRem(inst),514 .rem => try self.airRem(inst),
515 .mod => try self.airMod(inst),515 .mod => try self.airMod(inst),
516 .shl, .shl_exact => try self.airShl(inst),516 .shl, .shl_exact => try self.airShl(inst),
517 .shl_sat => try self.airShlSat(inst),517 .shl_sat => try self.airShlSat(inst),
518 .min => try self.airMin(inst),518 .min => try self.airMin(inst),
519 .max => try self.airMax(inst),519 .max => try self.airMax(inst),
520 .slice => try self.airSlice(inst),520 .slice => try self.airSlice(inst),
521521
522 .add_with_overflow => try self.airAddWithOverflow(inst),522 .add_with_overflow => try self.airAddWithOverflow(inst),
523 .sub_with_overflow => try self.airSubWithOverflow(inst),523 .sub_with_overflow => try self.airSubWithOverflow(inst),
524 .mul_with_overflow => try self.airMulWithOverflow(inst),524 .mul_with_overflow => try self.airMulWithOverflow(inst),
525 .shl_with_overflow => try self.airShlWithOverflow(inst),525 .shl_with_overflow => try self.airShlWithOverflow(inst),
526526
527 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),527 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
528528
529 .cmp_lt => try self.airCmp(inst, .lt),529 .cmp_lt => try self.airCmp(inst, .lt),
530 .cmp_lte => try self.airCmp(inst, .lte),530 .cmp_lte => try self.airCmp(inst, .lte),
531 .cmp_eq => try self.airCmp(inst, .eq),531 .cmp_eq => try self.airCmp(inst, .eq),
532 .cmp_gte => try self.airCmp(inst, .gte),532 .cmp_gte => try self.airCmp(inst, .gte),
533 .cmp_gt => try self.airCmp(inst, .gt),533 .cmp_gt => try self.airCmp(inst, .gt),
534 .cmp_neq => try self.airCmp(inst, .neq),534 .cmp_neq => try self.airCmp(inst, .neq),
535535
536 .bool_and => try self.airBoolOp(inst),536 .bool_and => try self.airBoolOp(inst),
537 .bool_or => try self.airBoolOp(inst),537 .bool_or => try self.airBoolOp(inst),
538 .bit_and => try self.airBitAnd(inst),538 .bit_and => try self.airBitAnd(inst),
539 .bit_or => try self.airBitOr(inst),539 .bit_or => try self.airBitOr(inst),
540 .xor => try self.airXor(inst),540 .xor => try self.airXor(inst),
541 .shr => try self.airShr(inst),541 .shr => try self.airShr(inst),
542542
543 .alloc => try self.airAlloc(inst),543 .alloc => try self.airAlloc(inst),
544 .ret_ptr => try self.airRetPtr(inst),544 .ret_ptr => try self.airRetPtr(inst),
545 .arg => try self.airArg(inst),545 .arg => try self.airArg(inst),
546 .assembly => try self.airAsm(inst),546 .assembly => try self.airAsm(inst),
547 .bitcast => try self.airBitCast(inst),547 .bitcast => try self.airBitCast(inst),
548 .block => try self.airBlock(inst),548 .block => try self.airBlock(inst),
549 .br => try self.airBr(inst),549 .br => try self.airBr(inst),
550 .breakpoint => try self.airBreakpoint(),550 .breakpoint => try self.airBreakpoint(),
551 .ret_addr => try self.airRetAddr(),551 .ret_addr => try self.airRetAddr(),
552 .fence => try self.airFence(),552 .fence => try self.airFence(),
553 .call => try self.airCall(inst),553 .call => try self.airCall(inst),
554 .cond_br => try self.airCondBr(inst),554 .cond_br => try self.airCondBr(inst),
555 .dbg_stmt => try self.airDbgStmt(inst),555 .dbg_stmt => try self.airDbgStmt(inst),
556 .fptrunc => try self.airFptrunc(inst),556 .fptrunc => try self.airFptrunc(inst),
557 .fpext => try self.airFpext(inst),557 .fpext => try self.airFpext(inst),
558 .intcast => try self.airIntCast(inst),558 .intcast => try self.airIntCast(inst),
559 .trunc => try self.airTrunc(inst),559 .trunc => try self.airTrunc(inst),
560 .bool_to_int => try self.airBoolToInt(inst),560 .bool_to_int => try self.airBoolToInt(inst),
561 .is_non_null => try self.airIsNonNull(inst),561 .is_non_null => try self.airIsNonNull(inst),
562 .is_non_null_ptr => try self.airIsNonNullPtr(inst),562 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
563 .is_null => try self.airIsNull(inst),563 .is_null => try self.airIsNull(inst),
564 .is_null_ptr => try self.airIsNullPtr(inst),564 .is_null_ptr => try self.airIsNullPtr(inst),
565 .is_non_err => try self.airIsNonErr(inst),565 .is_non_err => try self.airIsNonErr(inst),
566 .is_non_err_ptr => try self.airIsNonErrPtr(inst),566 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
567 .is_err => try self.airIsErr(inst),567 .is_err => try self.airIsErr(inst),
568 .is_err_ptr => try self.airIsErrPtr(inst),568 .is_err_ptr => try self.airIsErrPtr(inst),
569 .load => try self.airLoad(inst),569 .load => try self.airLoad(inst),
570 .loop => try self.airLoop(inst),570 .loop => try self.airLoop(inst),
571 .not => try self.airNot(inst),571 .not => try self.airNot(inst),
572 .ptrtoint => try self.airPtrToInt(inst),572 .ptrtoint => try self.airPtrToInt(inst),
573 .ret => try self.airRet(inst),573 .ret => try self.airRet(inst),
574 .ret_load => try self.airRetLoad(inst),574 .ret_load => try self.airRetLoad(inst),
575 .store => try self.airStore(inst),575 .store => try self.airStore(inst),
576 .struct_field_ptr=> try self.airStructFieldPtr(inst),576 .struct_field_ptr=> try self.airStructFieldPtr(inst),
577 .struct_field_val=> try self.airStructFieldVal(inst),577 .struct_field_val=> try self.airStructFieldVal(inst),
578 .array_to_slice => try self.airArrayToSlice(inst),578 .array_to_slice => try self.airArrayToSlice(inst),
579 .int_to_float => try self.airIntToFloat(inst),579 .int_to_float => try self.airIntToFloat(inst),
580 .float_to_int => try self.airFloatToInt(inst),580 .float_to_int => try self.airFloatToInt(inst),
581 .cmpxchg_strong => try self.airCmpxchg(inst),581 .cmpxchg_strong => try self.airCmpxchg(inst),
582 .cmpxchg_weak => try self.airCmpxchg(inst),582 .cmpxchg_weak => try self.airCmpxchg(inst),
583 .atomic_rmw => try self.airAtomicRmw(inst),583 .atomic_rmw => try self.airAtomicRmw(inst),
584 .atomic_load => try self.airAtomicLoad(inst),584 .atomic_load => try self.airAtomicLoad(inst),
585 .memcpy => try self.airMemcpy(inst),585 .memcpy => try self.airMemcpy(inst),
586 .memset => try self.airMemset(inst),586 .memset => try self.airMemset(inst),
587 .set_union_tag => try self.airSetUnionTag(inst),587 .set_union_tag => try self.airSetUnionTag(inst),
588 .get_union_tag => try self.airGetUnionTag(inst),588 .get_union_tag => try self.airGetUnionTag(inst),
589 .clz => try self.airClz(inst),589 .clz => try self.airClz(inst),
590 .ctz => try self.airCtz(inst),590 .ctz => try self.airCtz(inst),
591 .popcount => try self.airPopcount(inst),591 .popcount => try self.airPopcount(inst),
592592 .tag_name => try self.airTagName(inst),
593 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),593
594 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),594 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
595 .atomic_store_release => try self.airAtomicStore(inst, .Release),595 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
596 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),596 .atomic_store_release => try self.airAtomicStore(inst, .Release),
597597 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
598 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),598
599 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),599 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
600 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),600 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
601 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),601 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
602602 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
603 .switch_br => try self.airSwitch(inst),603
604 .slice_ptr => try self.airSlicePtr(inst),604 .switch_br => try self.airSwitch(inst),
605 .slice_len => try self.airSliceLen(inst),605 .slice_ptr => try self.airSlicePtr(inst),
606606 .slice_len => try self.airSliceLen(inst),
607 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),607
608 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),608 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
609609 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
610 .array_elem_val => try self.airArrayElemVal(inst),610
611 .slice_elem_val => try self.airSliceElemVal(inst),611 .array_elem_val => try self.airArrayElemVal(inst),
612 .slice_elem_ptr => try self.airSliceElemPtr(inst),612 .slice_elem_val => try self.airSliceElemVal(inst),
613 .ptr_elem_val => try self.airPtrElemVal(inst),613 .slice_elem_ptr => try self.airSliceElemPtr(inst),
614 .ptr_elem_ptr => try self.airPtrElemPtr(inst),614 .ptr_elem_val => try self.airPtrElemVal(inst),
615615 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
616 .constant => unreachable, // excluded from function bodies616
617 .const_ty => unreachable, // excluded from function bodies617 .constant => unreachable, // excluded from function bodies
618 .unreach => self.finishAirBookkeeping(),618 .const_ty => unreachable, // excluded from function bodies
619619 .unreach => self.finishAirBookkeeping(),
620 .optional_payload => try self.airOptionalPayload(inst),620
621 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),621 .optional_payload => try self.airOptionalPayload(inst),
622 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),622 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
623 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),623 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
624 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),624 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
625 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),625 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
626 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),626 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
627627 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
628 .wrap_optional => try self.airWrapOptional(inst),628
629 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),629 .wrap_optional => try self.airWrapOptional(inst),
630 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),630 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
631 // zig fmt: on631 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
632 // zig fmt: on
632 }633 }
633 if (std.debug.runtime_safety) {634 if (std.debug.runtime_safety) {
634 if (self.air_bookkeeping < old_air_bookkeeping + 1) {635 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
...@@ -3301,6 +3302,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -3301,6 +3302,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
3301 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});3302 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
3302}3303}
33033304
3305fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
3306 const un_op = self.air.instructions.items(.data)[inst].un_op;
3307 const operand = try self.resolveInst(un_op);
3308 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
3309 _ = operand;
3310 return self.fail("TODO implement airTagName for arm", .{});
3311 };
3312 return self.finishAir(inst, result, .{ un_op, .none, .none });
3313}
3314
3304fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {3315fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
3305 // First section of indexes correspond to a set number of constant values.3316 // First section of indexes correspond to a set number of constant values.
3306 const ref_int = @enumToInt(inst);3317 const ref_int = @enumToInt(inst);
src/arch/riscv64/CodeGen.zig+138-127
...@@ -483,133 +483,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -483,133 +483,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
483483
484 switch (air_tags[inst]) {484 switch (air_tags[inst]) {
485 // zig fmt: off485 // zig fmt: off
486 .add, .ptr_add => try self.airAdd(inst),486 .add, .ptr_add => try self.airAdd(inst),
487 .addwrap => try self.airAddWrap(inst),487 .addwrap => try self.airAddWrap(inst),
488 .add_sat => try self.airAddSat(inst),488 .add_sat => try self.airAddSat(inst),
489 .sub, .ptr_sub => try self.airSub(inst),489 .sub, .ptr_sub => try self.airSub(inst),
490 .subwrap => try self.airSubWrap(inst),490 .subwrap => try self.airSubWrap(inst),
491 .sub_sat => try self.airSubSat(inst),491 .sub_sat => try self.airSubSat(inst),
492 .mul => try self.airMul(inst),492 .mul => try self.airMul(inst),
493 .mulwrap => try self.airMulWrap(inst),493 .mulwrap => try self.airMulWrap(inst),
494 .mul_sat => try self.airMulSat(inst),494 .mul_sat => try self.airMulSat(inst),
495 .rem => try self.airRem(inst),495 .rem => try self.airRem(inst),
496 .mod => try self.airMod(inst),496 .mod => try self.airMod(inst),
497 .shl, .shl_exact => try self.airShl(inst),497 .shl, .shl_exact => try self.airShl(inst),
498 .shl_sat => try self.airShlSat(inst),498 .shl_sat => try self.airShlSat(inst),
499 .min => try self.airMin(inst),499 .min => try self.airMin(inst),
500 .max => try self.airMax(inst),500 .max => try self.airMax(inst),
501 .slice => try self.airSlice(inst),501 .slice => try self.airSlice(inst),
502502
503 .add_with_overflow => try self.airAddWithOverflow(inst),503 .add_with_overflow => try self.airAddWithOverflow(inst),
504 .sub_with_overflow => try self.airSubWithOverflow(inst),504 .sub_with_overflow => try self.airSubWithOverflow(inst),
505 .mul_with_overflow => try self.airMulWithOverflow(inst),505 .mul_with_overflow => try self.airMulWithOverflow(inst),
506 .shl_with_overflow => try self.airShlWithOverflow(inst),506 .shl_with_overflow => try self.airShlWithOverflow(inst),
507507
508 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),508 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
509509
510 .cmp_lt => try self.airCmp(inst, .lt),510 .cmp_lt => try self.airCmp(inst, .lt),
511 .cmp_lte => try self.airCmp(inst, .lte),511 .cmp_lte => try self.airCmp(inst, .lte),
512 .cmp_eq => try self.airCmp(inst, .eq),512 .cmp_eq => try self.airCmp(inst, .eq),
513 .cmp_gte => try self.airCmp(inst, .gte),513 .cmp_gte => try self.airCmp(inst, .gte),
514 .cmp_gt => try self.airCmp(inst, .gt),514 .cmp_gt => try self.airCmp(inst, .gt),
515 .cmp_neq => try self.airCmp(inst, .neq),515 .cmp_neq => try self.airCmp(inst, .neq),
516516
517 .bool_and => try self.airBoolOp(inst),517 .bool_and => try self.airBoolOp(inst),
518 .bool_or => try self.airBoolOp(inst),518 .bool_or => try self.airBoolOp(inst),
519 .bit_and => try self.airBitAnd(inst),519 .bit_and => try self.airBitAnd(inst),
520 .bit_or => try self.airBitOr(inst),520 .bit_or => try self.airBitOr(inst),
521 .xor => try self.airXor(inst),521 .xor => try self.airXor(inst),
522 .shr => try self.airShr(inst),522 .shr => try self.airShr(inst),
523523
524 .alloc => try self.airAlloc(inst),524 .alloc => try self.airAlloc(inst),
525 .ret_ptr => try self.airRetPtr(inst),525 .ret_ptr => try self.airRetPtr(inst),
526 .arg => try self.airArg(inst),526 .arg => try self.airArg(inst),
527 .assembly => try self.airAsm(inst),527 .assembly => try self.airAsm(inst),
528 .bitcast => try self.airBitCast(inst),528 .bitcast => try self.airBitCast(inst),
529 .block => try self.airBlock(inst),529 .block => try self.airBlock(inst),
530 .br => try self.airBr(inst),530 .br => try self.airBr(inst),
531 .breakpoint => try self.airBreakpoint(),531 .breakpoint => try self.airBreakpoint(),
532 .ret_addr => try self.airRetAddr(),532 .ret_addr => try self.airRetAddr(),
533 .fence => try self.airFence(),533 .fence => try self.airFence(),
534 .call => try self.airCall(inst),534 .call => try self.airCall(inst),
535 .cond_br => try self.airCondBr(inst),535 .cond_br => try self.airCondBr(inst),
536 .dbg_stmt => try self.airDbgStmt(inst),536 .dbg_stmt => try self.airDbgStmt(inst),
537 .fptrunc => try self.airFptrunc(inst),537 .fptrunc => try self.airFptrunc(inst),
538 .fpext => try self.airFpext(inst),538 .fpext => try self.airFpext(inst),
539 .intcast => try self.airIntCast(inst),539 .intcast => try self.airIntCast(inst),
540 .trunc => try self.airTrunc(inst),540 .trunc => try self.airTrunc(inst),
541 .bool_to_int => try self.airBoolToInt(inst),541 .bool_to_int => try self.airBoolToInt(inst),
542 .is_non_null => try self.airIsNonNull(inst),542 .is_non_null => try self.airIsNonNull(inst),
543 .is_non_null_ptr => try self.airIsNonNullPtr(inst),543 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
544 .is_null => try self.airIsNull(inst),544 .is_null => try self.airIsNull(inst),
545 .is_null_ptr => try self.airIsNullPtr(inst),545 .is_null_ptr => try self.airIsNullPtr(inst),
546 .is_non_err => try self.airIsNonErr(inst),546 .is_non_err => try self.airIsNonErr(inst),
547 .is_non_err_ptr => try self.airIsNonErrPtr(inst),547 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
548 .is_err => try self.airIsErr(inst),548 .is_err => try self.airIsErr(inst),
549 .is_err_ptr => try self.airIsErrPtr(inst),549 .is_err_ptr => try self.airIsErrPtr(inst),
550 .load => try self.airLoad(inst),550 .load => try self.airLoad(inst),
551 .loop => try self.airLoop(inst),551 .loop => try self.airLoop(inst),
552 .not => try self.airNot(inst),552 .not => try self.airNot(inst),
553 .ptrtoint => try self.airPtrToInt(inst),553 .ptrtoint => try self.airPtrToInt(inst),
554 .ret => try self.airRet(inst),554 .ret => try self.airRet(inst),
555 .ret_load => try self.airRetLoad(inst),555 .ret_load => try self.airRetLoad(inst),
556 .store => try self.airStore(inst),556 .store => try self.airStore(inst),
557 .struct_field_ptr=> try self.airStructFieldPtr(inst),557 .struct_field_ptr=> try self.airStructFieldPtr(inst),
558 .struct_field_val=> try self.airStructFieldVal(inst),558 .struct_field_val=> try self.airStructFieldVal(inst),
559 .array_to_slice => try self.airArrayToSlice(inst),559 .array_to_slice => try self.airArrayToSlice(inst),
560 .int_to_float => try self.airIntToFloat(inst),560 .int_to_float => try self.airIntToFloat(inst),
561 .float_to_int => try self.airFloatToInt(inst),561 .float_to_int => try self.airFloatToInt(inst),
562 .cmpxchg_strong => try self.airCmpxchg(inst),562 .cmpxchg_strong => try self.airCmpxchg(inst),
563 .cmpxchg_weak => try self.airCmpxchg(inst),563 .cmpxchg_weak => try self.airCmpxchg(inst),
564 .atomic_rmw => try self.airAtomicRmw(inst),564 .atomic_rmw => try self.airAtomicRmw(inst),
565 .atomic_load => try self.airAtomicLoad(inst),565 .atomic_load => try self.airAtomicLoad(inst),
566 .memcpy => try self.airMemcpy(inst),566 .memcpy => try self.airMemcpy(inst),
567 .memset => try self.airMemset(inst),567 .memset => try self.airMemset(inst),
568 .set_union_tag => try self.airSetUnionTag(inst),568 .set_union_tag => try self.airSetUnionTag(inst),
569 .get_union_tag => try self.airGetUnionTag(inst),569 .get_union_tag => try self.airGetUnionTag(inst),
570 .clz => try self.airClz(inst),570 .clz => try self.airClz(inst),
571 .ctz => try self.airCtz(inst),571 .ctz => try self.airCtz(inst),
572 .popcount => try self.airPopcount(inst),572 .popcount => try self.airPopcount(inst),
573573 .tag_name => try self.airTagName(inst),
574 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),574
575 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),575 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
576 .atomic_store_release => try self.airAtomicStore(inst, .Release),576 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
577 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),577 .atomic_store_release => try self.airAtomicStore(inst, .Release),
578578 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
579 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),579
580 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),580 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
581 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),581 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
582 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),582 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
583583 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
584 .switch_br => try self.airSwitch(inst),584
585 .slice_ptr => try self.airSlicePtr(inst),585 .switch_br => try self.airSwitch(inst),
586 .slice_len => try self.airSliceLen(inst),586 .slice_ptr => try self.airSlicePtr(inst),
587587 .slice_len => try self.airSliceLen(inst),
588 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),588
589 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),589 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
590590 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
591 .array_elem_val => try self.airArrayElemVal(inst),591
592 .slice_elem_val => try self.airSliceElemVal(inst),592 .array_elem_val => try self.airArrayElemVal(inst),
593 .slice_elem_ptr => try self.airSliceElemPtr(inst),593 .slice_elem_val => try self.airSliceElemVal(inst),
594 .ptr_elem_val => try self.airPtrElemVal(inst),594 .slice_elem_ptr => try self.airSliceElemPtr(inst),
595 .ptr_elem_ptr => try self.airPtrElemPtr(inst),595 .ptr_elem_val => try self.airPtrElemVal(inst),
596596 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
597 .constant => unreachable, // excluded from function bodies597
598 .const_ty => unreachable, // excluded from function bodies598 .constant => unreachable, // excluded from function bodies
599 .unreach => self.finishAirBookkeeping(),599 .const_ty => unreachable, // excluded from function bodies
600600 .unreach => self.finishAirBookkeeping(),
601 .optional_payload => try self.airOptionalPayload(inst),601
602 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),602 .optional_payload => try self.airOptionalPayload(inst),
603 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),603 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
604 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),604 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
605 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),605 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
606 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),606 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
607 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),607 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
608608 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
609 .wrap_optional => try self.airWrapOptional(inst),609
610 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),610 .wrap_optional => try self.airWrapOptional(inst),
611 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),611 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
612 // zig fmt: on612 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
613 // zig fmt: on
613 }614 }
614 if (std.debug.runtime_safety) {615 if (std.debug.runtime_safety) {
615 if (self.air_bookkeeping < old_air_bookkeeping + 1) {616 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
...@@ -2045,6 +2046,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -2045,6 +2046,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
2045 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});2046 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
2046}2047}
20472048
2049fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
2050 const un_op = self.air.instructions.items(.data)[inst].un_op;
2051 const operand = try self.resolveInst(un_op);
2052 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
2053 _ = operand;
2054 return self.fail("TODO implement airTagName for riscv64", .{});
2055 };
2056 return self.finishAir(inst, result, .{ un_op, .none, .none });
2057}
2058
2048fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {2059fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
2049 // First section of indexes correspond to a set number of constant values.2060 // First section of indexes correspond to a set number of constant values.
2050 const ref_int = @enumToInt(inst);2061 const ref_int = @enumToInt(inst);
src/arch/x86_64/CodeGen.zig+138-127
...@@ -538,133 +538,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -538,133 +538,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
538538
539 switch (air_tags[inst]) {539 switch (air_tags[inst]) {
540 // zig fmt: off540 // zig fmt: off
541 .add, .ptr_add => try self.airAdd(inst),541 .add, .ptr_add => try self.airAdd(inst),
542 .addwrap => try self.airAddWrap(inst),542 .addwrap => try self.airAddWrap(inst),
543 .add_sat => try self.airAddSat(inst),543 .add_sat => try self.airAddSat(inst),
544 .sub, .ptr_sub => try self.airSub(inst),544 .sub, .ptr_sub => try self.airSub(inst),
545 .subwrap => try self.airSubWrap(inst),545 .subwrap => try self.airSubWrap(inst),
546 .sub_sat => try self.airSubSat(inst),546 .sub_sat => try self.airSubSat(inst),
547 .mul => try self.airMul(inst),547 .mul => try self.airMul(inst),
548 .mulwrap => try self.airMulWrap(inst),548 .mulwrap => try self.airMulWrap(inst),
549 .mul_sat => try self.airMulSat(inst),549 .mul_sat => try self.airMulSat(inst),
550 .rem => try self.airRem(inst),550 .rem => try self.airRem(inst),
551 .mod => try self.airMod(inst),551 .mod => try self.airMod(inst),
552 .shl, .shl_exact => try self.airShl(inst),552 .shl, .shl_exact => try self.airShl(inst),
553 .shl_sat => try self.airShlSat(inst),553 .shl_sat => try self.airShlSat(inst),
554 .min => try self.airMin(inst),554 .min => try self.airMin(inst),
555 .max => try self.airMax(inst),555 .max => try self.airMax(inst),
556 .slice => try self.airSlice(inst),556 .slice => try self.airSlice(inst),
557557
558 .add_with_overflow => try self.airAddWithOverflow(inst),558 .add_with_overflow => try self.airAddWithOverflow(inst),
559 .sub_with_overflow => try self.airSubWithOverflow(inst),559 .sub_with_overflow => try self.airSubWithOverflow(inst),
560 .mul_with_overflow => try self.airMulWithOverflow(inst),560 .mul_with_overflow => try self.airMulWithOverflow(inst),
561 .shl_with_overflow => try self.airShlWithOverflow(inst),561 .shl_with_overflow => try self.airShlWithOverflow(inst),
562562
563 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),563 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
564564
565 .cmp_lt => try self.airCmp(inst, .lt),565 .cmp_lt => try self.airCmp(inst, .lt),
566 .cmp_lte => try self.airCmp(inst, .lte),566 .cmp_lte => try self.airCmp(inst, .lte),
567 .cmp_eq => try self.airCmp(inst, .eq),567 .cmp_eq => try self.airCmp(inst, .eq),
568 .cmp_gte => try self.airCmp(inst, .gte),568 .cmp_gte => try self.airCmp(inst, .gte),
569 .cmp_gt => try self.airCmp(inst, .gt),569 .cmp_gt => try self.airCmp(inst, .gt),
570 .cmp_neq => try self.airCmp(inst, .neq),570 .cmp_neq => try self.airCmp(inst, .neq),
571571
572 .bool_and => try self.airBoolOp(inst),572 .bool_and => try self.airBoolOp(inst),
573 .bool_or => try self.airBoolOp(inst),573 .bool_or => try self.airBoolOp(inst),
574 .bit_and => try self.airBitAnd(inst),574 .bit_and => try self.airBitAnd(inst),
575 .bit_or => try self.airBitOr(inst),575 .bit_or => try self.airBitOr(inst),
576 .xor => try self.airXor(inst),576 .xor => try self.airXor(inst),
577 .shr => try self.airShr(inst),577 .shr => try self.airShr(inst),
578578
579 .alloc => try self.airAlloc(inst),579 .alloc => try self.airAlloc(inst),
580 .ret_ptr => try self.airRetPtr(inst),580 .ret_ptr => try self.airRetPtr(inst),
581 .arg => try self.airArg(inst),581 .arg => try self.airArg(inst),
582 .assembly => try self.airAsm(inst),582 .assembly => try self.airAsm(inst),
583 .bitcast => try self.airBitCast(inst),583 .bitcast => try self.airBitCast(inst),
584 .block => try self.airBlock(inst),584 .block => try self.airBlock(inst),
585 .br => try self.airBr(inst),585 .br => try self.airBr(inst),
586 .breakpoint => try self.airBreakpoint(),586 .breakpoint => try self.airBreakpoint(),
587 .ret_addr => try self.airRetAddr(),587 .ret_addr => try self.airRetAddr(),
588 .fence => try self.airFence(),588 .fence => try self.airFence(),
589 .call => try self.airCall(inst),589 .call => try self.airCall(inst),
590 .cond_br => try self.airCondBr(inst),590 .cond_br => try self.airCondBr(inst),
591 .dbg_stmt => try self.airDbgStmt(inst),591 .dbg_stmt => try self.airDbgStmt(inst),
592 .fptrunc => try self.airFptrunc(inst),592 .fptrunc => try self.airFptrunc(inst),
593 .fpext => try self.airFpext(inst),593 .fpext => try self.airFpext(inst),
594 .intcast => try self.airIntCast(inst),594 .intcast => try self.airIntCast(inst),
595 .trunc => try self.airTrunc(inst),595 .trunc => try self.airTrunc(inst),
596 .bool_to_int => try self.airBoolToInt(inst),596 .bool_to_int => try self.airBoolToInt(inst),
597 .is_non_null => try self.airIsNonNull(inst),597 .is_non_null => try self.airIsNonNull(inst),
598 .is_non_null_ptr => try self.airIsNonNullPtr(inst),598 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
599 .is_null => try self.airIsNull(inst),599 .is_null => try self.airIsNull(inst),
600 .is_null_ptr => try self.airIsNullPtr(inst),600 .is_null_ptr => try self.airIsNullPtr(inst),
601 .is_non_err => try self.airIsNonErr(inst),601 .is_non_err => try self.airIsNonErr(inst),
602 .is_non_err_ptr => try self.airIsNonErrPtr(inst),602 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
603 .is_err => try self.airIsErr(inst),603 .is_err => try self.airIsErr(inst),
604 .is_err_ptr => try self.airIsErrPtr(inst),604 .is_err_ptr => try self.airIsErrPtr(inst),
605 .load => try self.airLoad(inst),605 .load => try self.airLoad(inst),
606 .loop => try self.airLoop(inst),606 .loop => try self.airLoop(inst),
607 .not => try self.airNot(inst),607 .not => try self.airNot(inst),
608 .ptrtoint => try self.airPtrToInt(inst),608 .ptrtoint => try self.airPtrToInt(inst),
609 .ret => try self.airRet(inst),609 .ret => try self.airRet(inst),
610 .ret_load => try self.airRetLoad(inst),610 .ret_load => try self.airRetLoad(inst),
611 .store => try self.airStore(inst),611 .store => try self.airStore(inst),
612 .struct_field_ptr=> try self.airStructFieldPtr(inst),612 .struct_field_ptr=> try self.airStructFieldPtr(inst),
613 .struct_field_val=> try self.airStructFieldVal(inst),613 .struct_field_val=> try self.airStructFieldVal(inst),
614 .array_to_slice => try self.airArrayToSlice(inst),614 .array_to_slice => try self.airArrayToSlice(inst),
615 .int_to_float => try self.airIntToFloat(inst),615 .int_to_float => try self.airIntToFloat(inst),
616 .float_to_int => try self.airFloatToInt(inst),616 .float_to_int => try self.airFloatToInt(inst),
617 .cmpxchg_strong => try self.airCmpxchg(inst),617 .cmpxchg_strong => try self.airCmpxchg(inst),
618 .cmpxchg_weak => try self.airCmpxchg(inst),618 .cmpxchg_weak => try self.airCmpxchg(inst),
619 .atomic_rmw => try self.airAtomicRmw(inst),619 .atomic_rmw => try self.airAtomicRmw(inst),
620 .atomic_load => try self.airAtomicLoad(inst),620 .atomic_load => try self.airAtomicLoad(inst),
621 .memcpy => try self.airMemcpy(inst),621 .memcpy => try self.airMemcpy(inst),
622 .memset => try self.airMemset(inst),622 .memset => try self.airMemset(inst),
623 .set_union_tag => try self.airSetUnionTag(inst),623 .set_union_tag => try self.airSetUnionTag(inst),
624 .get_union_tag => try self.airGetUnionTag(inst),624 .get_union_tag => try self.airGetUnionTag(inst),
625 .clz => try self.airClz(inst),625 .clz => try self.airClz(inst),
626 .ctz => try self.airCtz(inst),626 .ctz => try self.airCtz(inst),
627 .popcount => try self.airPopcount(inst),627 .popcount => try self.airPopcount(inst),
628628 .tag_name => try self.airTagName(inst),
629 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),629
630 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),630 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
631 .atomic_store_release => try self.airAtomicStore(inst, .Release),631 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
632 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),632 .atomic_store_release => try self.airAtomicStore(inst, .Release),
633633 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
634 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),634
635 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),635 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
636 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),636 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
637 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),637 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
638638 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
639 .switch_br => try self.airSwitch(inst),639
640 .slice_ptr => try self.airSlicePtr(inst),640 .switch_br => try self.airSwitch(inst),
641 .slice_len => try self.airSliceLen(inst),641 .slice_ptr => try self.airSlicePtr(inst),
642642 .slice_len => try self.airSliceLen(inst),
643 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),643
644 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),644 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
645645 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
646 .array_elem_val => try self.airArrayElemVal(inst),646
647 .slice_elem_val => try self.airSliceElemVal(inst),647 .array_elem_val => try self.airArrayElemVal(inst),
648 .slice_elem_ptr => try self.airSliceElemPtr(inst),648 .slice_elem_val => try self.airSliceElemVal(inst),
649 .ptr_elem_val => try self.airPtrElemVal(inst),649 .slice_elem_ptr => try self.airSliceElemPtr(inst),
650 .ptr_elem_ptr => try self.airPtrElemPtr(inst),650 .ptr_elem_val => try self.airPtrElemVal(inst),
651651 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
652 .constant => unreachable, // excluded from function bodies652
653 .const_ty => unreachable, // excluded from function bodies653 .constant => unreachable, // excluded from function bodies
654 .unreach => self.finishAirBookkeeping(),654 .const_ty => unreachable, // excluded from function bodies
655655 .unreach => self.finishAirBookkeeping(),
656 .optional_payload => try self.airOptionalPayload(inst),656
657 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),657 .optional_payload => try self.airOptionalPayload(inst),
658 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),658 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
659 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),659 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
660 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),660 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
661 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),661 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
662 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),662 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
663663 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
664 .wrap_optional => try self.airWrapOptional(inst),664
665 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),665 .wrap_optional => try self.airWrapOptional(inst),
666 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),666 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
667 // zig fmt: on667 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
668 // zig fmt: on
668 }669 }
669 if (std.debug.runtime_safety) {670 if (std.debug.runtime_safety) {
670 if (self.air_bookkeeping < old_air_bookkeeping + 1) {671 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
...@@ -3174,6 +3175,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -3174,6 +3175,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
3174 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});3175 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
3175}3176}
31763177
3178fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
3179 const un_op = self.air.instructions.items(.data)[inst].un_op;
3180 const operand = try self.resolveInst(un_op);
3181 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {
3182 _ = operand;
3183 return self.fail("TODO implement airTagName for x86_64", .{});
3184 };
3185 return self.finishAir(inst, result, .{ un_op, .none, .none });
3186}
3187
3177fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {3188fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
3178 // First section of indexes correspond to a set number of constant values.3189 // First section of indexes correspond to a set number of constant values.
3179 const ref_int = @enumToInt(inst);3190 const ref_int = @enumToInt(inst);
src/codegen/c.zig+19
...@@ -1230,6 +1230,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1230,6 +1230,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1230 .clz => try airBuiltinCall(f, inst, "clz"),1230 .clz => try airBuiltinCall(f, inst, "clz"),
1231 .ctz => try airBuiltinCall(f, inst, "ctz"),1231 .ctz => try airBuiltinCall(f, inst, "ctz"),
1232 .popcount => try airBuiltinCall(f, inst, "popcount"),1232 .popcount => try airBuiltinCall(f, inst, "popcount"),
1233 .tag_name => try airTagName(f, inst),
12331234
1234 .int_to_float,1235 .int_to_float,
1235 .float_to_int,1236 .float_to_int,
...@@ -2914,6 +2915,24 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2914,6 +2915,24 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
2914 return local;2915 return local;
2915}2916}
29162917
2918fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
2919 if (f.liveness.isUnused(inst)) return CValue.none;
2920
2921 const un_op = f.air.instructions.items(.data)[inst].un_op;
2922 const writer = f.object.writer();
2923 const inst_ty = f.air.typeOfIndex(inst);
2924 const operand = try f.resolveInst(un_op);
2925 const local = try f.allocLocal(inst_ty, .Const);
2926
2927 try writer.writeAll(" = ");
2928
2929 _ = operand;
2930 _ = local;
2931 return f.fail("TODO: C backend: implement airTagName", .{});
2932 //try writer.writeAll(";\n");
2933 //return local;
2934}
2935
2917fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {2936fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
2918 return switch (order) {2937 return switch (order) {
2919 .Unordered => "memory_order_relaxed",2938 .Unordered => "memory_order_relaxed",
src/codegen/llvm.zig+132-14
...@@ -636,15 +636,6 @@ pub const DeclGen = struct {...@@ -636,15 +636,6 @@ pub const DeclGen = struct {
636 llvm_param_i += 1;636 llvm_param_i += 1;
637 }637 }
638638
639 if (dg.module.comp.bin_file.options.skip_linker_dependencies) {
640 // The intent here is for compiler-rt and libc functions to not generate
641 // infinite recursion. For example, if we are compiling the memcpy function,
642 // and llvm detects that the body is equivalent to memcpy, it may replace the
643 // body of memcpy with a call to memcpy, which would then cause a stack
644 // overflow instead of performing memcpy.
645 dg.addFnAttr(llvm_fn, "nobuiltin");
646 }
647
648 // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`.639 // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`.
649 if (fn_info.cc == .Naked) {640 if (fn_info.cc == .Naked) {
650 dg.addFnAttr(llvm_fn, "naked");641 dg.addFnAttr(llvm_fn, "naked");
...@@ -653,6 +644,16 @@ pub const DeclGen = struct {...@@ -653,6 +644,16 @@ pub const DeclGen = struct {
653 }644 }
654645
655 // Function attributes that are independent of analysis results of the function body.646 // Function attributes that are independent of analysis results of the function body.
647 dg.addCommonFnAttributes(llvm_fn);
648
649 if (return_type.isNoReturn()) {
650 dg.addFnAttr(llvm_fn, "noreturn");
651 }
652
653 return llvm_fn;
654 }
655
656 fn addCommonFnAttributes(dg: *DeclGen, llvm_fn: *const llvm.Value) void {
656 if (!dg.module.comp.bin_file.options.red_zone) {657 if (!dg.module.comp.bin_file.options.red_zone) {
657 dg.addFnAttr(llvm_fn, "noredzone");658 dg.addFnAttr(llvm_fn, "noredzone");
658 }659 }
...@@ -665,6 +666,14 @@ pub const DeclGen = struct {...@@ -665,6 +666,14 @@ pub const DeclGen = struct {
665 if (dg.module.comp.unwind_tables) {666 if (dg.module.comp.unwind_tables) {
666 dg.addFnAttr(llvm_fn, "uwtable");667 dg.addFnAttr(llvm_fn, "uwtable");
667 }668 }
669 if (dg.module.comp.bin_file.options.skip_linker_dependencies) {
670 // The intent here is for compiler-rt and libc functions to not generate
671 // infinite recursion. For example, if we are compiling the memcpy function,
672 // and llvm detects that the body is equivalent to memcpy, it may replace the
673 // body of memcpy with a call to memcpy, which would then cause a stack
674 // overflow instead of performing memcpy.
675 dg.addFnAttr(llvm_fn, "nobuiltin");
676 }
668 if (dg.module.comp.bin_file.options.optimize_mode == .ReleaseSmall) {677 if (dg.module.comp.bin_file.options.optimize_mode == .ReleaseSmall) {
669 dg.addFnAttr(llvm_fn, "minsize");678 dg.addFnAttr(llvm_fn, "minsize");
670 dg.addFnAttr(llvm_fn, "optsize");679 dg.addFnAttr(llvm_fn, "optsize");
...@@ -673,11 +682,6 @@ pub const DeclGen = struct {...@@ -673,11 +682,6 @@ pub const DeclGen = struct {
673 dg.addFnAttr(llvm_fn, "sanitize_thread");682 dg.addFnAttr(llvm_fn, "sanitize_thread");
674 }683 }
675 // TODO add target-cpu and target-features fn attributes684 // TODO add target-cpu and target-features fn attributes
676 if (return_type.isNoReturn()) {
677 dg.addFnAttr(llvm_fn, "noreturn");
678 }
679
680 return llvm_fn;
681 }685 }
682686
683 fn resolveGlobalDecl(dg: *DeclGen, decl: *Module.Decl) Error!*const llvm.Value {687 fn resolveGlobalDecl(dg: *DeclGen, decl: *Module.Decl) Error!*const llvm.Value {
...@@ -1958,6 +1962,7 @@ pub const FuncGen = struct {...@@ -1958,6 +1962,7 @@ pub const FuncGen = struct {
1958 .clz => try self.airClzCtz(inst, "ctlz"),1962 .clz => try self.airClzCtz(inst, "ctlz"),
1959 .ctz => try self.airClzCtz(inst, "cttz"),1963 .ctz => try self.airClzCtz(inst, "cttz"),
1960 .popcount => try self.airPopCount(inst, "ctpop"),1964 .popcount => try self.airPopCount(inst, "ctpop"),
1965 .tag_name => try self.airTagName(inst),
19611966
1962 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),1967 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
1963 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),1968 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -4093,6 +4098,119 @@ pub const FuncGen = struct {...@@ -4093,6 +4098,119 @@ pub const FuncGen = struct {
4093 }4098 }
4094 }4099 }
40954100
4101 fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4102 if (self.liveness.isUnused(inst)) return null;
4103
4104 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
4105 defer arena_allocator.deinit();
4106 const arena = arena_allocator.allocator();
4107
4108 const un_op = self.air.instructions.items(.data)[inst].un_op;
4109 const operand = try self.resolveInst(un_op);
4110 const enum_ty = self.air.typeOf(un_op);
4111
4112 const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{
4113 try enum_ty.getOwnerDecl().getFullyQualifiedName(arena),
4114 });
4115
4116 const llvm_fn = try self.getEnumTagNameFunction(enum_ty, llvm_fn_name);
4117 const params = [_]*const llvm.Value{operand};
4118 return self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");
4119 }
4120
4121 fn getEnumTagNameFunction(
4122 self: *FuncGen,
4123 enum_ty: Type,
4124 llvm_fn_name: [:0]const u8,
4125 ) !*const llvm.Value {
4126 // TODO: detect when the type changes and re-emit this function.
4127 if (self.dg.object.llvm_module.getNamedFunction(llvm_fn_name)) |llvm_fn| {
4128 return llvm_fn;
4129 }
4130
4131 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
4132 const llvm_ret_ty = try self.dg.llvmType(slice_ty);
4133 const usize_llvm_ty = try self.dg.llvmType(Type.usize);
4134 const target = self.dg.module.getTarget();
4135 const slice_alignment = slice_ty.abiAlignment(target);
4136
4137 var int_tag_type_buffer: Type.Payload.Bits = undefined;
4138 const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer);
4139 const param_types = [_]*const llvm.Type{try self.dg.llvmType(int_tag_ty)};
4140
4141 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
4142 const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
4143 fn_val.setLinkage(.Internal);
4144 fn_val.setFunctionCallConv(.Fast);
4145 self.dg.addCommonFnAttributes(fn_val);
4146
4147 const prev_block = self.builder.getInsertBlock();
4148 const prev_debug_location = self.builder.getCurrentDebugLocation2();
4149 defer {
4150 self.builder.positionBuilderAtEnd(prev_block);
4151 if (!self.dg.module.comp.bin_file.options.strip) {
4152 self.builder.setCurrentDebugLocation2(prev_debug_location);
4153 }
4154 }
4155
4156 const entry_block = self.dg.context.appendBasicBlock(fn_val, "Entry");
4157 self.builder.positionBuilderAtEnd(entry_block);
4158 self.builder.clearCurrentDebugLocation();
4159
4160 const fields = enum_ty.enumFields();
4161 const bad_value_block = self.dg.context.appendBasicBlock(fn_val, "BadValue");
4162 const tag_int_value = fn_val.getParam(0);
4163 const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @intCast(c_uint, fields.count()));
4164
4165 const array_ptr_indices = [_]*const llvm.Value{
4166 usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
4167 };
4168
4169 for (fields.keys()) |name, field_index| {
4170 const str_init = self.dg.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
4171 const str_global = self.dg.object.llvm_module.addGlobal(str_init.typeOf(), "");
4172 str_global.setInitializer(str_init);
4173 str_global.setLinkage(.Private);
4174 str_global.setGlobalConstant(.True);
4175 str_global.setUnnamedAddr(.True);
4176 str_global.setAlignment(1);
4177
4178 const slice_fields = [_]*const llvm.Value{
4179 str_global.constInBoundsGEP(&array_ptr_indices, array_ptr_indices.len),
4180 usize_llvm_ty.constInt(name.len, .False),
4181 };
4182 const slice_init = llvm_ret_ty.constNamedStruct(&slice_fields, slice_fields.len);
4183 const slice_global = self.dg.object.llvm_module.addGlobal(slice_init.typeOf(), "");
4184 slice_global.setInitializer(slice_init);
4185 slice_global.setLinkage(.Private);
4186 slice_global.setGlobalConstant(.True);
4187 slice_global.setUnnamedAddr(.True);
4188 slice_global.setAlignment(slice_alignment);
4189
4190 const return_block = self.dg.context.appendBasicBlock(fn_val, "Name");
4191 const this_tag_int_value = int: {
4192 var tag_val_payload: Value.Payload.U32 = .{
4193 .base = .{ .tag = .enum_field_index },
4194 .data = @intCast(u32, field_index),
4195 };
4196 break :int try self.dg.genTypedValue(.{
4197 .ty = enum_ty,
4198 .val = Value.initPayload(&tag_val_payload.base),
4199 });
4200 };
4201 switch_instr.addCase(this_tag_int_value, return_block);
4202
4203 self.builder.positionBuilderAtEnd(return_block);
4204 const loaded = self.builder.buildLoad(slice_global, "");
4205 loaded.setAlignment(slice_alignment);
4206 _ = self.builder.buildRet(loaded);
4207 }
4208
4209 self.builder.positionBuilderAtEnd(bad_value_block);
4210 _ = self.builder.buildUnreachable();
4211 return fn_val;
4212 }
4213
4096 /// Assumes the optional is not pointer-like and payload has bits.4214 /// Assumes the optional is not pointer-like and payload has bits.
4097 fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {4215 fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {
4098 if (is_by_ref) {4216 if (is_by_ref) {
src/codegen/llvm/bindings.zig+15
...@@ -785,8 +785,23 @@ pub const Builder = opaque {...@@ -785,8 +785,23 @@ pub const Builder = opaque {
785785
786 pub const buildExactSDiv = LLVMBuildExactSDiv;786 pub const buildExactSDiv = LLVMBuildExactSDiv;
787 extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;787 extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
788
789 pub const zigSetCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation;
790 extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_int, column: c_int, scope: *DIScope) void;
791
792 pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation;
793 extern fn ZigLLVMClearCurrentDebugLocation(builder: *const Builder) void;
794
795 pub const getCurrentDebugLocation2 = LLVMGetCurrentDebugLocation2;
796 extern fn LLVMGetCurrentDebugLocation2(Builder: *const Builder) *Metadata;
797
798 pub const setCurrentDebugLocation2 = LLVMSetCurrentDebugLocation2;
799 extern fn LLVMSetCurrentDebugLocation2(Builder: *const Builder, Loc: *Metadata) void;
788};800};
789801
802pub const DIScope = opaque {};
803pub const Metadata = opaque {};
804
790pub const IntPredicate = enum(c_uint) {805pub const IntPredicate = enum(c_uint) {
791 EQ = 32,806 EQ = 32,
792 NE = 33,807 NE = 33,
src/print_air.zig+1
...@@ -155,6 +155,7 @@ const Writer = struct {...@@ -155,6 +155,7 @@ const Writer = struct {
155 .bool_to_int,155 .bool_to_int,
156 .ret,156 .ret,
157 .ret_load,157 .ret_load,
158 .tag_name,
158 => try w.writeUnOp(s, inst),159 => try w.writeUnOp(s, inst),
159160
160 .breakpoint,161 .breakpoint,
src/type.zig+124-31
...@@ -94,6 +94,7 @@ pub const Type = extern union {...@@ -94,6 +94,7 @@ pub const Type = extern union {
9494
95 .single_const_pointer_to_comptime_int,95 .single_const_pointer_to_comptime_int,
96 .const_slice_u8,96 .const_slice_u8,
97 .const_slice_u8_sentinel_0,
97 .single_const_pointer,98 .single_const_pointer,
98 .single_mut_pointer,99 .single_mut_pointer,
99 .many_const_pointer,100 .many_const_pointer,
...@@ -107,6 +108,7 @@ pub const Type = extern union {...@@ -107,6 +108,7 @@ pub const Type = extern union {
107 .inferred_alloc_mut,108 .inferred_alloc_mut,
108 .manyptr_u8,109 .manyptr_u8,
109 .manyptr_const_u8,110 .manyptr_const_u8,
111 .manyptr_const_u8_sentinel_0,
110 => return .Pointer,112 => return .Pointer,
111113
112 .optional,114 .optional,
...@@ -254,6 +256,7 @@ pub const Type = extern union {...@@ -254,6 +256,7 @@ pub const Type = extern union {
254 .optional_single_mut_pointer,256 .optional_single_mut_pointer,
255 .manyptr_u8,257 .manyptr_u8,
256 .manyptr_const_u8,258 .manyptr_const_u8,
259 .manyptr_const_u8_sentinel_0,
257 => self.cast(Payload.ElemType),260 => self.cast(Payload.ElemType),
258261
259 .inferred_alloc_const => unreachable,262 .inferred_alloc_const => unreachable,
...@@ -275,9 +278,11 @@ pub const Type = extern union {...@@ -275,9 +278,11 @@ pub const Type = extern union {
275 return switch (ty.tag()) {278 return switch (ty.tag()) {
276 .single_const_pointer_to_comptime_int,279 .single_const_pointer_to_comptime_int,
277 .const_slice_u8,280 .const_slice_u8,
281 .const_slice_u8_sentinel_0,
278 .single_const_pointer,282 .single_const_pointer,
279 .many_const_pointer,283 .many_const_pointer,
280 .manyptr_const_u8,284 .manyptr_const_u8,
285 .manyptr_const_u8_sentinel_0,
281 .c_const_pointer,286 .c_const_pointer,
282 .const_slice,287 .const_slice,
283 => false,288 => false,
...@@ -330,6 +335,18 @@ pub const Type = extern union {...@@ -330,6 +335,18 @@ pub const Type = extern union {
330 .@"volatile" = false,335 .@"volatile" = false,
331 .size = .Slice,336 .size = .Slice,
332 } },337 } },
338 .const_slice_u8_sentinel_0 => return .{ .data = .{
339 .pointee_type = Type.initTag(.u8),
340 .sentinel = Value.zero,
341 .@"align" = 0,
342 .@"addrspace" = .generic,
343 .bit_offset = 0,
344 .host_size = 0,
345 .@"allowzero" = false,
346 .mutable = false,
347 .@"volatile" = false,
348 .size = .Slice,
349 } },
333 .single_const_pointer => return .{ .data = .{350 .single_const_pointer => return .{ .data = .{
334 .pointee_type = self.castPointer().?.data,351 .pointee_type = self.castPointer().?.data,
335 .sentinel = null,352 .sentinel = null,
...@@ -378,6 +395,18 @@ pub const Type = extern union {...@@ -378,6 +395,18 @@ pub const Type = extern union {
378 .@"volatile" = false,395 .@"volatile" = false,
379 .size = .Many,396 .size = .Many,
380 } },397 } },
398 .manyptr_const_u8_sentinel_0 => return .{ .data = .{
399 .pointee_type = Type.initTag(.u8),
400 .sentinel = Value.zero,
401 .@"align" = 0,
402 .@"addrspace" = .generic,
403 .bit_offset = 0,
404 .host_size = 0,
405 .@"allowzero" = false,
406 .mutable = false,
407 .@"volatile" = false,
408 .size = .Many,
409 } },
381 .many_mut_pointer => return .{ .data = .{410 .many_mut_pointer => return .{ .data = .{
382 .pointee_type = self.castPointer().?.data,411 .pointee_type = self.castPointer().?.data,
383 .sentinel = null,412 .sentinel = null,
...@@ -784,6 +813,7 @@ pub const Type = extern union {...@@ -784,6 +813,7 @@ pub const Type = extern union {
784 .fn_ccc_void_no_args,813 .fn_ccc_void_no_args,
785 .single_const_pointer_to_comptime_int,814 .single_const_pointer_to_comptime_int,
786 .const_slice_u8,815 .const_slice_u8,
816 .const_slice_u8_sentinel_0,
787 .enum_literal,817 .enum_literal,
788 .anyerror_void_error_union,818 .anyerror_void_error_union,
789 .inferred_alloc_const,819 .inferred_alloc_const,
...@@ -792,6 +822,7 @@ pub const Type = extern union {...@@ -792,6 +822,7 @@ pub const Type = extern union {
792 .empty_struct_literal,822 .empty_struct_literal,
793 .manyptr_u8,823 .manyptr_u8,
794 .manyptr_const_u8,824 .manyptr_const_u8,
825 .manyptr_const_u8_sentinel_0,
795 .atomic_order,826 .atomic_order,
796 .atomic_rmw_op,827 .atomic_rmw_op,
797 .calling_convention,828 .calling_convention,
...@@ -1016,6 +1047,7 @@ pub const Type = extern union {...@@ -1016,6 +1047,7 @@ pub const Type = extern union {
10161047
1017 .anyerror_void_error_union => return writer.writeAll("anyerror!void"),1048 .anyerror_void_error_union => return writer.writeAll("anyerror!void"),
1018 .const_slice_u8 => return writer.writeAll("[]const u8"),1049 .const_slice_u8 => return writer.writeAll("[]const u8"),
1050 .const_slice_u8_sentinel_0 => return writer.writeAll("[:0]const u8"),
1019 .fn_noreturn_no_args => return writer.writeAll("fn() noreturn"),1051 .fn_noreturn_no_args => return writer.writeAll("fn() noreturn"),
1020 .fn_void_no_args => return writer.writeAll("fn() void"),1052 .fn_void_no_args => return writer.writeAll("fn() void"),
1021 .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"),1053 .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"),
...@@ -1023,6 +1055,7 @@ pub const Type = extern union {...@@ -1023,6 +1055,7 @@ pub const Type = extern union {
1023 .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"),1055 .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"),
1024 .manyptr_u8 => return writer.writeAll("[*]u8"),1056 .manyptr_u8 => return writer.writeAll("[*]u8"),
1025 .manyptr_const_u8 => return writer.writeAll("[*]const u8"),1057 .manyptr_const_u8 => return writer.writeAll("[*]const u8"),
1058 .manyptr_const_u8_sentinel_0 => return writer.writeAll("[*:0]const u8"),
1026 .atomic_order => return writer.writeAll("std.builtin.AtomicOrder"),1059 .atomic_order => return writer.writeAll("std.builtin.AtomicOrder"),
1027 .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"),1060 .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"),
1028 .calling_convention => return writer.writeAll("std.builtin.CallingConvention"),1061 .calling_convention => return writer.writeAll("std.builtin.CallingConvention"),
...@@ -1308,6 +1341,7 @@ pub const Type = extern union {...@@ -1308,6 +1341,7 @@ pub const Type = extern union {
13081341
1309 .anyerror_void_error_union => return "anyerror!void",1342 .anyerror_void_error_union => return "anyerror!void",
1310 .const_slice_u8 => return "[]const u8",1343 .const_slice_u8 => return "[]const u8",
1344 .const_slice_u8_sentinel_0 => return "[:0]const u8",
1311 .fn_noreturn_no_args => return "fn() noreturn",1345 .fn_noreturn_no_args => return "fn() noreturn",
1312 .fn_void_no_args => return "fn() void",1346 .fn_void_no_args => return "fn() void",
1313 .fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn",1347 .fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn",
...@@ -1315,6 +1349,7 @@ pub const Type = extern union {...@@ -1315,6 +1349,7 @@ pub const Type = extern union {
1315 .single_const_pointer_to_comptime_int => return "*const comptime_int",1349 .single_const_pointer_to_comptime_int => return "*const comptime_int",
1316 .manyptr_u8 => return "[*]u8",1350 .manyptr_u8 => return "[*]u8",
1317 .manyptr_const_u8 => return "[*]const u8",1351 .manyptr_const_u8 => return "[*]const u8",
1352 .manyptr_const_u8_sentinel_0 => return "[*:0]const u8",
1318 .atomic_order => return "AtomicOrder",1353 .atomic_order => return "AtomicOrder",
1319 .atomic_rmw_op => return "AtomicRmwOp",1354 .atomic_rmw_op => return "AtomicRmwOp",
1320 .calling_convention => return "CallingConvention",1355 .calling_convention => return "CallingConvention",
...@@ -1386,11 +1421,13 @@ pub const Type = extern union {...@@ -1386,11 +1421,13 @@ pub const Type = extern union {
1386 .extern_options,1421 .extern_options,
1387 .manyptr_u8,1422 .manyptr_u8,
1388 .manyptr_const_u8,1423 .manyptr_const_u8,
1424 .manyptr_const_u8_sentinel_0,
1389 .fn_noreturn_no_args,1425 .fn_noreturn_no_args,
1390 .fn_void_no_args,1426 .fn_void_no_args,
1391 .fn_naked_noreturn_no_args,1427 .fn_naked_noreturn_no_args,
1392 .fn_ccc_void_no_args,1428 .fn_ccc_void_no_args,
1393 .const_slice_u8,1429 .const_slice_u8,
1430 .const_slice_u8_sentinel_0,
1394 .anyerror_void_error_union,1431 .anyerror_void_error_union,
1395 .empty_struct_literal,1432 .empty_struct_literal,
1396 .function,1433 .function,
...@@ -1498,9 +1535,11 @@ pub const Type = extern union {...@@ -1498,9 +1535,11 @@ pub const Type = extern union {
1498 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),1535 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
1499 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),1536 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
1500 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),1537 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
1538 .const_slice_u8_sentinel_0 => return Value.initTag(.const_slice_u8_sentinel_0_type),
1501 .enum_literal => return Value.initTag(.enum_literal_type),1539 .enum_literal => return Value.initTag(.enum_literal_type),
1502 .manyptr_u8 => return Value.initTag(.manyptr_u8_type),1540 .manyptr_u8 => return Value.initTag(.manyptr_u8_type),
1503 .manyptr_const_u8 => return Value.initTag(.manyptr_const_u8_type),1541 .manyptr_const_u8 => return Value.initTag(.manyptr_const_u8_type),
1542 .manyptr_const_u8_sentinel_0 => return Value.initTag(.manyptr_const_u8_sentinel_0_type),
1504 .atomic_order => return Value.initTag(.atomic_order_type),1543 .atomic_order => return Value.initTag(.atomic_order_type),
1505 .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type),1544 .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type),
1506 .calling_convention => return Value.initTag(.calling_convention_type),1545 .calling_convention => return Value.initTag(.calling_convention_type),
...@@ -1550,6 +1589,7 @@ pub const Type = extern union {...@@ -1550,6 +1589,7 @@ pub const Type = extern union {
1550 .anyerror,1589 .anyerror,
1551 .single_const_pointer_to_comptime_int,1590 .single_const_pointer_to_comptime_int,
1552 .const_slice_u8,1591 .const_slice_u8,
1592 .const_slice_u8_sentinel_0,
1553 .array_u8_sentinel_0,1593 .array_u8_sentinel_0,
1554 .optional,1594 .optional,
1555 .optional_single_mut_pointer,1595 .optional_single_mut_pointer,
...@@ -1561,6 +1601,7 @@ pub const Type = extern union {...@@ -1561,6 +1601,7 @@ pub const Type = extern union {
1561 .error_set_merged,1601 .error_set_merged,
1562 .manyptr_u8,1602 .manyptr_u8,
1563 .manyptr_const_u8,1603 .manyptr_const_u8,
1604 .manyptr_const_u8_sentinel_0,
1564 .atomic_order,1605 .atomic_order,
1565 .atomic_rmw_op,1606 .atomic_rmw_op,
1566 .calling_convention,1607 .calling_convention,
...@@ -1703,7 +1744,9 @@ pub const Type = extern union {...@@ -1703,7 +1744,9 @@ pub const Type = extern union {
17031744
1704 .manyptr_u8,1745 .manyptr_u8,
1705 .manyptr_const_u8,1746 .manyptr_const_u8,
1747 .manyptr_const_u8_sentinel_0,
1706 .const_slice_u8,1748 .const_slice_u8,
1749 .const_slice_u8_sentinel_0,
1707 => return 1,1750 => return 1,
17081751
1709 .pointer => {1752 .pointer => {
...@@ -1723,6 +1766,7 @@ pub const Type = extern union {...@@ -1723,6 +1766,7 @@ pub const Type = extern union {
1723 return switch (self.tag()) {1766 return switch (self.tag()) {
1724 .single_const_pointer_to_comptime_int,1767 .single_const_pointer_to_comptime_int,
1725 .const_slice_u8,1768 .const_slice_u8,
1769 .const_slice_u8_sentinel_0,
1726 .single_const_pointer,1770 .single_const_pointer,
1727 .single_mut_pointer,1771 .single_mut_pointer,
1728 .many_const_pointer,1772 .many_const_pointer,
...@@ -1735,6 +1779,7 @@ pub const Type = extern union {...@@ -1735,6 +1779,7 @@ pub const Type = extern union {
1735 .inferred_alloc_mut,1779 .inferred_alloc_mut,
1736 .manyptr_u8,1780 .manyptr_u8,
1737 .manyptr_const_u8,1781 .manyptr_const_u8,
1782 .manyptr_const_u8_sentinel_0,
1738 => .generic,1783 => .generic,
17391784
1740 .pointer => self.castTag(.pointer).?.data.@"addrspace",1785 .pointer => self.castTag(.pointer).?.data.@"addrspace",
...@@ -1785,6 +1830,7 @@ pub const Type = extern union {...@@ -1785,6 +1830,7 @@ pub const Type = extern union {
1785 .usize,1830 .usize,
1786 .single_const_pointer_to_comptime_int,1831 .single_const_pointer_to_comptime_int,
1787 .const_slice_u8,1832 .const_slice_u8,
1833 .const_slice_u8_sentinel_0,
1788 .single_const_pointer,1834 .single_const_pointer,
1789 .single_mut_pointer,1835 .single_mut_pointer,
1790 .many_const_pointer,1836 .many_const_pointer,
...@@ -1798,6 +1844,7 @@ pub const Type = extern union {...@@ -1798,6 +1844,7 @@ pub const Type = extern union {
1798 .pointer,1844 .pointer,
1799 .manyptr_u8,1845 .manyptr_u8,
1800 .manyptr_const_u8,1846 .manyptr_const_u8,
1847 .manyptr_const_u8_sentinel_0,
1801 .@"anyframe",1848 .@"anyframe",
1802 .anyframe_T,1849 .anyframe_T,
1803 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),1850 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
...@@ -2050,7 +2097,9 @@ pub const Type = extern union {...@@ -2050,7 +2097,9 @@ pub const Type = extern union {
2050 if (self.elemType().hasCodeGenBits()) return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2;2097 if (self.elemType().hasCodeGenBits()) return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2;
2051 return @divExact(target.cpu.arch.ptrBitWidth(), 8);2098 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
2052 },2099 },
2053 .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,2100 .const_slice_u8,
2101 .const_slice_u8_sentinel_0,
2102 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
20542103
2055 .optional_single_const_pointer,2104 .optional_single_const_pointer,
2056 .optional_single_mut_pointer,2105 .optional_single_mut_pointer,
...@@ -2068,6 +2117,7 @@ pub const Type = extern union {...@@ -2068,6 +2117,7 @@ pub const Type = extern union {
2068 .pointer,2117 .pointer,
2069 .manyptr_u8,2118 .manyptr_u8,
2070 .manyptr_const_u8,2119 .manyptr_const_u8,
2120 .manyptr_const_u8_sentinel_0,
2071 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),2121 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
20722122
2073 .c_short => return @divExact(CType.short.sizeInBits(target), 8),2123 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
...@@ -2223,7 +2273,9 @@ pub const Type = extern union {...@@ -2223,7 +2273,9 @@ pub const Type = extern union {
2223 return target.cpu.arch.ptrBitWidth();2273 return target.cpu.arch.ptrBitWidth();
2224 }2274 }
2225 },2275 },
2226 .const_slice_u8 => target.cpu.arch.ptrBitWidth() * 2,2276 .const_slice_u8,
2277 .const_slice_u8_sentinel_0,
2278 => target.cpu.arch.ptrBitWidth() * 2,
22272279
2228 .optional_single_const_pointer,2280 .optional_single_const_pointer,
2229 .optional_single_mut_pointer,2281 .optional_single_mut_pointer,
...@@ -2252,6 +2304,7 @@ pub const Type = extern union {...@@ -2252,6 +2304,7 @@ pub const Type = extern union {
22522304
2253 .manyptr_u8,2305 .manyptr_u8,
2254 .manyptr_const_u8,2306 .manyptr_const_u8,
2307 .manyptr_const_u8_sentinel_0,
2255 => return target.cpu.arch.ptrBitWidth(),2308 => return target.cpu.arch.ptrBitWidth(),
22562309
2257 .c_short => return CType.short.sizeInBits(target),2310 .c_short => return CType.short.sizeInBits(target),
...@@ -2337,12 +2390,14 @@ pub const Type = extern union {...@@ -2337,12 +2390,14 @@ pub const Type = extern union {
2337 .const_slice,2390 .const_slice,
2338 .mut_slice,2391 .mut_slice,
2339 .const_slice_u8,2392 .const_slice_u8,
2393 .const_slice_u8_sentinel_0,
2340 => .Slice,2394 => .Slice,
23412395
2342 .many_const_pointer,2396 .many_const_pointer,
2343 .many_mut_pointer,2397 .many_mut_pointer,
2344 .manyptr_u8,2398 .manyptr_u8,
2345 .manyptr_const_u8,2399 .manyptr_const_u8,
2400 .manyptr_const_u8_sentinel_0,
2346 => .Many,2401 => .Many,
23472402
2348 .c_const_pointer,2403 .c_const_pointer,
...@@ -2367,6 +2422,7 @@ pub const Type = extern union {...@@ -2367,6 +2422,7 @@ pub const Type = extern union {
2367 .const_slice,2422 .const_slice,
2368 .mut_slice,2423 .mut_slice,
2369 .const_slice_u8,2424 .const_slice_u8,
2425 .const_slice_u8_sentinel_0,
2370 => true,2426 => true,
23712427
2372 .pointer => self.castTag(.pointer).?.data.size == .Slice,2428 .pointer => self.castTag(.pointer).?.data.size == .Slice,
...@@ -2383,6 +2439,7 @@ pub const Type = extern union {...@@ -2383,6 +2439,7 @@ pub const Type = extern union {
2383 pub fn slicePtrFieldType(self: Type, buffer: *SlicePtrFieldTypeBuffer) Type {2439 pub fn slicePtrFieldType(self: Type, buffer: *SlicePtrFieldTypeBuffer) Type {
2384 switch (self.tag()) {2440 switch (self.tag()) {
2385 .const_slice_u8 => return Type.initTag(.manyptr_const_u8),2441 .const_slice_u8 => return Type.initTag(.manyptr_const_u8),
2442 .const_slice_u8_sentinel_0 => return Type.initTag(.manyptr_const_u8_sentinel_0),
23862443
2387 .const_slice => {2444 .const_slice => {
2388 const elem_type = self.castTag(.const_slice).?.data;2445 const elem_type = self.castTag(.const_slice).?.data;
...@@ -2464,8 +2521,10 @@ pub const Type = extern union {...@@ -2464,8 +2521,10 @@ pub const Type = extern union {
2464 .c_const_pointer,2521 .c_const_pointer,
2465 .single_const_pointer_to_comptime_int,2522 .single_const_pointer_to_comptime_int,
2466 .const_slice_u8,2523 .const_slice_u8,
2524 .const_slice_u8_sentinel_0,
2467 .const_slice,2525 .const_slice,
2468 .manyptr_const_u8,2526 .manyptr_const_u8,
2527 .manyptr_const_u8_sentinel_0,
2469 => true,2528 => true,
24702529
2471 .pointer => !self.castTag(.pointer).?.data.mutable,2530 .pointer => !self.castTag(.pointer).?.data.mutable,
...@@ -2513,6 +2572,7 @@ pub const Type = extern union {...@@ -2513,6 +2572,7 @@ pub const Type = extern union {
2513 .many_const_pointer,2572 .many_const_pointer,
2514 .many_mut_pointer,2573 .many_mut_pointer,
2515 .manyptr_const_u8,2574 .manyptr_const_u8,
2575 .manyptr_const_u8_sentinel_0,
2516 .manyptr_u8,2576 .manyptr_u8,
2517 .optional_single_const_pointer,2577 .optional_single_const_pointer,
2518 .optional_single_mut_pointer,2578 .optional_single_mut_pointer,
...@@ -2648,9 +2708,11 @@ pub const Type = extern union {...@@ -2648,9 +2708,11 @@ pub const Type = extern union {
2648 .array_u8,2708 .array_u8,
2649 .array_u8_sentinel_0,2709 .array_u8_sentinel_0,
2650 .const_slice_u8,2710 .const_slice_u8,
2711 .const_slice_u8_sentinel_0,
2651 .manyptr_u8,2712 .manyptr_u8,
2652 .manyptr_const_u8,2713 .manyptr_const_u8,
2653 => Type.initTag(.u8),2714 .manyptr_const_u8_sentinel_0,
2715 => Type.u8,
26542716
2655 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),2717 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
2656 .pointer => ty.castTag(.pointer).?.data.pointee_type,2718 .pointer => ty.castTag(.pointer).?.data.pointee_type,
...@@ -2690,9 +2752,11 @@ pub const Type = extern union {...@@ -2690,9 +2752,11 @@ pub const Type = extern union {
2690 .array_u8,2752 .array_u8,
2691 .array_u8_sentinel_0,2753 .array_u8_sentinel_0,
2692 .const_slice_u8,2754 .const_slice_u8,
2755 .const_slice_u8_sentinel_0,
2693 .manyptr_u8,2756 .manyptr_u8,
2694 .manyptr_const_u8,2757 .manyptr_const_u8,
2695 => Type.initTag(.u8),2758 .manyptr_const_u8_sentinel_0,
2759 => Type.u8,
26962760
2697 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),2761 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
2698 .pointer => {2762 .pointer => {
...@@ -2937,7 +3001,11 @@ pub const Type = extern union {...@@ -2937,7 +3001,11 @@ pub const Type = extern union {
29373001
2938 .pointer => return self.castTag(.pointer).?.data.sentinel,3002 .pointer => return self.castTag(.pointer).?.data.sentinel,
2939 .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,3003 .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,
2940 .array_u8_sentinel_0 => return Value.zero,3004
3005 .array_u8_sentinel_0,
3006 .const_slice_u8_sentinel_0,
3007 .manyptr_const_u8_sentinel_0,
3008 => return Value.zero,
29413009
2942 else => unreachable,3010 else => unreachable,
2943 };3011 };
...@@ -3309,6 +3377,7 @@ pub const Type = extern union {...@@ -3309,6 +3377,7 @@ pub const Type = extern union {
3309 .array_sentinel,3377 .array_sentinel,
3310 .array_u8_sentinel_0,3378 .array_u8_sentinel_0,
3311 .const_slice_u8,3379 .const_slice_u8,
3380 .const_slice_u8_sentinel_0,
3312 .const_slice,3381 .const_slice,
3313 .mut_slice,3382 .mut_slice,
3314 .anyopaque,3383 .anyopaque,
...@@ -3326,6 +3395,7 @@ pub const Type = extern union {...@@ -3326,6 +3395,7 @@ pub const Type = extern union {
3326 .var_args_param,3395 .var_args_param,
3327 .manyptr_u8,3396 .manyptr_u8,
3328 .manyptr_const_u8,3397 .manyptr_const_u8,
3398 .manyptr_const_u8_sentinel_0,
3329 .atomic_order,3399 .atomic_order,
3330 .atomic_rmw_op,3400 .atomic_rmw_op,
3331 .calling_convention,3401 .calling_convention,
...@@ -3956,12 +4026,14 @@ pub const Type = extern union {...@@ -3956,12 +4026,14 @@ pub const Type = extern union {
3956 type_info,4026 type_info,
3957 manyptr_u8,4027 manyptr_u8,
3958 manyptr_const_u8,4028 manyptr_const_u8,
4029 manyptr_const_u8_sentinel_0,
3959 fn_noreturn_no_args,4030 fn_noreturn_no_args,
3960 fn_void_no_args,4031 fn_void_no_args,
3961 fn_naked_noreturn_no_args,4032 fn_naked_noreturn_no_args,
3962 fn_ccc_void_no_args,4033 fn_ccc_void_no_args,
3963 single_const_pointer_to_comptime_int,4034 single_const_pointer_to_comptime_int,
3964 const_slice_u8,4035 const_slice_u8,
4036 const_slice_u8_sentinel_0,
3965 anyerror_void_error_union,4037 anyerror_void_error_union,
3966 generic_poison,4038 generic_poison,
3967 /// This is a special type for variadic parameters of a function call.4039 /// This is a special type for variadic parameters of a function call.
...@@ -4064,6 +4136,7 @@ pub const Type = extern union {...@@ -4064,6 +4136,7 @@ pub const Type = extern union {
4064 .single_const_pointer_to_comptime_int,4136 .single_const_pointer_to_comptime_int,
4065 .anyerror_void_error_union,4137 .anyerror_void_error_union,
4066 .const_slice_u8,4138 .const_slice_u8,
4139 .const_slice_u8_sentinel_0,
4067 .generic_poison,4140 .generic_poison,
4068 .inferred_alloc_const,4141 .inferred_alloc_const,
4069 .inferred_alloc_mut,4142 .inferred_alloc_mut,
...@@ -4071,6 +4144,7 @@ pub const Type = extern union {...@@ -4071,6 +4144,7 @@ pub const Type = extern union {
4071 .empty_struct_literal,4144 .empty_struct_literal,
4072 .manyptr_u8,4145 .manyptr_u8,
4073 .manyptr_const_u8,4146 .manyptr_const_u8,
4147 .manyptr_const_u8_sentinel_0,
4074 .atomic_order,4148 .atomic_order,
4075 .atomic_rmw_op,4149 .atomic_rmw_op,
4076 .calling_convention,4150 .calling_convention,
...@@ -4322,36 +4396,55 @@ pub const Type = extern union {...@@ -4322,36 +4396,55 @@ pub const Type = extern union {
43224396
4323 pub fn ptr(arena: Allocator, d: Payload.Pointer.Data) !Type {4397 pub fn ptr(arena: Allocator, d: Payload.Pointer.Data) !Type {
4324 assert(d.host_size == 0 or d.bit_offset < d.host_size * 8);4398 assert(d.host_size == 0 or d.bit_offset < d.host_size * 8);
4399 if (d.size == .C) {
4400 assert(d.@"allowzero"); // All C pointers must set allowzero to true.
4401 }
43254402
4326 if (d.sentinel != null or d.@"align" != 0 or d.@"addrspace" != .generic or4403 if (d.@"align" == 0 and d.@"addrspace" == .generic and
4327 d.bit_offset != 0 or d.host_size != 0 or d.@"allowzero" or d.@"volatile")4404 d.bit_offset == 0 and d.host_size == 0 and !d.@"allowzero" and !d.@"volatile")
4328 {4405 {
4329 if (d.size == .C) {4406 if (d.sentinel) |sent| {
4330 assert(d.@"allowzero"); // All C pointers must set allowzero to true.4407 if (!d.mutable and d.pointee_type.eql(Type.u8)) {
4408 switch (d.size) {
4409 .Slice => {
4410 if (sent.compareWithZero(.eq)) {
4411 return Type.initTag(.const_slice_u8_sentinel_0);
4412 }
4413 },
4414 .Many => {
4415 if (sent.compareWithZero(.eq)) {
4416 return Type.initTag(.manyptr_const_u8_sentinel_0);
4417 }
4418 },
4419 else => {},
4420 }
4421 }
4422 } else if (!d.mutable and d.pointee_type.eql(Type.u8)) {
4423 switch (d.size) {
4424 .Slice => return Type.initTag(.const_slice_u8),
4425 .Many => return Type.initTag(.manyptr_const_u8),
4426 else => {},
4427 }
4428 } else {
4429 // TODO stage1 type inference bug
4430 const T = Type.Tag;
4431
4432 const type_payload = try arena.create(Type.Payload.ElemType);
4433 type_payload.* = .{
4434 .base = .{
4435 .tag = switch (d.size) {
4436 .One => if (d.mutable) T.single_mut_pointer else T.single_const_pointer,
4437 .Many => if (d.mutable) T.many_mut_pointer else T.many_const_pointer,
4438 .C => if (d.mutable) T.c_mut_pointer else T.c_const_pointer,
4439 .Slice => if (d.mutable) T.mut_slice else T.const_slice,
4440 },
4441 },
4442 .data = d.pointee_type,
4443 };
4444 return Type.initPayload(&type_payload.base);
4331 }4445 }
4332 return Type.Tag.pointer.create(arena, d);
4333 }
4334
4335 if (!d.mutable and d.size == .Slice and d.pointee_type.eql(Type.initTag(.u8))) {
4336 return Type.initTag(.const_slice_u8);
4337 }4446 }
43384447 return Type.Tag.pointer.create(arena, d);
4339 // TODO stage1 type inference bug
4340 const T = Type.Tag;
4341
4342 const type_payload = try arena.create(Type.Payload.ElemType);
4343 type_payload.* = .{
4344 .base = .{
4345 .tag = switch (d.size) {
4346 .One => if (d.mutable) T.single_mut_pointer else T.single_const_pointer,
4347 .Many => if (d.mutable) T.many_mut_pointer else T.many_const_pointer,
4348 .C => if (d.mutable) T.c_mut_pointer else T.c_const_pointer,
4349 .Slice => if (d.mutable) T.mut_slice else T.const_slice,
4350 },
4351 },
4352 .data = d.pointee_type,
4353 };
4354 return Type.initPayload(&type_payload.base);
4355 }4448 }
43564449
4357 pub fn array(4450 pub fn array(
src/value.zig+10
...@@ -73,12 +73,14 @@ pub const Value = extern union {...@@ -73,12 +73,14 @@ pub const Value = extern union {
73 type_info_type,73 type_info_type,
74 manyptr_u8_type,74 manyptr_u8_type,
75 manyptr_const_u8_type,75 manyptr_const_u8_type,
76 manyptr_const_u8_sentinel_0_type,
76 fn_noreturn_no_args_type,77 fn_noreturn_no_args_type,
77 fn_void_no_args_type,78 fn_void_no_args_type,
78 fn_naked_noreturn_no_args_type,79 fn_naked_noreturn_no_args_type,
79 fn_ccc_void_no_args_type,80 fn_ccc_void_no_args_type,
80 single_const_pointer_to_comptime_int_type,81 single_const_pointer_to_comptime_int_type,
81 const_slice_u8_type,82 const_slice_u8_type,
83 const_slice_u8_sentinel_0_type,
82 anyerror_void_error_union_type,84 anyerror_void_error_union_type,
83 generic_poison_type,85 generic_poison_type,
8486
...@@ -221,6 +223,7 @@ pub const Value = extern union {...@@ -221,6 +223,7 @@ pub const Value = extern union {
221 .single_const_pointer_to_comptime_int_type,223 .single_const_pointer_to_comptime_int_type,
222 .anyframe_type,224 .anyframe_type,
223 .const_slice_u8_type,225 .const_slice_u8_type,
226 .const_slice_u8_sentinel_0_type,
224 .anyerror_void_error_union_type,227 .anyerror_void_error_union_type,
225 .generic_poison_type,228 .generic_poison_type,
226 .enum_literal_type,229 .enum_literal_type,
...@@ -238,6 +241,7 @@ pub const Value = extern union {...@@ -238,6 +241,7 @@ pub const Value = extern union {
238 .abi_align_default,241 .abi_align_default,
239 .manyptr_u8_type,242 .manyptr_u8_type,
240 .manyptr_const_u8_type,243 .manyptr_const_u8_type,
244 .manyptr_const_u8_sentinel_0_type,
241 .atomic_order_type,245 .atomic_order_type,
242 .atomic_rmw_op_type,246 .atomic_rmw_op_type,
243 .calling_convention_type,247 .calling_convention_type,
...@@ -412,6 +416,7 @@ pub const Value = extern union {...@@ -412,6 +416,7 @@ pub const Value = extern union {
412 .single_const_pointer_to_comptime_int_type,416 .single_const_pointer_to_comptime_int_type,
413 .anyframe_type,417 .anyframe_type,
414 .const_slice_u8_type,418 .const_slice_u8_type,
419 .const_slice_u8_sentinel_0_type,
415 .anyerror_void_error_union_type,420 .anyerror_void_error_union_type,
416 .generic_poison_type,421 .generic_poison_type,
417 .enum_literal_type,422 .enum_literal_type,
...@@ -429,6 +434,7 @@ pub const Value = extern union {...@@ -429,6 +434,7 @@ pub const Value = extern union {
429 .abi_align_default,434 .abi_align_default,
430 .manyptr_u8_type,435 .manyptr_u8_type,
431 .manyptr_const_u8_type,436 .manyptr_const_u8_type,
437 .manyptr_const_u8_sentinel_0_type,
432 .atomic_order_type,438 .atomic_order_type,
433 .atomic_rmw_op_type,439 .atomic_rmw_op_type,
434 .calling_convention_type,440 .calling_convention_type,
...@@ -642,12 +648,14 @@ pub const Value = extern union {...@@ -642,12 +648,14 @@ pub const Value = extern union {
642 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),648 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
643 .anyframe_type => return out_stream.writeAll("anyframe"),649 .anyframe_type => return out_stream.writeAll("anyframe"),
644 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),650 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
651 .const_slice_u8_sentinel_0_type => return out_stream.writeAll("[:0]const u8"),
645 .anyerror_void_error_union_type => return out_stream.writeAll("anyerror!void"),652 .anyerror_void_error_union_type => return out_stream.writeAll("anyerror!void"),
646 .generic_poison_type => return out_stream.writeAll("(generic poison type)"),653 .generic_poison_type => return out_stream.writeAll("(generic poison type)"),
647 .generic_poison => return out_stream.writeAll("(generic poison)"),654 .generic_poison => return out_stream.writeAll("(generic poison)"),
648 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),655 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
649 .manyptr_u8_type => return out_stream.writeAll("[*]u8"),656 .manyptr_u8_type => return out_stream.writeAll("[*]u8"),
650 .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"),657 .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"),
658 .manyptr_const_u8_sentinel_0_type => return out_stream.writeAll("[*:0]const u8"),
651 .atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"),659 .atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"),
652 .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"),660 .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"),
653 .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"),661 .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"),
...@@ -821,11 +829,13 @@ pub const Value = extern union {...@@ -821,11 +829,13 @@ pub const Value = extern union {
821 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),829 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
822 .anyframe_type => Type.initTag(.@"anyframe"),830 .anyframe_type => Type.initTag(.@"anyframe"),
823 .const_slice_u8_type => Type.initTag(.const_slice_u8),831 .const_slice_u8_type => Type.initTag(.const_slice_u8),
832 .const_slice_u8_sentinel_0_type => Type.initTag(.const_slice_u8_sentinel_0),
824 .anyerror_void_error_union_type => Type.initTag(.anyerror_void_error_union),833 .anyerror_void_error_union_type => Type.initTag(.anyerror_void_error_union),
825 .generic_poison_type => Type.initTag(.generic_poison),834 .generic_poison_type => Type.initTag(.generic_poison),
826 .enum_literal_type => Type.initTag(.enum_literal),835 .enum_literal_type => Type.initTag(.enum_literal),
827 .manyptr_u8_type => Type.initTag(.manyptr_u8),836 .manyptr_u8_type => Type.initTag(.manyptr_u8),
828 .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8),837 .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8),
838 .manyptr_const_u8_sentinel_0_type => Type.initTag(.manyptr_const_u8_sentinel_0),
829 .atomic_order_type => Type.initTag(.atomic_order),839 .atomic_order_type => Type.initTag(.atomic_order),
830 .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op),840 .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op),
831 .calling_convention_type => Type.initTag(.calling_convention),841 .calling_convention_type => Type.initTag(.calling_convention),
test/behavior.zig+1
...@@ -75,6 +75,7 @@ test {...@@ -75,6 +75,7 @@ test {
75 _ = @import("behavior/bugs/3112.zig");75 _ = @import("behavior/bugs/3112.zig");
76 _ = @import("behavior/bugs/7250.zig");76 _ = @import("behavior/bugs/7250.zig");
77 _ = @import("behavior/cast_llvm.zig");77 _ = @import("behavior/cast_llvm.zig");
78 _ = @import("behavior/enum_llvm.zig");
78 _ = @import("behavior/eval.zig");79 _ = @import("behavior/eval.zig");
79 _ = @import("behavior/floatop.zig");80 _ = @import("behavior/floatop.zig");
80 _ = @import("behavior/fn.zig");81 _ = @import("behavior/fn.zig");
test/behavior/enum.zig+123
...@@ -699,3 +699,126 @@ test "single field non-exhaustive enum" {...@@ -699,3 +699,126 @@ test "single field non-exhaustive enum" {
699 try S.doTheTest(23);699 try S.doTheTest(23);
700 comptime try S.doTheTest(23);700 comptime try S.doTheTest(23);
701}701}
702
703const EnumWithTagValues = enum(u4) {
704 A = 1 << 0,
705 B = 1 << 1,
706 C = 1 << 2,
707 D = 1 << 3,
708};
709test "enum with tag values don't require parens" {
710 try expect(@enumToInt(EnumWithTagValues.C) == 0b0100);
711}
712
713const MultipleChoice2 = enum(u32) {
714 Unspecified1,
715 A = 20,
716 Unspecified2,
717 B = 40,
718 Unspecified3,
719 C = 60,
720 Unspecified4,
721 D = 1000,
722 Unspecified5,
723};
724
725test "cast integer literal to enum" {
726 try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
727 try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
728}
729
730test "enum with specified and unspecified tag values" {
731 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
732 comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
733}
734
735fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
736 try expect(@enumToInt(x) == 1000);
737 try expect(1234 == switch (x) {
738 MultipleChoice2.A => 1,
739 MultipleChoice2.B => 2,
740 MultipleChoice2.C => 3,
741 MultipleChoice2.D => @as(u32, 1234),
742 MultipleChoice2.Unspecified1 => 5,
743 MultipleChoice2.Unspecified2 => 6,
744 MultipleChoice2.Unspecified3 => 7,
745 MultipleChoice2.Unspecified4 => 8,
746 MultipleChoice2.Unspecified5 => 9,
747 });
748}
749
750const Small2 = enum(u2) { One, Two };
751const Small = enum(u2) { One, Two, Three, Four };
752
753test "set enum tag type" {
754 {
755 var x = Small.One;
756 x = Small.Two;
757 comptime try expect(Tag(Small) == u2);
758 }
759 {
760 var x = Small2.One;
761 x = Small2.Two;
762 comptime try expect(Tag(Small2) == u2);
763 }
764}
765
766test "casting enum to its tag type" {
767 try testCastEnumTag(Small2.Two);
768 comptime try testCastEnumTag(Small2.Two);
769}
770
771fn testCastEnumTag(value: Small2) !void {
772 try expect(@enumToInt(value) == 1);
773}
774
775test "enum with 1 field but explicit tag type should still have the tag type" {
776 const Enum = enum(u8) {
777 B = 2,
778 };
779 comptime try expect(@sizeOf(Enum) == @sizeOf(u8));
780}
781
782test "signed integer as enum tag" {
783 const SignedEnum = enum(i2) {
784 A0 = -1,
785 A1 = 0,
786 A2 = 1,
787 };
788
789 try expect(@enumToInt(SignedEnum.A0) == -1);
790 try expect(@enumToInt(SignedEnum.A1) == 0);
791 try expect(@enumToInt(SignedEnum.A2) == 1);
792}
793
794test "enum with one member and custom tag type" {
795 const E = enum(u2) {
796 One,
797 };
798 try expect(@enumToInt(E.One) == 0);
799 const E2 = enum(u2) {
800 One = 2,
801 };
802 try expect(@enumToInt(E2.One) == 2);
803}
804
805test "enum with one member and u1 tag type @enumToInt" {
806 const Enum = enum(u1) {
807 Test,
808 };
809 try expect(@enumToInt(Enum.Test) == 0);
810}
811
812test "enum with comptime_int tag type" {
813 const Enum = enum(comptime_int) {
814 One = 3,
815 Two = 2,
816 Three = 1,
817 };
818 comptime try expect(Tag(Enum) == comptime_int);
819}
820
821test "enum with one member default to u0 tag type" {
822 const E0 = enum { X };
823 comptime try expect(Tag(E0) == u0);
824}
test/behavior/enum_llvm.zig created+49
...@@ -0,0 +1,49 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const mem = std.mem;
4const Tag = std.meta.Tag;
5
6test "@tagName" {
7 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
8 comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
9}
10
11fn testEnumTagNameBare(n: anytype) []const u8 {
12 return @tagName(n);
13}
14
15const BareNumber = enum { One, Two, Three };
16
17test "@tagName non-exhaustive enum" {
18 try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
19 comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
20}
21const NonExhaustive = enum(u8) { A, B, _ };
22
23test "@tagName is null-terminated" {
24 const S = struct {
25 fn doTheTest(n: BareNumber) !void {
26 try expect(@tagName(n)[3] == 0);
27 }
28 };
29 try S.doTheTest(.Two);
30 try comptime S.doTheTest(.Two);
31}
32
33test "tag name with assigned enum values" {
34 const LocalFoo = enum(u8) {
35 A = 1,
36 B = 0,
37 };
38 var b = LocalFoo.B;
39 try expect(mem.eql(u8, @tagName(b), "B"));
40}
41
42const Bar = enum { A, B, C, D };
43
44test "enum literal casting to optional" {
45 var bar: ?Bar = undefined;
46 bar = .B;
47
48 try expect(bar.? == Bar.B);
49}
test/behavior/enum_stage1.zig-151
...@@ -2,47 +2,7 @@ const expect = @import("std").testing.expect;...@@ -2,47 +2,7 @@ const expect = @import("std").testing.expect;
2const mem = @import("std").mem;2const mem = @import("std").mem;
3const Tag = @import("std").meta.Tag;3const Tag = @import("std").meta.Tag;
44
5test "@tagName" {
6 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
7 comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
8}
9
10test "@tagName non-exhaustive enum" {
11 try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
12 comptime try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
13}
14
15test "@tagName is null-terminated" {
16 const S = struct {
17 fn doTheTest(n: BareNumber) !void {
18 try expect(@tagName(n)[3] == 0);
19 }
20 };
21 try S.doTheTest(.Two);
22 try comptime S.doTheTest(.Two);
23}
24
25fn testEnumTagNameBare(n: anytype) []const u8 {
26 return @tagName(n);
27}
28
29const BareNumber = enum { One, Two, Three };
30const NonExhaustive = enum(u8) { A, B, _ };
31const Small2 = enum(u2) { One, Two };5const Small2 = enum(u2) { One, Two };
32const Small = enum(u2) { One, Two, Three, Four };
33
34test "set enum tag type" {
35 {
36 var x = Small.One;
37 x = Small.Two;
38 comptime try expect(Tag(Small) == u2);
39 }
40 {
41 var x = Small2.One;
42 x = Small2.Two;
43 comptime try expect(Tag(Small2) == u2);
44 }
45}
466
47const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };7const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
48const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };8const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
...@@ -87,15 +47,6 @@ fn getC(data: *const BitFieldOfEnums) C {...@@ -87,15 +47,6 @@ fn getC(data: *const BitFieldOfEnums) C {
87 return data.c;47 return data.c;
88}48}
8949
90test "casting enum to its tag type" {
91 try testCastEnumTag(Small2.Two);
92 comptime try testCastEnumTag(Small2.Two);
93}
94
95fn testCastEnumTag(value: Small2) !void {
96 try expect(@enumToInt(value) == 1);
97}
98
99const MultipleChoice2 = enum(u32) {50const MultipleChoice2 = enum(u32) {
100 Unspecified1,51 Unspecified1,
101 A = 20,52 A = 20,
...@@ -108,31 +59,6 @@ const MultipleChoice2 = enum(u32) {...@@ -108,31 +59,6 @@ const MultipleChoice2 = enum(u32) {
108 Unspecified5,59 Unspecified5,
109};60};
11061
111test "enum with specified and unspecified tag values" {
112 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
113 comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
114}
115
116fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
117 try expect(@enumToInt(x) == 1000);
118 try expect(1234 == switch (x) {
119 MultipleChoice2.A => 1,
120 MultipleChoice2.B => 2,
121 MultipleChoice2.C => 3,
122 MultipleChoice2.D => @as(u32, 1234),
123 MultipleChoice2.Unspecified1 => 5,
124 MultipleChoice2.Unspecified2 => 6,
125 MultipleChoice2.Unspecified3 => 7,
126 MultipleChoice2.Unspecified4 => 8,
127 MultipleChoice2.Unspecified5 => 9,
128 });
129}
130
131test "cast integer literal to enum" {
132 try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
133 try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
134}
135
136const EnumWithOneMember = enum { Eof };62const EnumWithOneMember = enum { Eof };
13763
138fn doALoopThing(id: EnumWithOneMember) void {64fn doALoopThing(id: EnumWithOneMember) void {
...@@ -157,32 +83,6 @@ test "switch on enum with one member is comptime known" {...@@ -157,32 +83,6 @@ test "switch on enum with one member is comptime known" {
157 @compileError("analysis should not reach here");83 @compileError("analysis should not reach here");
158}84}
15985
160const EnumWithTagValues = enum(u4) {
161 A = 1 << 0,
162 B = 1 << 1,
163 C = 1 << 2,
164 D = 1 << 3,
165};
166test "enum with tag values don't require parens" {
167 try expect(@enumToInt(EnumWithTagValues.C) == 0b0100);
168}
169
170test "enum with 1 field but explicit tag type should still have the tag type" {
171 const Enum = enum(u8) {
172 B = 2,
173 };
174 comptime try expect(@sizeOf(Enum) == @sizeOf(u8));
175}
176
177test "tag name with assigned enum values" {
178 const LocalFoo = enum(u8) {
179 A = 1,
180 B = 0,
181 };
182 var b = LocalFoo.B;
183 try expect(mem.eql(u8, @tagName(b), "B"));
184}
185
186test "enum literal in array literal" {86test "enum literal in array literal" {
187 const Items = enum { one, two };87 const Items = enum { one, two };
188 const array = [_]Items{ .one, .two };88 const array = [_]Items{ .one, .two };
...@@ -191,18 +91,6 @@ test "enum literal in array literal" {...@@ -191,18 +91,6 @@ test "enum literal in array literal" {
191 try expect(array[1] == .two);91 try expect(array[1] == .two);
192}92}
19393
194test "signed integer as enum tag" {
195 const SignedEnum = enum(i2) {
196 A0 = -1,
197 A1 = 0,
198 A2 = 1,
199 };
200
201 try expect(@enumToInt(SignedEnum.A0) == -1);
202 try expect(@enumToInt(SignedEnum.A1) == 0);
203 try expect(@enumToInt(SignedEnum.A2) == 1);
204}
205
206test "enum value allocation" {94test "enum value allocation" {
207 const LargeEnum = enum(u32) {95 const LargeEnum = enum(u32) {
208 A0 = 0x80000000,96 A0 = 0x80000000,
...@@ -235,26 +123,8 @@ test "enum literal casting to tagged union" {...@@ -235,26 +123,8 @@ test "enum literal casting to tagged union" {
235 }123 }
236}124}
237125
238test "enum with one member and custom tag type" {
239 const E = enum(u2) {
240 One,
241 };
242 try expect(@enumToInt(E.One) == 0);
243 const E2 = enum(u2) {
244 One = 2,
245 };
246 try expect(@enumToInt(E2.One) == 2);
247}
248
249const Bar = enum { A, B, C, D };126const Bar = enum { A, B, C, D };
250127
251test "enum literal casting to optional" {
252 var bar: ?Bar = undefined;
253 bar = .B;
254
255 try expect(bar.? == Bar.B);
256}
257
258test "enum literal casting to error union with payload enum" {128test "enum literal casting to error union with payload enum" {
259 var bar: error{B}!Bar = undefined;129 var bar: error{B}!Bar = undefined;
260 bar = .B; // should never cast to the error set130 bar = .B; // should never cast to the error set
...@@ -262,27 +132,6 @@ test "enum literal casting to error union with payload enum" {...@@ -262,27 +132,6 @@ test "enum literal casting to error union with payload enum" {
262 try expect((try bar) == Bar.B);132 try expect((try bar) == Bar.B);
263}133}
264134
265test "enum with one member and u1 tag type @enumToInt" {
266 const Enum = enum(u1) {
267 Test,
268 };
269 try expect(@enumToInt(Enum.Test) == 0);
270}
271
272test "enum with comptime_int tag type" {
273 const Enum = enum(comptime_int) {
274 One = 3,
275 Two = 2,
276 Three = 1,
277 };
278 comptime try expect(Tag(Enum) == comptime_int);
279}
280
281test "enum with one member default to u0 tag type" {
282 const E0 = enum { X };
283 comptime try expect(Tag(E0) == u0);
284}
285
286test "tagName on enum literals" {135test "tagName on enum literals" {
287 try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));136 try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
288 comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));137 comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));