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 {
496496 /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`.
497497 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
499504 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
500505 return switch (op) {
501506 .lt => .cmp_lt,
......@@ -811,6 +816,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
811816
812817 .bool_to_int => return Type.initTag(.u1),
813818
819 .tag_name => return Type.initTag(.const_slice_u8_sentinel_0),
820
814821 .call => {
815822 const callee_ty = air.typeOf(datas[inst].pl_op.operand);
816823 switch (callee_ty.zigTypeTag()) {
src/Liveness.zig+1
......@@ -333,6 +333,7 @@ fn analyzeInst(
333333 .bool_to_int,
334334 .ret,
335335 .ret_load,
336 .tag_name,
336337 => {
337338 const operand = inst_datas[inst].un_op;
338339 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
28042804 const tracy = trace(@src());
28052805 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 {
28092812 // `zir_bytes` references memory inside the ZIR module, which can get deallocated
28102813 // after semantic analysis is complete, for example in the case of the initialization
28112814 // 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
1004510048
1004610049fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1004710050 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 };
1004810052 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);
1005010095}
1005110096
1005210097fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -15339,6 +15384,7 @@ fn typeHasOnePossibleValue(
1533915384 .array_sentinel,
1534015385 .array_u8_sentinel_0,
1534115386 .const_slice_u8,
15387 .const_slice_u8_sentinel_0,
1534215388 .const_slice,
1534315389 .mut_slice,
1534415390 .anyopaque,
......@@ -15356,6 +15402,7 @@ fn typeHasOnePossibleValue(
1535615402 .var_args_param,
1535715403 .manyptr_u8,
1535815404 .manyptr_const_u8,
15405 .manyptr_const_u8_sentinel_0,
1535915406 .atomic_order,
1536015407 .atomic_rmw_op,
1536115408 .calling_convention,
src/arch/aarch64/CodeGen.zig+138-127
......@@ -504,133 +504,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
504504
505505 switch (air_tags[inst]) {
506506 // zig fmt: off
507 .add, .ptr_add => try self.airAdd(inst),
508 .addwrap => try self.airAddWrap(inst),
509 .add_sat => try self.airAddSat(inst),
510 .sub, .ptr_sub => try self.airSub(inst),
511 .subwrap => try self.airSubWrap(inst),
512 .sub_sat => try self.airSubSat(inst),
513 .mul => try self.airMul(inst),
514 .mulwrap => try self.airMulWrap(inst),
515 .mul_sat => try self.airMulSat(inst),
516 .rem => try self.airRem(inst),
517 .mod => try self.airMod(inst),
518 .shl, .shl_exact => try self.airShl(inst),
519 .shl_sat => try self.airShlSat(inst),
520 .min => try self.airMin(inst),
521 .max => try self.airMax(inst),
522 .slice => try self.airSlice(inst),
523
524 .add_with_overflow => try self.airAddWithOverflow(inst),
525 .sub_with_overflow => try self.airSubWithOverflow(inst),
526 .mul_with_overflow => try self.airMulWithOverflow(inst),
527 .shl_with_overflow => try self.airShlWithOverflow(inst),
528
529 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
530
531 .cmp_lt => try self.airCmp(inst, .lt),
532 .cmp_lte => try self.airCmp(inst, .lte),
533 .cmp_eq => try self.airCmp(inst, .eq),
534 .cmp_gte => try self.airCmp(inst, .gte),
535 .cmp_gt => try self.airCmp(inst, .gt),
536 .cmp_neq => try self.airCmp(inst, .neq),
537
538 .bool_and => try self.airBoolOp(inst),
539 .bool_or => try self.airBoolOp(inst),
540 .bit_and => try self.airBitAnd(inst),
541 .bit_or => try self.airBitOr(inst),
542 .xor => try self.airXor(inst),
543 .shr => try self.airShr(inst),
544
545 .alloc => try self.airAlloc(inst),
546 .ret_ptr => try self.airRetPtr(inst),
547 .arg => try self.airArg(inst),
548 .assembly => try self.airAsm(inst),
549 .bitcast => try self.airBitCast(inst),
550 .block => try self.airBlock(inst),
551 .br => try self.airBr(inst),
552 .breakpoint => try self.airBreakpoint(),
553 .ret_addr => try self.airRetAddr(),
554 .fence => try self.airFence(),
555 .call => try self.airCall(inst),
556 .cond_br => try self.airCondBr(inst),
557 .dbg_stmt => try self.airDbgStmt(inst),
558 .fptrunc => try self.airFptrunc(inst),
559 .fpext => try self.airFpext(inst),
560 .intcast => try self.airIntCast(inst),
561 .trunc => try self.airTrunc(inst),
562 .bool_to_int => try self.airBoolToInt(inst),
563 .is_non_null => try self.airIsNonNull(inst),
564 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
565 .is_null => try self.airIsNull(inst),
566 .is_null_ptr => try self.airIsNullPtr(inst),
567 .is_non_err => try self.airIsNonErr(inst),
568 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
569 .is_err => try self.airIsErr(inst),
570 .is_err_ptr => try self.airIsErrPtr(inst),
571 .load => try self.airLoad(inst),
572 .loop => try self.airLoop(inst),
573 .not => try self.airNot(inst),
574 .ptrtoint => try self.airPtrToInt(inst),
575 .ret => try self.airRet(inst),
576 .ret_load => try self.airRetLoad(inst),
577 .store => try self.airStore(inst),
578 .struct_field_ptr=> try self.airStructFieldPtr(inst),
579 .struct_field_val=> try self.airStructFieldVal(inst),
580 .array_to_slice => try self.airArrayToSlice(inst),
581 .int_to_float => try self.airIntToFloat(inst),
582 .float_to_int => try self.airFloatToInt(inst),
583 .cmpxchg_strong => try self.airCmpxchg(inst),
584 .cmpxchg_weak => try self.airCmpxchg(inst),
585 .atomic_rmw => try self.airAtomicRmw(inst),
586 .atomic_load => try self.airAtomicLoad(inst),
587 .memcpy => try self.airMemcpy(inst),
588 .memset => try self.airMemset(inst),
589 .set_union_tag => try self.airSetUnionTag(inst),
590 .get_union_tag => try self.airGetUnionTag(inst),
591 .clz => try self.airClz(inst),
592 .ctz => try self.airCtz(inst),
593 .popcount => try self.airPopcount(inst),
594
595 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
596 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
597 .atomic_store_release => try self.airAtomicStore(inst, .Release),
598 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
599
600 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
601 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
602 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
603 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
604
605 .switch_br => try self.airSwitch(inst),
606 .slice_ptr => try self.airSlicePtr(inst),
607 .slice_len => try self.airSliceLen(inst),
608
609 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
610 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
611
612 .array_elem_val => try self.airArrayElemVal(inst),
613 .slice_elem_val => try self.airSliceElemVal(inst),
614 .slice_elem_ptr => try self.airSliceElemPtr(inst),
615 .ptr_elem_val => try self.airPtrElemVal(inst),
616 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
617
618 .constant => unreachable, // excluded from function bodies
619 .const_ty => unreachable, // excluded from function bodies
620 .unreach => self.finishAirBookkeeping(),
621
622 .optional_payload => try self.airOptionalPayload(inst),
623 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
624 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
625 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
626 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
627 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
628 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
629
630 .wrap_optional => try self.airWrapOptional(inst),
631 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
632 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
633 // zig fmt: on
507 .add, .ptr_add => try self.airAdd(inst),
508 .addwrap => try self.airAddWrap(inst),
509 .add_sat => try self.airAddSat(inst),
510 .sub, .ptr_sub => try self.airSub(inst),
511 .subwrap => try self.airSubWrap(inst),
512 .sub_sat => try self.airSubSat(inst),
513 .mul => try self.airMul(inst),
514 .mulwrap => try self.airMulWrap(inst),
515 .mul_sat => try self.airMulSat(inst),
516 .rem => try self.airRem(inst),
517 .mod => try self.airMod(inst),
518 .shl, .shl_exact => try self.airShl(inst),
519 .shl_sat => try self.airShlSat(inst),
520 .min => try self.airMin(inst),
521 .max => try self.airMax(inst),
522 .slice => try self.airSlice(inst),
523
524 .add_with_overflow => try self.airAddWithOverflow(inst),
525 .sub_with_overflow => try self.airSubWithOverflow(inst),
526 .mul_with_overflow => try self.airMulWithOverflow(inst),
527 .shl_with_overflow => try self.airShlWithOverflow(inst),
528
529 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
530
531 .cmp_lt => try self.airCmp(inst, .lt),
532 .cmp_lte => try self.airCmp(inst, .lte),
533 .cmp_eq => try self.airCmp(inst, .eq),
534 .cmp_gte => try self.airCmp(inst, .gte),
535 .cmp_gt => try self.airCmp(inst, .gt),
536 .cmp_neq => try self.airCmp(inst, .neq),
537
538 .bool_and => try self.airBoolOp(inst),
539 .bool_or => try self.airBoolOp(inst),
540 .bit_and => try self.airBitAnd(inst),
541 .bit_or => try self.airBitOr(inst),
542 .xor => try self.airXor(inst),
543 .shr => try self.airShr(inst),
544
545 .alloc => try self.airAlloc(inst),
546 .ret_ptr => try self.airRetPtr(inst),
547 .arg => try self.airArg(inst),
548 .assembly => try self.airAsm(inst),
549 .bitcast => try self.airBitCast(inst),
550 .block => try self.airBlock(inst),
551 .br => try self.airBr(inst),
552 .breakpoint => try self.airBreakpoint(),
553 .ret_addr => try self.airRetAddr(),
554 .fence => try self.airFence(),
555 .call => try self.airCall(inst),
556 .cond_br => try self.airCondBr(inst),
557 .dbg_stmt => try self.airDbgStmt(inst),
558 .fptrunc => try self.airFptrunc(inst),
559 .fpext => try self.airFpext(inst),
560 .intcast => try self.airIntCast(inst),
561 .trunc => try self.airTrunc(inst),
562 .bool_to_int => try self.airBoolToInt(inst),
563 .is_non_null => try self.airIsNonNull(inst),
564 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
565 .is_null => try self.airIsNull(inst),
566 .is_null_ptr => try self.airIsNullPtr(inst),
567 .is_non_err => try self.airIsNonErr(inst),
568 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
569 .is_err => try self.airIsErr(inst),
570 .is_err_ptr => try self.airIsErrPtr(inst),
571 .load => try self.airLoad(inst),
572 .loop => try self.airLoop(inst),
573 .not => try self.airNot(inst),
574 .ptrtoint => try self.airPtrToInt(inst),
575 .ret => try self.airRet(inst),
576 .ret_load => try self.airRetLoad(inst),
577 .store => try self.airStore(inst),
578 .struct_field_ptr=> try self.airStructFieldPtr(inst),
579 .struct_field_val=> try self.airStructFieldVal(inst),
580 .array_to_slice => try self.airArrayToSlice(inst),
581 .int_to_float => try self.airIntToFloat(inst),
582 .float_to_int => try self.airFloatToInt(inst),
583 .cmpxchg_strong => try self.airCmpxchg(inst),
584 .cmpxchg_weak => try self.airCmpxchg(inst),
585 .atomic_rmw => try self.airAtomicRmw(inst),
586 .atomic_load => try self.airAtomicLoad(inst),
587 .memcpy => try self.airMemcpy(inst),
588 .memset => try self.airMemset(inst),
589 .set_union_tag => try self.airSetUnionTag(inst),
590 .get_union_tag => try self.airGetUnionTag(inst),
591 .clz => try self.airClz(inst),
592 .ctz => try self.airCtz(inst),
593 .popcount => try self.airPopcount(inst),
594 .tag_name => try self.airTagName(inst),
595
596 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
597 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
598 .atomic_store_release => try self.airAtomicStore(inst, .Release),
599 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
600
601 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
602 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
603 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
604 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
605
606 .switch_br => try self.airSwitch(inst),
607 .slice_ptr => try self.airSlicePtr(inst),
608 .slice_len => try self.airSliceLen(inst),
609
610 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
611 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
612
613 .array_elem_val => try self.airArrayElemVal(inst),
614 .slice_elem_val => try self.airSliceElemVal(inst),
615 .slice_elem_ptr => try self.airSliceElemPtr(inst),
616 .ptr_elem_val => try self.airPtrElemVal(inst),
617 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
618
619 .constant => unreachable, // excluded from function bodies
620 .const_ty => unreachable, // excluded from function bodies
621 .unreach => self.finishAirBookkeeping(),
622
623 .optional_payload => try self.airOptionalPayload(inst),
624 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
625 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
626 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
627 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
628 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
629 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
630
631 .wrap_optional => try self.airWrapOptional(inst),
632 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
633 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
634 // zig fmt: on
634635 }
635636 if (std.debug.runtime_safety) {
636637 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
......@@ -2546,6 +2547,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
25462547 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
25472548}
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
25492560fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
25502561 // First section of indexes correspond to a set number of constant values.
25512562 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 {
502502
503503 switch (air_tags[inst]) {
504504 // zig fmt: off
505 .add, .ptr_add => try self.airAdd(inst),
506 .addwrap => try self.airAddWrap(inst),
507 .add_sat => try self.airAddSat(inst),
508 .sub, .ptr_sub => try self.airSub(inst),
509 .subwrap => try self.airSubWrap(inst),
510 .sub_sat => try self.airSubSat(inst),
511 .mul => try self.airMul(inst),
512 .mulwrap => try self.airMulWrap(inst),
513 .mul_sat => try self.airMulSat(inst),
514 .rem => try self.airRem(inst),
515 .mod => try self.airMod(inst),
516 .shl, .shl_exact => try self.airShl(inst),
517 .shl_sat => try self.airShlSat(inst),
518 .min => try self.airMin(inst),
519 .max => try self.airMax(inst),
520 .slice => try self.airSlice(inst),
521
522 .add_with_overflow => try self.airAddWithOverflow(inst),
523 .sub_with_overflow => try self.airSubWithOverflow(inst),
524 .mul_with_overflow => try self.airMulWithOverflow(inst),
525 .shl_with_overflow => try self.airShlWithOverflow(inst),
526
527 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
528
529 .cmp_lt => try self.airCmp(inst, .lt),
530 .cmp_lte => try self.airCmp(inst, .lte),
531 .cmp_eq => try self.airCmp(inst, .eq),
532 .cmp_gte => try self.airCmp(inst, .gte),
533 .cmp_gt => try self.airCmp(inst, .gt),
534 .cmp_neq => try self.airCmp(inst, .neq),
535
536 .bool_and => try self.airBoolOp(inst),
537 .bool_or => try self.airBoolOp(inst),
538 .bit_and => try self.airBitAnd(inst),
539 .bit_or => try self.airBitOr(inst),
540 .xor => try self.airXor(inst),
541 .shr => try self.airShr(inst),
542
543 .alloc => try self.airAlloc(inst),
544 .ret_ptr => try self.airRetPtr(inst),
545 .arg => try self.airArg(inst),
546 .assembly => try self.airAsm(inst),
547 .bitcast => try self.airBitCast(inst),
548 .block => try self.airBlock(inst),
549 .br => try self.airBr(inst),
550 .breakpoint => try self.airBreakpoint(),
551 .ret_addr => try self.airRetAddr(),
552 .fence => try self.airFence(),
553 .call => try self.airCall(inst),
554 .cond_br => try self.airCondBr(inst),
555 .dbg_stmt => try self.airDbgStmt(inst),
556 .fptrunc => try self.airFptrunc(inst),
557 .fpext => try self.airFpext(inst),
558 .intcast => try self.airIntCast(inst),
559 .trunc => try self.airTrunc(inst),
560 .bool_to_int => try self.airBoolToInt(inst),
561 .is_non_null => try self.airIsNonNull(inst),
562 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
563 .is_null => try self.airIsNull(inst),
564 .is_null_ptr => try self.airIsNullPtr(inst),
565 .is_non_err => try self.airIsNonErr(inst),
566 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
567 .is_err => try self.airIsErr(inst),
568 .is_err_ptr => try self.airIsErrPtr(inst),
569 .load => try self.airLoad(inst),
570 .loop => try self.airLoop(inst),
571 .not => try self.airNot(inst),
572 .ptrtoint => try self.airPtrToInt(inst),
573 .ret => try self.airRet(inst),
574 .ret_load => try self.airRetLoad(inst),
575 .store => try self.airStore(inst),
576 .struct_field_ptr=> try self.airStructFieldPtr(inst),
577 .struct_field_val=> try self.airStructFieldVal(inst),
578 .array_to_slice => try self.airArrayToSlice(inst),
579 .int_to_float => try self.airIntToFloat(inst),
580 .float_to_int => try self.airFloatToInt(inst),
581 .cmpxchg_strong => try self.airCmpxchg(inst),
582 .cmpxchg_weak => try self.airCmpxchg(inst),
583 .atomic_rmw => try self.airAtomicRmw(inst),
584 .atomic_load => try self.airAtomicLoad(inst),
585 .memcpy => try self.airMemcpy(inst),
586 .memset => try self.airMemset(inst),
587 .set_union_tag => try self.airSetUnionTag(inst),
588 .get_union_tag => try self.airGetUnionTag(inst),
589 .clz => try self.airClz(inst),
590 .ctz => try self.airCtz(inst),
591 .popcount => try self.airPopcount(inst),
592
593 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
594 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
595 .atomic_store_release => try self.airAtomicStore(inst, .Release),
596 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
597
598 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
599 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
600 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
601 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
602
603 .switch_br => try self.airSwitch(inst),
604 .slice_ptr => try self.airSlicePtr(inst),
605 .slice_len => try self.airSliceLen(inst),
606
607 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
608 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
609
610 .array_elem_val => try self.airArrayElemVal(inst),
611 .slice_elem_val => try self.airSliceElemVal(inst),
612 .slice_elem_ptr => try self.airSliceElemPtr(inst),
613 .ptr_elem_val => try self.airPtrElemVal(inst),
614 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
615
616 .constant => unreachable, // excluded from function bodies
617 .const_ty => unreachable, // excluded from function bodies
618 .unreach => self.finishAirBookkeeping(),
619
620 .optional_payload => try self.airOptionalPayload(inst),
621 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
622 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
623 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
624 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
625 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
626 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
627
628 .wrap_optional => try self.airWrapOptional(inst),
629 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
630 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
631 // zig fmt: on
505 .add, .ptr_add => try self.airAdd(inst),
506 .addwrap => try self.airAddWrap(inst),
507 .add_sat => try self.airAddSat(inst),
508 .sub, .ptr_sub => try self.airSub(inst),
509 .subwrap => try self.airSubWrap(inst),
510 .sub_sat => try self.airSubSat(inst),
511 .mul => try self.airMul(inst),
512 .mulwrap => try self.airMulWrap(inst),
513 .mul_sat => try self.airMulSat(inst),
514 .rem => try self.airRem(inst),
515 .mod => try self.airMod(inst),
516 .shl, .shl_exact => try self.airShl(inst),
517 .shl_sat => try self.airShlSat(inst),
518 .min => try self.airMin(inst),
519 .max => try self.airMax(inst),
520 .slice => try self.airSlice(inst),
521
522 .add_with_overflow => try self.airAddWithOverflow(inst),
523 .sub_with_overflow => try self.airSubWithOverflow(inst),
524 .mul_with_overflow => try self.airMulWithOverflow(inst),
525 .shl_with_overflow => try self.airShlWithOverflow(inst),
526
527 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
528
529 .cmp_lt => try self.airCmp(inst, .lt),
530 .cmp_lte => try self.airCmp(inst, .lte),
531 .cmp_eq => try self.airCmp(inst, .eq),
532 .cmp_gte => try self.airCmp(inst, .gte),
533 .cmp_gt => try self.airCmp(inst, .gt),
534 .cmp_neq => try self.airCmp(inst, .neq),
535
536 .bool_and => try self.airBoolOp(inst),
537 .bool_or => try self.airBoolOp(inst),
538 .bit_and => try self.airBitAnd(inst),
539 .bit_or => try self.airBitOr(inst),
540 .xor => try self.airXor(inst),
541 .shr => try self.airShr(inst),
542
543 .alloc => try self.airAlloc(inst),
544 .ret_ptr => try self.airRetPtr(inst),
545 .arg => try self.airArg(inst),
546 .assembly => try self.airAsm(inst),
547 .bitcast => try self.airBitCast(inst),
548 .block => try self.airBlock(inst),
549 .br => try self.airBr(inst),
550 .breakpoint => try self.airBreakpoint(),
551 .ret_addr => try self.airRetAddr(),
552 .fence => try self.airFence(),
553 .call => try self.airCall(inst),
554 .cond_br => try self.airCondBr(inst),
555 .dbg_stmt => try self.airDbgStmt(inst),
556 .fptrunc => try self.airFptrunc(inst),
557 .fpext => try self.airFpext(inst),
558 .intcast => try self.airIntCast(inst),
559 .trunc => try self.airTrunc(inst),
560 .bool_to_int => try self.airBoolToInt(inst),
561 .is_non_null => try self.airIsNonNull(inst),
562 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
563 .is_null => try self.airIsNull(inst),
564 .is_null_ptr => try self.airIsNullPtr(inst),
565 .is_non_err => try self.airIsNonErr(inst),
566 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
567 .is_err => try self.airIsErr(inst),
568 .is_err_ptr => try self.airIsErrPtr(inst),
569 .load => try self.airLoad(inst),
570 .loop => try self.airLoop(inst),
571 .not => try self.airNot(inst),
572 .ptrtoint => try self.airPtrToInt(inst),
573 .ret => try self.airRet(inst),
574 .ret_load => try self.airRetLoad(inst),
575 .store => try self.airStore(inst),
576 .struct_field_ptr=> try self.airStructFieldPtr(inst),
577 .struct_field_val=> try self.airStructFieldVal(inst),
578 .array_to_slice => try self.airArrayToSlice(inst),
579 .int_to_float => try self.airIntToFloat(inst),
580 .float_to_int => try self.airFloatToInt(inst),
581 .cmpxchg_strong => try self.airCmpxchg(inst),
582 .cmpxchg_weak => try self.airCmpxchg(inst),
583 .atomic_rmw => try self.airAtomicRmw(inst),
584 .atomic_load => try self.airAtomicLoad(inst),
585 .memcpy => try self.airMemcpy(inst),
586 .memset => try self.airMemset(inst),
587 .set_union_tag => try self.airSetUnionTag(inst),
588 .get_union_tag => try self.airGetUnionTag(inst),
589 .clz => try self.airClz(inst),
590 .ctz => try self.airCtz(inst),
591 .popcount => try self.airPopcount(inst),
592 .tag_name => try self.airTagName(inst),
593
594 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
595 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
596 .atomic_store_release => try self.airAtomicStore(inst, .Release),
597 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
598
599 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
600 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
601 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
602 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
603
604 .switch_br => try self.airSwitch(inst),
605 .slice_ptr => try self.airSlicePtr(inst),
606 .slice_len => try self.airSliceLen(inst),
607
608 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
609 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
610
611 .array_elem_val => try self.airArrayElemVal(inst),
612 .slice_elem_val => try self.airSliceElemVal(inst),
613 .slice_elem_ptr => try self.airSliceElemPtr(inst),
614 .ptr_elem_val => try self.airPtrElemVal(inst),
615 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
616
617 .constant => unreachable, // excluded from function bodies
618 .const_ty => unreachable, // excluded from function bodies
619 .unreach => self.finishAirBookkeeping(),
620
621 .optional_payload => try self.airOptionalPayload(inst),
622 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
623 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
624 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
625 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
626 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
627 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
628
629 .wrap_optional => try self.airWrapOptional(inst),
630 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
631 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
632 // zig fmt: on
632633 }
633634 if (std.debug.runtime_safety) {
634635 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
......@@ -3301,6 +3302,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
33013302 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
33023303}
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
33043315fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
33053316 // First section of indexes correspond to a set number of constant values.
33063317 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 {
483483
484484 switch (air_tags[inst]) {
485485 // zig fmt: off
486 .add, .ptr_add => try self.airAdd(inst),
487 .addwrap => try self.airAddWrap(inst),
488 .add_sat => try self.airAddSat(inst),
489 .sub, .ptr_sub => try self.airSub(inst),
490 .subwrap => try self.airSubWrap(inst),
491 .sub_sat => try self.airSubSat(inst),
492 .mul => try self.airMul(inst),
493 .mulwrap => try self.airMulWrap(inst),
494 .mul_sat => try self.airMulSat(inst),
495 .rem => try self.airRem(inst),
496 .mod => try self.airMod(inst),
497 .shl, .shl_exact => try self.airShl(inst),
498 .shl_sat => try self.airShlSat(inst),
499 .min => try self.airMin(inst),
500 .max => try self.airMax(inst),
501 .slice => try self.airSlice(inst),
502
503 .add_with_overflow => try self.airAddWithOverflow(inst),
504 .sub_with_overflow => try self.airSubWithOverflow(inst),
505 .mul_with_overflow => try self.airMulWithOverflow(inst),
506 .shl_with_overflow => try self.airShlWithOverflow(inst),
507
508 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
509
510 .cmp_lt => try self.airCmp(inst, .lt),
511 .cmp_lte => try self.airCmp(inst, .lte),
512 .cmp_eq => try self.airCmp(inst, .eq),
513 .cmp_gte => try self.airCmp(inst, .gte),
514 .cmp_gt => try self.airCmp(inst, .gt),
515 .cmp_neq => try self.airCmp(inst, .neq),
516
517 .bool_and => try self.airBoolOp(inst),
518 .bool_or => try self.airBoolOp(inst),
519 .bit_and => try self.airBitAnd(inst),
520 .bit_or => try self.airBitOr(inst),
521 .xor => try self.airXor(inst),
522 .shr => try self.airShr(inst),
523
524 .alloc => try self.airAlloc(inst),
525 .ret_ptr => try self.airRetPtr(inst),
526 .arg => try self.airArg(inst),
527 .assembly => try self.airAsm(inst),
528 .bitcast => try self.airBitCast(inst),
529 .block => try self.airBlock(inst),
530 .br => try self.airBr(inst),
531 .breakpoint => try self.airBreakpoint(),
532 .ret_addr => try self.airRetAddr(),
533 .fence => try self.airFence(),
534 .call => try self.airCall(inst),
535 .cond_br => try self.airCondBr(inst),
536 .dbg_stmt => try self.airDbgStmt(inst),
537 .fptrunc => try self.airFptrunc(inst),
538 .fpext => try self.airFpext(inst),
539 .intcast => try self.airIntCast(inst),
540 .trunc => try self.airTrunc(inst),
541 .bool_to_int => try self.airBoolToInt(inst),
542 .is_non_null => try self.airIsNonNull(inst),
543 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
544 .is_null => try self.airIsNull(inst),
545 .is_null_ptr => try self.airIsNullPtr(inst),
546 .is_non_err => try self.airIsNonErr(inst),
547 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
548 .is_err => try self.airIsErr(inst),
549 .is_err_ptr => try self.airIsErrPtr(inst),
550 .load => try self.airLoad(inst),
551 .loop => try self.airLoop(inst),
552 .not => try self.airNot(inst),
553 .ptrtoint => try self.airPtrToInt(inst),
554 .ret => try self.airRet(inst),
555 .ret_load => try self.airRetLoad(inst),
556 .store => try self.airStore(inst),
557 .struct_field_ptr=> try self.airStructFieldPtr(inst),
558 .struct_field_val=> try self.airStructFieldVal(inst),
559 .array_to_slice => try self.airArrayToSlice(inst),
560 .int_to_float => try self.airIntToFloat(inst),
561 .float_to_int => try self.airFloatToInt(inst),
562 .cmpxchg_strong => try self.airCmpxchg(inst),
563 .cmpxchg_weak => try self.airCmpxchg(inst),
564 .atomic_rmw => try self.airAtomicRmw(inst),
565 .atomic_load => try self.airAtomicLoad(inst),
566 .memcpy => try self.airMemcpy(inst),
567 .memset => try self.airMemset(inst),
568 .set_union_tag => try self.airSetUnionTag(inst),
569 .get_union_tag => try self.airGetUnionTag(inst),
570 .clz => try self.airClz(inst),
571 .ctz => try self.airCtz(inst),
572 .popcount => try self.airPopcount(inst),
573
574 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
575 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
576 .atomic_store_release => try self.airAtomicStore(inst, .Release),
577 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
578
579 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
580 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
581 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
582 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
583
584 .switch_br => try self.airSwitch(inst),
585 .slice_ptr => try self.airSlicePtr(inst),
586 .slice_len => try self.airSliceLen(inst),
587
588 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
589 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
590
591 .array_elem_val => try self.airArrayElemVal(inst),
592 .slice_elem_val => try self.airSliceElemVal(inst),
593 .slice_elem_ptr => try self.airSliceElemPtr(inst),
594 .ptr_elem_val => try self.airPtrElemVal(inst),
595 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
596
597 .constant => unreachable, // excluded from function bodies
598 .const_ty => unreachable, // excluded from function bodies
599 .unreach => self.finishAirBookkeeping(),
600
601 .optional_payload => try self.airOptionalPayload(inst),
602 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
603 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
604 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
605 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
606 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
607 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
608
609 .wrap_optional => try self.airWrapOptional(inst),
610 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
611 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
612 // zig fmt: on
486 .add, .ptr_add => try self.airAdd(inst),
487 .addwrap => try self.airAddWrap(inst),
488 .add_sat => try self.airAddSat(inst),
489 .sub, .ptr_sub => try self.airSub(inst),
490 .subwrap => try self.airSubWrap(inst),
491 .sub_sat => try self.airSubSat(inst),
492 .mul => try self.airMul(inst),
493 .mulwrap => try self.airMulWrap(inst),
494 .mul_sat => try self.airMulSat(inst),
495 .rem => try self.airRem(inst),
496 .mod => try self.airMod(inst),
497 .shl, .shl_exact => try self.airShl(inst),
498 .shl_sat => try self.airShlSat(inst),
499 .min => try self.airMin(inst),
500 .max => try self.airMax(inst),
501 .slice => try self.airSlice(inst),
502
503 .add_with_overflow => try self.airAddWithOverflow(inst),
504 .sub_with_overflow => try self.airSubWithOverflow(inst),
505 .mul_with_overflow => try self.airMulWithOverflow(inst),
506 .shl_with_overflow => try self.airShlWithOverflow(inst),
507
508 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
509
510 .cmp_lt => try self.airCmp(inst, .lt),
511 .cmp_lte => try self.airCmp(inst, .lte),
512 .cmp_eq => try self.airCmp(inst, .eq),
513 .cmp_gte => try self.airCmp(inst, .gte),
514 .cmp_gt => try self.airCmp(inst, .gt),
515 .cmp_neq => try self.airCmp(inst, .neq),
516
517 .bool_and => try self.airBoolOp(inst),
518 .bool_or => try self.airBoolOp(inst),
519 .bit_and => try self.airBitAnd(inst),
520 .bit_or => try self.airBitOr(inst),
521 .xor => try self.airXor(inst),
522 .shr => try self.airShr(inst),
523
524 .alloc => try self.airAlloc(inst),
525 .ret_ptr => try self.airRetPtr(inst),
526 .arg => try self.airArg(inst),
527 .assembly => try self.airAsm(inst),
528 .bitcast => try self.airBitCast(inst),
529 .block => try self.airBlock(inst),
530 .br => try self.airBr(inst),
531 .breakpoint => try self.airBreakpoint(),
532 .ret_addr => try self.airRetAddr(),
533 .fence => try self.airFence(),
534 .call => try self.airCall(inst),
535 .cond_br => try self.airCondBr(inst),
536 .dbg_stmt => try self.airDbgStmt(inst),
537 .fptrunc => try self.airFptrunc(inst),
538 .fpext => try self.airFpext(inst),
539 .intcast => try self.airIntCast(inst),
540 .trunc => try self.airTrunc(inst),
541 .bool_to_int => try self.airBoolToInt(inst),
542 .is_non_null => try self.airIsNonNull(inst),
543 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
544 .is_null => try self.airIsNull(inst),
545 .is_null_ptr => try self.airIsNullPtr(inst),
546 .is_non_err => try self.airIsNonErr(inst),
547 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
548 .is_err => try self.airIsErr(inst),
549 .is_err_ptr => try self.airIsErrPtr(inst),
550 .load => try self.airLoad(inst),
551 .loop => try self.airLoop(inst),
552 .not => try self.airNot(inst),
553 .ptrtoint => try self.airPtrToInt(inst),
554 .ret => try self.airRet(inst),
555 .ret_load => try self.airRetLoad(inst),
556 .store => try self.airStore(inst),
557 .struct_field_ptr=> try self.airStructFieldPtr(inst),
558 .struct_field_val=> try self.airStructFieldVal(inst),
559 .array_to_slice => try self.airArrayToSlice(inst),
560 .int_to_float => try self.airIntToFloat(inst),
561 .float_to_int => try self.airFloatToInt(inst),
562 .cmpxchg_strong => try self.airCmpxchg(inst),
563 .cmpxchg_weak => try self.airCmpxchg(inst),
564 .atomic_rmw => try self.airAtomicRmw(inst),
565 .atomic_load => try self.airAtomicLoad(inst),
566 .memcpy => try self.airMemcpy(inst),
567 .memset => try self.airMemset(inst),
568 .set_union_tag => try self.airSetUnionTag(inst),
569 .get_union_tag => try self.airGetUnionTag(inst),
570 .clz => try self.airClz(inst),
571 .ctz => try self.airCtz(inst),
572 .popcount => try self.airPopcount(inst),
573 .tag_name => try self.airTagName(inst),
574
575 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
576 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
577 .atomic_store_release => try self.airAtomicStore(inst, .Release),
578 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
579
580 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
581 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
582 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
583 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
584
585 .switch_br => try self.airSwitch(inst),
586 .slice_ptr => try self.airSlicePtr(inst),
587 .slice_len => try self.airSliceLen(inst),
588
589 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
590 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
591
592 .array_elem_val => try self.airArrayElemVal(inst),
593 .slice_elem_val => try self.airSliceElemVal(inst),
594 .slice_elem_ptr => try self.airSliceElemPtr(inst),
595 .ptr_elem_val => try self.airPtrElemVal(inst),
596 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
597
598 .constant => unreachable, // excluded from function bodies
599 .const_ty => unreachable, // excluded from function bodies
600 .unreach => self.finishAirBookkeeping(),
601
602 .optional_payload => try self.airOptionalPayload(inst),
603 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
604 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
605 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
606 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
607 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
608 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
609
610 .wrap_optional => try self.airWrapOptional(inst),
611 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
612 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
613 // zig fmt: on
613614 }
614615 if (std.debug.runtime_safety) {
615616 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
......@@ -2045,6 +2046,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
20452046 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
20462047}
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
20482059fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
20492060 // First section of indexes correspond to a set number of constant values.
20502061 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 {
538538
539539 switch (air_tags[inst]) {
540540 // zig fmt: off
541 .add, .ptr_add => try self.airAdd(inst),
542 .addwrap => try self.airAddWrap(inst),
543 .add_sat => try self.airAddSat(inst),
544 .sub, .ptr_sub => try self.airSub(inst),
545 .subwrap => try self.airSubWrap(inst),
546 .sub_sat => try self.airSubSat(inst),
547 .mul => try self.airMul(inst),
548 .mulwrap => try self.airMulWrap(inst),
549 .mul_sat => try self.airMulSat(inst),
550 .rem => try self.airRem(inst),
551 .mod => try self.airMod(inst),
552 .shl, .shl_exact => try self.airShl(inst),
553 .shl_sat => try self.airShlSat(inst),
554 .min => try self.airMin(inst),
555 .max => try self.airMax(inst),
556 .slice => try self.airSlice(inst),
557
558 .add_with_overflow => try self.airAddWithOverflow(inst),
559 .sub_with_overflow => try self.airSubWithOverflow(inst),
560 .mul_with_overflow => try self.airMulWithOverflow(inst),
561 .shl_with_overflow => try self.airShlWithOverflow(inst),
562
563 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
564
565 .cmp_lt => try self.airCmp(inst, .lt),
566 .cmp_lte => try self.airCmp(inst, .lte),
567 .cmp_eq => try self.airCmp(inst, .eq),
568 .cmp_gte => try self.airCmp(inst, .gte),
569 .cmp_gt => try self.airCmp(inst, .gt),
570 .cmp_neq => try self.airCmp(inst, .neq),
571
572 .bool_and => try self.airBoolOp(inst),
573 .bool_or => try self.airBoolOp(inst),
574 .bit_and => try self.airBitAnd(inst),
575 .bit_or => try self.airBitOr(inst),
576 .xor => try self.airXor(inst),
577 .shr => try self.airShr(inst),
578
579 .alloc => try self.airAlloc(inst),
580 .ret_ptr => try self.airRetPtr(inst),
581 .arg => try self.airArg(inst),
582 .assembly => try self.airAsm(inst),
583 .bitcast => try self.airBitCast(inst),
584 .block => try self.airBlock(inst),
585 .br => try self.airBr(inst),
586 .breakpoint => try self.airBreakpoint(),
587 .ret_addr => try self.airRetAddr(),
588 .fence => try self.airFence(),
589 .call => try self.airCall(inst),
590 .cond_br => try self.airCondBr(inst),
591 .dbg_stmt => try self.airDbgStmt(inst),
592 .fptrunc => try self.airFptrunc(inst),
593 .fpext => try self.airFpext(inst),
594 .intcast => try self.airIntCast(inst),
595 .trunc => try self.airTrunc(inst),
596 .bool_to_int => try self.airBoolToInt(inst),
597 .is_non_null => try self.airIsNonNull(inst),
598 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
599 .is_null => try self.airIsNull(inst),
600 .is_null_ptr => try self.airIsNullPtr(inst),
601 .is_non_err => try self.airIsNonErr(inst),
602 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
603 .is_err => try self.airIsErr(inst),
604 .is_err_ptr => try self.airIsErrPtr(inst),
605 .load => try self.airLoad(inst),
606 .loop => try self.airLoop(inst),
607 .not => try self.airNot(inst),
608 .ptrtoint => try self.airPtrToInt(inst),
609 .ret => try self.airRet(inst),
610 .ret_load => try self.airRetLoad(inst),
611 .store => try self.airStore(inst),
612 .struct_field_ptr=> try self.airStructFieldPtr(inst),
613 .struct_field_val=> try self.airStructFieldVal(inst),
614 .array_to_slice => try self.airArrayToSlice(inst),
615 .int_to_float => try self.airIntToFloat(inst),
616 .float_to_int => try self.airFloatToInt(inst),
617 .cmpxchg_strong => try self.airCmpxchg(inst),
618 .cmpxchg_weak => try self.airCmpxchg(inst),
619 .atomic_rmw => try self.airAtomicRmw(inst),
620 .atomic_load => try self.airAtomicLoad(inst),
621 .memcpy => try self.airMemcpy(inst),
622 .memset => try self.airMemset(inst),
623 .set_union_tag => try self.airSetUnionTag(inst),
624 .get_union_tag => try self.airGetUnionTag(inst),
625 .clz => try self.airClz(inst),
626 .ctz => try self.airCtz(inst),
627 .popcount => try self.airPopcount(inst),
628
629 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
630 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
631 .atomic_store_release => try self.airAtomicStore(inst, .Release),
632 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
633
634 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
635 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
636 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
637 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
638
639 .switch_br => try self.airSwitch(inst),
640 .slice_ptr => try self.airSlicePtr(inst),
641 .slice_len => try self.airSliceLen(inst),
642
643 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
644 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
645
646 .array_elem_val => try self.airArrayElemVal(inst),
647 .slice_elem_val => try self.airSliceElemVal(inst),
648 .slice_elem_ptr => try self.airSliceElemPtr(inst),
649 .ptr_elem_val => try self.airPtrElemVal(inst),
650 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
651
652 .constant => unreachable, // excluded from function bodies
653 .const_ty => unreachable, // excluded from function bodies
654 .unreach => self.finishAirBookkeeping(),
655
656 .optional_payload => try self.airOptionalPayload(inst),
657 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
658 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
659 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
660 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
661 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
662 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
663
664 .wrap_optional => try self.airWrapOptional(inst),
665 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
666 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
667 // zig fmt: on
541 .add, .ptr_add => try self.airAdd(inst),
542 .addwrap => try self.airAddWrap(inst),
543 .add_sat => try self.airAddSat(inst),
544 .sub, .ptr_sub => try self.airSub(inst),
545 .subwrap => try self.airSubWrap(inst),
546 .sub_sat => try self.airSubSat(inst),
547 .mul => try self.airMul(inst),
548 .mulwrap => try self.airMulWrap(inst),
549 .mul_sat => try self.airMulSat(inst),
550 .rem => try self.airRem(inst),
551 .mod => try self.airMod(inst),
552 .shl, .shl_exact => try self.airShl(inst),
553 .shl_sat => try self.airShlSat(inst),
554 .min => try self.airMin(inst),
555 .max => try self.airMax(inst),
556 .slice => try self.airSlice(inst),
557
558 .add_with_overflow => try self.airAddWithOverflow(inst),
559 .sub_with_overflow => try self.airSubWithOverflow(inst),
560 .mul_with_overflow => try self.airMulWithOverflow(inst),
561 .shl_with_overflow => try self.airShlWithOverflow(inst),
562
563 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
564
565 .cmp_lt => try self.airCmp(inst, .lt),
566 .cmp_lte => try self.airCmp(inst, .lte),
567 .cmp_eq => try self.airCmp(inst, .eq),
568 .cmp_gte => try self.airCmp(inst, .gte),
569 .cmp_gt => try self.airCmp(inst, .gt),
570 .cmp_neq => try self.airCmp(inst, .neq),
571
572 .bool_and => try self.airBoolOp(inst),
573 .bool_or => try self.airBoolOp(inst),
574 .bit_and => try self.airBitAnd(inst),
575 .bit_or => try self.airBitOr(inst),
576 .xor => try self.airXor(inst),
577 .shr => try self.airShr(inst),
578
579 .alloc => try self.airAlloc(inst),
580 .ret_ptr => try self.airRetPtr(inst),
581 .arg => try self.airArg(inst),
582 .assembly => try self.airAsm(inst),
583 .bitcast => try self.airBitCast(inst),
584 .block => try self.airBlock(inst),
585 .br => try self.airBr(inst),
586 .breakpoint => try self.airBreakpoint(),
587 .ret_addr => try self.airRetAddr(),
588 .fence => try self.airFence(),
589 .call => try self.airCall(inst),
590 .cond_br => try self.airCondBr(inst),
591 .dbg_stmt => try self.airDbgStmt(inst),
592 .fptrunc => try self.airFptrunc(inst),
593 .fpext => try self.airFpext(inst),
594 .intcast => try self.airIntCast(inst),
595 .trunc => try self.airTrunc(inst),
596 .bool_to_int => try self.airBoolToInt(inst),
597 .is_non_null => try self.airIsNonNull(inst),
598 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
599 .is_null => try self.airIsNull(inst),
600 .is_null_ptr => try self.airIsNullPtr(inst),
601 .is_non_err => try self.airIsNonErr(inst),
602 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
603 .is_err => try self.airIsErr(inst),
604 .is_err_ptr => try self.airIsErrPtr(inst),
605 .load => try self.airLoad(inst),
606 .loop => try self.airLoop(inst),
607 .not => try self.airNot(inst),
608 .ptrtoint => try self.airPtrToInt(inst),
609 .ret => try self.airRet(inst),
610 .ret_load => try self.airRetLoad(inst),
611 .store => try self.airStore(inst),
612 .struct_field_ptr=> try self.airStructFieldPtr(inst),
613 .struct_field_val=> try self.airStructFieldVal(inst),
614 .array_to_slice => try self.airArrayToSlice(inst),
615 .int_to_float => try self.airIntToFloat(inst),
616 .float_to_int => try self.airFloatToInt(inst),
617 .cmpxchg_strong => try self.airCmpxchg(inst),
618 .cmpxchg_weak => try self.airCmpxchg(inst),
619 .atomic_rmw => try self.airAtomicRmw(inst),
620 .atomic_load => try self.airAtomicLoad(inst),
621 .memcpy => try self.airMemcpy(inst),
622 .memset => try self.airMemset(inst),
623 .set_union_tag => try self.airSetUnionTag(inst),
624 .get_union_tag => try self.airGetUnionTag(inst),
625 .clz => try self.airClz(inst),
626 .ctz => try self.airCtz(inst),
627 .popcount => try self.airPopcount(inst),
628 .tag_name => try self.airTagName(inst),
629
630 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
631 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
632 .atomic_store_release => try self.airAtomicStore(inst, .Release),
633 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SeqCst),
634
635 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
636 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
637 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
638 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
639
640 .switch_br => try self.airSwitch(inst),
641 .slice_ptr => try self.airSlicePtr(inst),
642 .slice_len => try self.airSliceLen(inst),
643
644 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
645 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
646
647 .array_elem_val => try self.airArrayElemVal(inst),
648 .slice_elem_val => try self.airSliceElemVal(inst),
649 .slice_elem_ptr => try self.airSliceElemPtr(inst),
650 .ptr_elem_val => try self.airPtrElemVal(inst),
651 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
652
653 .constant => unreachable, // excluded from function bodies
654 .const_ty => unreachable, // excluded from function bodies
655 .unreach => self.finishAirBookkeeping(),
656
657 .optional_payload => try self.airOptionalPayload(inst),
658 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
659 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
660 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
661 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
662 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
663 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
664
665 .wrap_optional => try self.airWrapOptional(inst),
666 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
667 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
668 // zig fmt: on
668669 }
669670 if (std.debug.runtime_safety) {
670671 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
......@@ -3174,6 +3175,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
31743175 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
31753176}
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
31773188fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
31783189 // First section of indexes correspond to a set number of constant values.
31793190 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
12301230 .clz => try airBuiltinCall(f, inst, "clz"),
12311231 .ctz => try airBuiltinCall(f, inst, "ctz"),
12321232 .popcount => try airBuiltinCall(f, inst, "popcount"),
1233 .tag_name => try airTagName(f, inst),
12331234
12341235 .int_to_float,
12351236 .float_to_int,
......@@ -2914,6 +2915,24 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
29142915 return local;
29152916}
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
29172936fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
29182937 return switch (order) {
29192938 .Unordered => "memory_order_relaxed",
src/codegen/llvm.zig+132-14
......@@ -636,15 +636,6 @@ pub const DeclGen = struct {
636636 llvm_param_i += 1;
637637 }
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
648639 // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`.
649640 if (fn_info.cc == .Naked) {
650641 dg.addFnAttr(llvm_fn, "naked");
......@@ -653,6 +644,16 @@ pub const DeclGen = struct {
653644 }
654645
655646 // 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 {
656657 if (!dg.module.comp.bin_file.options.red_zone) {
657658 dg.addFnAttr(llvm_fn, "noredzone");
658659 }
......@@ -665,6 +666,14 @@ pub const DeclGen = struct {
665666 if (dg.module.comp.unwind_tables) {
666667 dg.addFnAttr(llvm_fn, "uwtable");
667668 }
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 }
668677 if (dg.module.comp.bin_file.options.optimize_mode == .ReleaseSmall) {
669678 dg.addFnAttr(llvm_fn, "minsize");
670679 dg.addFnAttr(llvm_fn, "optsize");
......@@ -673,11 +682,6 @@ pub const DeclGen = struct {
673682 dg.addFnAttr(llvm_fn, "sanitize_thread");
674683 }
675684 // 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;
681685 }
682686
683687 fn resolveGlobalDecl(dg: *DeclGen, decl: *Module.Decl) Error!*const llvm.Value {
......@@ -1958,6 +1962,7 @@ pub const FuncGen = struct {
19581962 .clz => try self.airClzCtz(inst, "ctlz"),
19591963 .ctz => try self.airClzCtz(inst, "cttz"),
19601964 .popcount => try self.airPopCount(inst, "ctpop"),
1965 .tag_name => try self.airTagName(inst),
19611966
19621967 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
19631968 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -4093,6 +4098,119 @@ pub const FuncGen = struct {
40934098 }
40944099 }
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
40964214 /// Assumes the optional is not pointer-like and payload has bits.
40974215 fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value {
40984216 if (is_by_ref) {
src/codegen/llvm/bindings.zig+15
......@@ -785,8 +785,23 @@ pub const Builder = opaque {
785785
786786 pub const buildExactSDiv = LLVMBuildExactSDiv;
787787 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;
788800};
789801
802pub const DIScope = opaque {};
803pub const Metadata = opaque {};
804
790805pub const IntPredicate = enum(c_uint) {
791806 EQ = 32,
792807 NE = 33,
src/print_air.zig+1
......@@ -155,6 +155,7 @@ const Writer = struct {
155155 .bool_to_int,
156156 .ret,
157157 .ret_load,
158 .tag_name,
158159 => try w.writeUnOp(s, inst),
159160
160161 .breakpoint,
src/type.zig+124-31
......@@ -94,6 +94,7 @@ pub const Type = extern union {
9494
9595 .single_const_pointer_to_comptime_int,
9696 .const_slice_u8,
97 .const_slice_u8_sentinel_0,
9798 .single_const_pointer,
9899 .single_mut_pointer,
99100 .many_const_pointer,
......@@ -107,6 +108,7 @@ pub const Type = extern union {
107108 .inferred_alloc_mut,
108109 .manyptr_u8,
109110 .manyptr_const_u8,
111 .manyptr_const_u8_sentinel_0,
110112 => return .Pointer,
111113
112114 .optional,
......@@ -254,6 +256,7 @@ pub const Type = extern union {
254256 .optional_single_mut_pointer,
255257 .manyptr_u8,
256258 .manyptr_const_u8,
259 .manyptr_const_u8_sentinel_0,
257260 => self.cast(Payload.ElemType),
258261
259262 .inferred_alloc_const => unreachable,
......@@ -275,9 +278,11 @@ pub const Type = extern union {
275278 return switch (ty.tag()) {
276279 .single_const_pointer_to_comptime_int,
277280 .const_slice_u8,
281 .const_slice_u8_sentinel_0,
278282 .single_const_pointer,
279283 .many_const_pointer,
280284 .manyptr_const_u8,
285 .manyptr_const_u8_sentinel_0,
281286 .c_const_pointer,
282287 .const_slice,
283288 => false,
......@@ -330,6 +335,18 @@ pub const Type = extern union {
330335 .@"volatile" = false,
331336 .size = .Slice,
332337 } },
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 } },
333350 .single_const_pointer => return .{ .data = .{
334351 .pointee_type = self.castPointer().?.data,
335352 .sentinel = null,
......@@ -378,6 +395,18 @@ pub const Type = extern union {
378395 .@"volatile" = false,
379396 .size = .Many,
380397 } },
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 } },
381410 .many_mut_pointer => return .{ .data = .{
382411 .pointee_type = self.castPointer().?.data,
383412 .sentinel = null,
......@@ -784,6 +813,7 @@ pub const Type = extern union {
784813 .fn_ccc_void_no_args,
785814 .single_const_pointer_to_comptime_int,
786815 .const_slice_u8,
816 .const_slice_u8_sentinel_0,
787817 .enum_literal,
788818 .anyerror_void_error_union,
789819 .inferred_alloc_const,
......@@ -792,6 +822,7 @@ pub const Type = extern union {
792822 .empty_struct_literal,
793823 .manyptr_u8,
794824 .manyptr_const_u8,
825 .manyptr_const_u8_sentinel_0,
795826 .atomic_order,
796827 .atomic_rmw_op,
797828 .calling_convention,
......@@ -1016,6 +1047,7 @@ pub const Type = extern union {
10161047
10171048 .anyerror_void_error_union => return writer.writeAll("anyerror!void"),
10181049 .const_slice_u8 => return writer.writeAll("[]const u8"),
1050 .const_slice_u8_sentinel_0 => return writer.writeAll("[:0]const u8"),
10191051 .fn_noreturn_no_args => return writer.writeAll("fn() noreturn"),
10201052 .fn_void_no_args => return writer.writeAll("fn() void"),
10211053 .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"),
......@@ -1023,6 +1055,7 @@ pub const Type = extern union {
10231055 .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"),
10241056 .manyptr_u8 => return writer.writeAll("[*]u8"),
10251057 .manyptr_const_u8 => return writer.writeAll("[*]const u8"),
1058 .manyptr_const_u8_sentinel_0 => return writer.writeAll("[*:0]const u8"),
10261059 .atomic_order => return writer.writeAll("std.builtin.AtomicOrder"),
10271060 .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"),
10281061 .calling_convention => return writer.writeAll("std.builtin.CallingConvention"),
......@@ -1308,6 +1341,7 @@ pub const Type = extern union {
13081341
13091342 .anyerror_void_error_union => return "anyerror!void",
13101343 .const_slice_u8 => return "[]const u8",
1344 .const_slice_u8_sentinel_0 => return "[:0]const u8",
13111345 .fn_noreturn_no_args => return "fn() noreturn",
13121346 .fn_void_no_args => return "fn() void",
13131347 .fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn",
......@@ -1315,6 +1349,7 @@ pub const Type = extern union {
13151349 .single_const_pointer_to_comptime_int => return "*const comptime_int",
13161350 .manyptr_u8 => return "[*]u8",
13171351 .manyptr_const_u8 => return "[*]const u8",
1352 .manyptr_const_u8_sentinel_0 => return "[*:0]const u8",
13181353 .atomic_order => return "AtomicOrder",
13191354 .atomic_rmw_op => return "AtomicRmwOp",
13201355 .calling_convention => return "CallingConvention",
......@@ -1386,11 +1421,13 @@ pub const Type = extern union {
13861421 .extern_options,
13871422 .manyptr_u8,
13881423 .manyptr_const_u8,
1424 .manyptr_const_u8_sentinel_0,
13891425 .fn_noreturn_no_args,
13901426 .fn_void_no_args,
13911427 .fn_naked_noreturn_no_args,
13921428 .fn_ccc_void_no_args,
13931429 .const_slice_u8,
1430 .const_slice_u8_sentinel_0,
13941431 .anyerror_void_error_union,
13951432 .empty_struct_literal,
13961433 .function,
......@@ -1498,9 +1535,11 @@ pub const Type = extern union {
14981535 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
14991536 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
15001537 .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),
15011539 .enum_literal => return Value.initTag(.enum_literal_type),
15021540 .manyptr_u8 => return Value.initTag(.manyptr_u8_type),
15031541 .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),
15041543 .atomic_order => return Value.initTag(.atomic_order_type),
15051544 .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type),
15061545 .calling_convention => return Value.initTag(.calling_convention_type),
......@@ -1550,6 +1589,7 @@ pub const Type = extern union {
15501589 .anyerror,
15511590 .single_const_pointer_to_comptime_int,
15521591 .const_slice_u8,
1592 .const_slice_u8_sentinel_0,
15531593 .array_u8_sentinel_0,
15541594 .optional,
15551595 .optional_single_mut_pointer,
......@@ -1561,6 +1601,7 @@ pub const Type = extern union {
15611601 .error_set_merged,
15621602 .manyptr_u8,
15631603 .manyptr_const_u8,
1604 .manyptr_const_u8_sentinel_0,
15641605 .atomic_order,
15651606 .atomic_rmw_op,
15661607 .calling_convention,
......@@ -1703,7 +1744,9 @@ pub const Type = extern union {
17031744
17041745 .manyptr_u8,
17051746 .manyptr_const_u8,
1747 .manyptr_const_u8_sentinel_0,
17061748 .const_slice_u8,
1749 .const_slice_u8_sentinel_0,
17071750 => return 1,
17081751
17091752 .pointer => {
......@@ -1723,6 +1766,7 @@ pub const Type = extern union {
17231766 return switch (self.tag()) {
17241767 .single_const_pointer_to_comptime_int,
17251768 .const_slice_u8,
1769 .const_slice_u8_sentinel_0,
17261770 .single_const_pointer,
17271771 .single_mut_pointer,
17281772 .many_const_pointer,
......@@ -1735,6 +1779,7 @@ pub const Type = extern union {
17351779 .inferred_alloc_mut,
17361780 .manyptr_u8,
17371781 .manyptr_const_u8,
1782 .manyptr_const_u8_sentinel_0,
17381783 => .generic,
17391784
17401785 .pointer => self.castTag(.pointer).?.data.@"addrspace",
......@@ -1785,6 +1830,7 @@ pub const Type = extern union {
17851830 .usize,
17861831 .single_const_pointer_to_comptime_int,
17871832 .const_slice_u8,
1833 .const_slice_u8_sentinel_0,
17881834 .single_const_pointer,
17891835 .single_mut_pointer,
17901836 .many_const_pointer,
......@@ -1798,6 +1844,7 @@ pub const Type = extern union {
17981844 .pointer,
17991845 .manyptr_u8,
18001846 .manyptr_const_u8,
1847 .manyptr_const_u8_sentinel_0,
18011848 .@"anyframe",
18021849 .anyframe_T,
18031850 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
......@@ -2050,7 +2097,9 @@ pub const Type = extern union {
20502097 if (self.elemType().hasCodeGenBits()) return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2;
20512098 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
20522099 },
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
20552104 .optional_single_const_pointer,
20562105 .optional_single_mut_pointer,
......@@ -2068,6 +2117,7 @@ pub const Type = extern union {
20682117 .pointer,
20692118 .manyptr_u8,
20702119 .manyptr_const_u8,
2120 .manyptr_const_u8_sentinel_0,
20712121 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
20722122
20732123 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
......@@ -2223,7 +2273,9 @@ pub const Type = extern union {
22232273 return target.cpu.arch.ptrBitWidth();
22242274 }
22252275 },
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
22282280 .optional_single_const_pointer,
22292281 .optional_single_mut_pointer,
......@@ -2252,6 +2304,7 @@ pub const Type = extern union {
22522304
22532305 .manyptr_u8,
22542306 .manyptr_const_u8,
2307 .manyptr_const_u8_sentinel_0,
22552308 => return target.cpu.arch.ptrBitWidth(),
22562309
22572310 .c_short => return CType.short.sizeInBits(target),
......@@ -2337,12 +2390,14 @@ pub const Type = extern union {
23372390 .const_slice,
23382391 .mut_slice,
23392392 .const_slice_u8,
2393 .const_slice_u8_sentinel_0,
23402394 => .Slice,
23412395
23422396 .many_const_pointer,
23432397 .many_mut_pointer,
23442398 .manyptr_u8,
23452399 .manyptr_const_u8,
2400 .manyptr_const_u8_sentinel_0,
23462401 => .Many,
23472402
23482403 .c_const_pointer,
......@@ -2367,6 +2422,7 @@ pub const Type = extern union {
23672422 .const_slice,
23682423 .mut_slice,
23692424 .const_slice_u8,
2425 .const_slice_u8_sentinel_0,
23702426 => true,
23712427
23722428 .pointer => self.castTag(.pointer).?.data.size == .Slice,
......@@ -2383,6 +2439,7 @@ pub const Type = extern union {
23832439 pub fn slicePtrFieldType(self: Type, buffer: *SlicePtrFieldTypeBuffer) Type {
23842440 switch (self.tag()) {
23852441 .const_slice_u8 => return Type.initTag(.manyptr_const_u8),
2442 .const_slice_u8_sentinel_0 => return Type.initTag(.manyptr_const_u8_sentinel_0),
23862443
23872444 .const_slice => {
23882445 const elem_type = self.castTag(.const_slice).?.data;
......@@ -2464,8 +2521,10 @@ pub const Type = extern union {
24642521 .c_const_pointer,
24652522 .single_const_pointer_to_comptime_int,
24662523 .const_slice_u8,
2524 .const_slice_u8_sentinel_0,
24672525 .const_slice,
24682526 .manyptr_const_u8,
2527 .manyptr_const_u8_sentinel_0,
24692528 => true,
24702529
24712530 .pointer => !self.castTag(.pointer).?.data.mutable,
......@@ -2513,6 +2572,7 @@ pub const Type = extern union {
25132572 .many_const_pointer,
25142573 .many_mut_pointer,
25152574 .manyptr_const_u8,
2575 .manyptr_const_u8_sentinel_0,
25162576 .manyptr_u8,
25172577 .optional_single_const_pointer,
25182578 .optional_single_mut_pointer,
......@@ -2648,9 +2708,11 @@ pub const Type = extern union {
26482708 .array_u8,
26492709 .array_u8_sentinel_0,
26502710 .const_slice_u8,
2711 .const_slice_u8_sentinel_0,
26512712 .manyptr_u8,
26522713 .manyptr_const_u8,
2653 => Type.initTag(.u8),
2714 .manyptr_const_u8_sentinel_0,
2715 => Type.u8,
26542716
26552717 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
26562718 .pointer => ty.castTag(.pointer).?.data.pointee_type,
......@@ -2690,9 +2752,11 @@ pub const Type = extern union {
26902752 .array_u8,
26912753 .array_u8_sentinel_0,
26922754 .const_slice_u8,
2755 .const_slice_u8_sentinel_0,
26932756 .manyptr_u8,
26942757 .manyptr_const_u8,
2695 => Type.initTag(.u8),
2758 .manyptr_const_u8_sentinel_0,
2759 => Type.u8,
26962760
26972761 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
26982762 .pointer => {
......@@ -2937,7 +3001,11 @@ pub const Type = extern union {
29373001
29383002 .pointer => return self.castTag(.pointer).?.data.sentinel,
29393003 .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
29423010 else => unreachable,
29433011 };
......@@ -3309,6 +3377,7 @@ pub const Type = extern union {
33093377 .array_sentinel,
33103378 .array_u8_sentinel_0,
33113379 .const_slice_u8,
3380 .const_slice_u8_sentinel_0,
33123381 .const_slice,
33133382 .mut_slice,
33143383 .anyopaque,
......@@ -3326,6 +3395,7 @@ pub const Type = extern union {
33263395 .var_args_param,
33273396 .manyptr_u8,
33283397 .manyptr_const_u8,
3398 .manyptr_const_u8_sentinel_0,
33293399 .atomic_order,
33303400 .atomic_rmw_op,
33313401 .calling_convention,
......@@ -3956,12 +4026,14 @@ pub const Type = extern union {
39564026 type_info,
39574027 manyptr_u8,
39584028 manyptr_const_u8,
4029 manyptr_const_u8_sentinel_0,
39594030 fn_noreturn_no_args,
39604031 fn_void_no_args,
39614032 fn_naked_noreturn_no_args,
39624033 fn_ccc_void_no_args,
39634034 single_const_pointer_to_comptime_int,
39644035 const_slice_u8,
4036 const_slice_u8_sentinel_0,
39654037 anyerror_void_error_union,
39664038 generic_poison,
39674039 /// This is a special type for variadic parameters of a function call.
......@@ -4064,6 +4136,7 @@ pub const Type = extern union {
40644136 .single_const_pointer_to_comptime_int,
40654137 .anyerror_void_error_union,
40664138 .const_slice_u8,
4139 .const_slice_u8_sentinel_0,
40674140 .generic_poison,
40684141 .inferred_alloc_const,
40694142 .inferred_alloc_mut,
......@@ -4071,6 +4144,7 @@ pub const Type = extern union {
40714144 .empty_struct_literal,
40724145 .manyptr_u8,
40734146 .manyptr_const_u8,
4147 .manyptr_const_u8_sentinel_0,
40744148 .atomic_order,
40754149 .atomic_rmw_op,
40764150 .calling_convention,
......@@ -4322,36 +4396,55 @@ pub const Type = extern union {
43224396
43234397 pub fn ptr(arena: Allocator, d: Payload.Pointer.Data) !Type {
43244398 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 or
4327 d.bit_offset != 0 or d.host_size != 0 or d.@"allowzero" or d.@"volatile")
4403 if (d.@"align" == 0 and d.@"addrspace" == .generic and
4404 d.bit_offset == 0 and d.host_size == 0 and !d.@"allowzero" and !d.@"volatile")
43284405 {
4329 if (d.size == .C) {
4330 assert(d.@"allowzero"); // All C pointers must set allowzero to true.
4406 if (d.sentinel) |sent| {
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);
43314445 }
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);
43374446 }
4338
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);
4447 return Type.Tag.pointer.create(arena, d);
43554448 }
43564449
43574450 pub fn array(
src/value.zig+10
......@@ -73,12 +73,14 @@ pub const Value = extern union {
7373 type_info_type,
7474 manyptr_u8_type,
7575 manyptr_const_u8_type,
76 manyptr_const_u8_sentinel_0_type,
7677 fn_noreturn_no_args_type,
7778 fn_void_no_args_type,
7879 fn_naked_noreturn_no_args_type,
7980 fn_ccc_void_no_args_type,
8081 single_const_pointer_to_comptime_int_type,
8182 const_slice_u8_type,
83 const_slice_u8_sentinel_0_type,
8284 anyerror_void_error_union_type,
8385 generic_poison_type,
8486
......@@ -221,6 +223,7 @@ pub const Value = extern union {
221223 .single_const_pointer_to_comptime_int_type,
222224 .anyframe_type,
223225 .const_slice_u8_type,
226 .const_slice_u8_sentinel_0_type,
224227 .anyerror_void_error_union_type,
225228 .generic_poison_type,
226229 .enum_literal_type,
......@@ -238,6 +241,7 @@ pub const Value = extern union {
238241 .abi_align_default,
239242 .manyptr_u8_type,
240243 .manyptr_const_u8_type,
244 .manyptr_const_u8_sentinel_0_type,
241245 .atomic_order_type,
242246 .atomic_rmw_op_type,
243247 .calling_convention_type,
......@@ -412,6 +416,7 @@ pub const Value = extern union {
412416 .single_const_pointer_to_comptime_int_type,
413417 .anyframe_type,
414418 .const_slice_u8_type,
419 .const_slice_u8_sentinel_0_type,
415420 .anyerror_void_error_union_type,
416421 .generic_poison_type,
417422 .enum_literal_type,
......@@ -429,6 +434,7 @@ pub const Value = extern union {
429434 .abi_align_default,
430435 .manyptr_u8_type,
431436 .manyptr_const_u8_type,
437 .manyptr_const_u8_sentinel_0_type,
432438 .atomic_order_type,
433439 .atomic_rmw_op_type,
434440 .calling_convention_type,
......@@ -642,12 +648,14 @@ pub const Value = extern union {
642648 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
643649 .anyframe_type => return out_stream.writeAll("anyframe"),
644650 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
651 .const_slice_u8_sentinel_0_type => return out_stream.writeAll("[:0]const u8"),
645652 .anyerror_void_error_union_type => return out_stream.writeAll("anyerror!void"),
646653 .generic_poison_type => return out_stream.writeAll("(generic poison type)"),
647654 .generic_poison => return out_stream.writeAll("(generic poison)"),
648655 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
649656 .manyptr_u8_type => return out_stream.writeAll("[*]u8"),
650657 .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"),
658 .manyptr_const_u8_sentinel_0_type => return out_stream.writeAll("[*:0]const u8"),
651659 .atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"),
652660 .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"),
653661 .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"),
......@@ -821,11 +829,13 @@ pub const Value = extern union {
821829 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
822830 .anyframe_type => Type.initTag(.@"anyframe"),
823831 .const_slice_u8_type => Type.initTag(.const_slice_u8),
832 .const_slice_u8_sentinel_0_type => Type.initTag(.const_slice_u8_sentinel_0),
824833 .anyerror_void_error_union_type => Type.initTag(.anyerror_void_error_union),
825834 .generic_poison_type => Type.initTag(.generic_poison),
826835 .enum_literal_type => Type.initTag(.enum_literal),
827836 .manyptr_u8_type => Type.initTag(.manyptr_u8),
828837 .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8),
838 .manyptr_const_u8_sentinel_0_type => Type.initTag(.manyptr_const_u8_sentinel_0),
829839 .atomic_order_type => Type.initTag(.atomic_order),
830840 .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op),
831841 .calling_convention_type => Type.initTag(.calling_convention),
test/behavior.zig+1
......@@ -75,6 +75,7 @@ test {
7575 _ = @import("behavior/bugs/3112.zig");
7676 _ = @import("behavior/bugs/7250.zig");
7777 _ = @import("behavior/cast_llvm.zig");
78 _ = @import("behavior/enum_llvm.zig");
7879 _ = @import("behavior/eval.zig");
7980 _ = @import("behavior/floatop.zig");
8081 _ = @import("behavior/fn.zig");
test/behavior/enum.zig+123
......@@ -699,3 +699,126 @@ test "single field non-exhaustive enum" {
699699 try S.doTheTest(23);
700700 comptime try S.doTheTest(23);
701701}
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;
22const mem = @import("std").mem;
33const 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, _ };
315const 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
477const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
488const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
......@@ -87,15 +47,6 @@ fn getC(data: *const BitFieldOfEnums) C {
8747 return data.c;
8848}
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
9950const MultipleChoice2 = enum(u32) {
10051 Unspecified1,
10152 A = 20,
......@@ -108,31 +59,6 @@ const MultipleChoice2 = enum(u32) {
10859 Unspecified5,
10960};
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
13662const EnumWithOneMember = enum { Eof };
13763
13864fn doALoopThing(id: EnumWithOneMember) void {
......@@ -157,32 +83,6 @@ test "switch on enum with one member is comptime known" {
15783 @compileError("analysis should not reach here");
15884}
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
18686test "enum literal in array literal" {
18787 const Items = enum { one, two };
18888 const array = [_]Items{ .one, .two };
......@@ -191,18 +91,6 @@ test "enum literal in array literal" {
19191 try expect(array[1] == .two);
19292}
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
20694test "enum value allocation" {
20795 const LargeEnum = enum(u32) {
20896 A0 = 0x80000000,
......@@ -235,26 +123,8 @@ test "enum literal casting to tagged union" {
235123 }
236124}
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
249126const 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
258128test "enum literal casting to error union with payload enum" {
259129 var bar: error{B}!Bar = undefined;
260130 bar = .B; // should never cast to the error set
......@@ -262,27 +132,6 @@ test "enum literal casting to error union with payload enum" {
262132 try expect((try bar) == Bar.B);
263133}
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
286135test "tagName on enum literals" {
287136 try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
288137 comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));