| author | |
| committer | |
| log | c8fb36b36cd8368e84752770edf720e6e91ed997 |
| tree | db0821f54a28f552240d27becaf4b1538b613d2e |
| parent | f41b9cdb6d7f954495ffca168108ddd38bf27353 |
Introduced a new AIR instruction: `tag_name`. Reasons to do this
instead of lowering it in Sema to a switch, function call, array
lookup, or if-else tower:
* Sema is a bottleneck; do less work in Sema whenever possible.
* If any optimization passes run, and the operand to becomes
comptime-known, then it could change to have a comptime result
value instead of lowering to a function or array or something which
would then have to be garbage-collected.
* Backends may want to choose to use a function and a switch branch,
or they may want to use a different strategy.
Codegen for `@tagName` is implemented for the LLVM backend but not any
others yet.
Introduced some new `Type` tags:
* `const_slice_u8_sentinel_0`
* `manyptr_const_u8_sentinel_0`
The motivation for this was to make typeof() on the tag_name AIR
instruction non-allocating.
A bunch more enum tests are passing now.17 files changed, 1083 insertions(+), 706 deletions(-)
src/Air.zig+7| ... | ... | @@ -496,6 +496,11 @@ pub const Inst = struct { |
| 496 | 496 | /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`. |
| 497 | 497 | atomic_rmw, |
| 498 | 498 | |
| 499 | /// Given an enum tag value, returns the tag name. The enum type may be non-exhaustive. | |
| 500 | /// Result type is always `[:0]const u8`. | |
| 501 | /// Uses the `un_op` field. | |
| 502 | tag_name, | |
| 503 | ||
| 499 | 504 | pub fn fromCmpOp(op: std.math.CompareOperator) Tag { |
| 500 | 505 | return switch (op) { |
| 501 | 506 | .lt => .cmp_lt, |
| ... | ... | @@ -811,6 +816,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 811 | 816 | |
| 812 | 817 | .bool_to_int => return Type.initTag(.u1), |
| 813 | 818 | |
| 819 | .tag_name => return Type.initTag(.const_slice_u8_sentinel_0), | |
| 820 | ||
| 814 | 821 | .call => { |
| 815 | 822 | const callee_ty = air.typeOf(datas[inst].pl_op.operand); |
| 816 | 823 | switch (callee_ty.zigTypeTag()) { |
src/Liveness.zig+1| ... | ... | @@ -333,6 +333,7 @@ fn analyzeInst( |
| 333 | 333 | .bool_to_int, |
| 334 | 334 | .ret, |
| 335 | 335 | .ret_load, |
| 336 | .tag_name, | |
| 336 | 337 | => { |
| 337 | 338 | const operand = inst_datas[inst].un_op; |
| 338 | 339 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); |
src/Sema.zig+49-2| ... | ... | @@ -2804,8 +2804,11 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 2804 | 2804 | const tracy = trace(@src()); |
| 2805 | 2805 | defer tracy.end(); |
| 2806 | 2806 | |
| 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 | } | |
| 2808 | 2810 | |
| 2811 | fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air.Inst.Ref { | |
| 2809 | 2812 | // `zir_bytes` references memory inside the ZIR module, which can get deallocated |
| 2810 | 2813 | // after semantic analysis is complete, for example in the case of the initialization |
| 2811 | 2814 | // expression of a variable declaration. We need the memory to be in the new |
| ... | ... | @@ -10045,8 +10048,50 @@ fn zirUnaryMath(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 10045 | 10048 | |
| 10046 | 10049 | fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 10047 | 10050 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 10051 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | |
| 10048 | 10052 | const src = inst_data.src(); |
| 10049 | return sema.fail(block, src, "TODO: Sema.zirTagName", .{}); | |
| 10053 | const operand = sema.resolveInst(inst_data.operand); | |
| 10054 | const operand_ty = sema.typeOf(operand); | |
| 10055 | ||
| 10056 | const enum_ty = switch (operand_ty.zigTypeTag()) { | |
| 10057 | .Enum => operand_ty, | |
| 10058 | .Union => operand_ty.unionTagType() orelse { | |
| 10059 | const decl = operand_ty.getOwnerDecl(); | |
| 10060 | const msg = msg: { | |
| 10061 | const msg = try sema.errMsg(block, src, "union '{s}' is untagged", .{ | |
| 10062 | decl.name, | |
| 10063 | }); | |
| 10064 | errdefer msg.destroy(sema.gpa); | |
| 10065 | try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "declared here", .{}); | |
| 10066 | break :msg msg; | |
| 10067 | }; | |
| 10068 | return sema.failWithOwnedErrorMsg(msg); | |
| 10069 | }, | |
| 10070 | else => return sema.fail(block, operand_src, "expected enum or union; found {}", .{ | |
| 10071 | operand_ty, | |
| 10072 | }), | |
| 10073 | }; | |
| 10074 | const enum_decl = enum_ty.getOwnerDecl(); | |
| 10075 | const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src); | |
| 10076 | if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { | |
| 10077 | const field_index = enum_ty.enumTagFieldIndex(val) orelse { | |
| 10078 | const msg = msg: { | |
| 10079 | const msg = try sema.errMsg(block, src, "no field with value {} in enum '{s}'", .{ | |
| 10080 | casted_operand, enum_decl.name, | |
| 10081 | }); | |
| 10082 | errdefer msg.destroy(sema.gpa); | |
| 10083 | try sema.mod.errNoteNonLazy(enum_decl.srcLoc(), msg, "declared here", .{}); | |
| 10084 | break :msg msg; | |
| 10085 | }; | |
| 10086 | return sema.failWithOwnedErrorMsg(msg); | |
| 10087 | }; | |
| 10088 | const field_name = enum_ty.enumFieldName(field_index); | |
| 10089 | return sema.addStrLit(block, field_name); | |
| 10090 | } | |
| 10091 | // In case the value is runtime-known, we have an AIR instruction for this instead | |
| 10092 | // of trying to lower it in Sema because an optimization pass may result in the operand | |
| 10093 | // being comptime-known, which would let us elide the `tag_name` AIR instruction. | |
| 10094 | return block.addUnOp(.tag_name, casted_operand); | |
| 10050 | 10095 | } |
| 10051 | 10096 | |
| 10052 | 10097 | fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -15339,6 +15384,7 @@ fn typeHasOnePossibleValue( |
| 15339 | 15384 | .array_sentinel, |
| 15340 | 15385 | .array_u8_sentinel_0, |
| 15341 | 15386 | .const_slice_u8, |
| 15387 | .const_slice_u8_sentinel_0, | |
| 15342 | 15388 | .const_slice, |
| 15343 | 15389 | .mut_slice, |
| 15344 | 15390 | .anyopaque, |
| ... | ... | @@ -15356,6 +15402,7 @@ fn typeHasOnePossibleValue( |
| 15356 | 15402 | .var_args_param, |
| 15357 | 15403 | .manyptr_u8, |
| 15358 | 15404 | .manyptr_const_u8, |
| 15405 | .manyptr_const_u8_sentinel_0, | |
| 15359 | 15406 | .atomic_order, |
| 15360 | 15407 | .atomic_rmw_op, |
| 15361 | 15408 | .calling_convention, |
src/arch/aarch64/CodeGen.zig+138-127| ... | ... | @@ -504,133 +504,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 504 | 504 | |
| 505 | 505 | switch (air_tags[inst]) { |
| 506 | 506 | // 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 | |
| 634 | 635 | } |
| 635 | 636 | if (std.debug.runtime_safety) { |
| 636 | 637 | if (self.air_bookkeeping < old_air_bookkeeping + 1) { |
| ... | ... | @@ -2546,6 +2547,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 2546 | 2547 | return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch}); |
| 2547 | 2548 | } |
| 2548 | 2549 | |
| 2550 | fn 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 | ||
| 2549 | 2560 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 2550 | 2561 | // First section of indexes correspond to a set number of constant values. |
| 2551 | 2562 | const ref_int = @enumToInt(inst); |
src/arch/arm/CodeGen.zig+138-127| ... | ... | @@ -502,133 +502,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 502 | 502 | |
| 503 | 503 | switch (air_tags[inst]) { |
| 504 | 504 | // 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 | |
| 632 | 633 | } |
| 633 | 634 | if (std.debug.runtime_safety) { |
| 634 | 635 | if (self.air_bookkeeping < old_air_bookkeeping + 1) { |
| ... | ... | @@ -3301,6 +3302,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 3301 | 3302 | return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch}); |
| 3302 | 3303 | } |
| 3303 | 3304 | |
| 3305 | fn 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 | ||
| 3304 | 3315 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 3305 | 3316 | // First section of indexes correspond to a set number of constant values. |
| 3306 | 3317 | const ref_int = @enumToInt(inst); |
src/arch/riscv64/CodeGen.zig+138-127| ... | ... | @@ -483,133 +483,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 483 | 483 | |
| 484 | 484 | switch (air_tags[inst]) { |
| 485 | 485 | // 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 | |
| 613 | 614 | } |
| 614 | 615 | if (std.debug.runtime_safety) { |
| 615 | 616 | if (self.air_bookkeeping < old_air_bookkeeping + 1) { |
| ... | ... | @@ -2045,6 +2046,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 2045 | 2046 | return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch}); |
| 2046 | 2047 | } |
| 2047 | 2048 | |
| 2049 | fn 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 | ||
| 2048 | 2059 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 2049 | 2060 | // First section of indexes correspond to a set number of constant values. |
| 2050 | 2061 | const ref_int = @enumToInt(inst); |
src/arch/x86_64/CodeGen.zig+138-127| ... | ... | @@ -538,133 +538,134 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 538 | 538 | |
| 539 | 539 | switch (air_tags[inst]) { |
| 540 | 540 | // 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 | |
| 668 | 669 | } |
| 669 | 670 | if (std.debug.runtime_safety) { |
| 670 | 671 | if (self.air_bookkeeping < old_air_bookkeeping + 1) { |
| ... | ... | @@ -3174,6 +3175,16 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 3174 | 3175 | return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch}); |
| 3175 | 3176 | } |
| 3176 | 3177 | |
| 3178 | fn 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 | ||
| 3177 | 3188 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 3178 | 3189 | // First section of indexes correspond to a set number of constant values. |
| 3179 | 3190 | const ref_int = @enumToInt(inst); |
src/codegen/c.zig+19| ... | ... | @@ -1230,6 +1230,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1230 | 1230 | .clz => try airBuiltinCall(f, inst, "clz"), |
| 1231 | 1231 | .ctz => try airBuiltinCall(f, inst, "ctz"), |
| 1232 | 1232 | .popcount => try airBuiltinCall(f, inst, "popcount"), |
| 1233 | .tag_name => try airTagName(f, inst), | |
| 1233 | 1234 | |
| 1234 | 1235 | .int_to_float, |
| 1235 | 1236 | .float_to_int, |
| ... | ... | @@ -2914,6 +2915,24 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2914 | 2915 | return local; |
| 2915 | 2916 | } |
| 2916 | 2917 | |
| 2918 | fn 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 | ||
| 2917 | 2936 | fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { |
| 2918 | 2937 | return switch (order) { |
| 2919 | 2938 | .Unordered => "memory_order_relaxed", |
src/codegen/llvm.zig+132-14| ... | ... | @@ -636,15 +636,6 @@ pub const DeclGen = struct { |
| 636 | 636 | llvm_param_i += 1; |
| 637 | 637 | } |
| 638 | 638 | |
| 639 | if (dg.module.comp.bin_file.options.skip_linker_dependencies) { | |
| 640 | // The intent here is for compiler-rt and libc functions to not generate | |
| 641 | // infinite recursion. For example, if we are compiling the memcpy function, | |
| 642 | // and llvm detects that the body is equivalent to memcpy, it may replace the | |
| 643 | // body of memcpy with a call to memcpy, which would then cause a stack | |
| 644 | // overflow instead of performing memcpy. | |
| 645 | dg.addFnAttr(llvm_fn, "nobuiltin"); | |
| 646 | } | |
| 647 | ||
| 648 | 639 | // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`. |
| 649 | 640 | if (fn_info.cc == .Naked) { |
| 650 | 641 | dg.addFnAttr(llvm_fn, "naked"); |
| ... | ... | @@ -653,6 +644,16 @@ pub const DeclGen = struct { |
| 653 | 644 | } |
| 654 | 645 | |
| 655 | 646 | // Function attributes that are independent of analysis results of the function body. |
| 647 | dg.addCommonFnAttributes(llvm_fn); | |
| 648 | ||
| 649 | if (return_type.isNoReturn()) { | |
| 650 | dg.addFnAttr(llvm_fn, "noreturn"); | |
| 651 | } | |
| 652 | ||
| 653 | return llvm_fn; | |
| 654 | } | |
| 655 | ||
| 656 | fn addCommonFnAttributes(dg: *DeclGen, llvm_fn: *const llvm.Value) void { | |
| 656 | 657 | if (!dg.module.comp.bin_file.options.red_zone) { |
| 657 | 658 | dg.addFnAttr(llvm_fn, "noredzone"); |
| 658 | 659 | } |
| ... | ... | @@ -665,6 +666,14 @@ pub const DeclGen = struct { |
| 665 | 666 | if (dg.module.comp.unwind_tables) { |
| 666 | 667 | dg.addFnAttr(llvm_fn, "uwtable"); |
| 667 | 668 | } |
| 669 | if (dg.module.comp.bin_file.options.skip_linker_dependencies) { | |
| 670 | // The intent here is for compiler-rt and libc functions to not generate | |
| 671 | // infinite recursion. For example, if we are compiling the memcpy function, | |
| 672 | // and llvm detects that the body is equivalent to memcpy, it may replace the | |
| 673 | // body of memcpy with a call to memcpy, which would then cause a stack | |
| 674 | // overflow instead of performing memcpy. | |
| 675 | dg.addFnAttr(llvm_fn, "nobuiltin"); | |
| 676 | } | |
| 668 | 677 | if (dg.module.comp.bin_file.options.optimize_mode == .ReleaseSmall) { |
| 669 | 678 | dg.addFnAttr(llvm_fn, "minsize"); |
| 670 | 679 | dg.addFnAttr(llvm_fn, "optsize"); |
| ... | ... | @@ -673,11 +682,6 @@ pub const DeclGen = struct { |
| 673 | 682 | dg.addFnAttr(llvm_fn, "sanitize_thread"); |
| 674 | 683 | } |
| 675 | 684 | // TODO add target-cpu and target-features fn attributes |
| 676 | if (return_type.isNoReturn()) { | |
| 677 | dg.addFnAttr(llvm_fn, "noreturn"); | |
| 678 | } | |
| 679 | ||
| 680 | return llvm_fn; | |
| 681 | 685 | } |
| 682 | 686 | |
| 683 | 687 | fn resolveGlobalDecl(dg: *DeclGen, decl: *Module.Decl) Error!*const llvm.Value { |
| ... | ... | @@ -1958,6 +1962,7 @@ pub const FuncGen = struct { |
| 1958 | 1962 | .clz => try self.airClzCtz(inst, "ctlz"), |
| 1959 | 1963 | .ctz => try self.airClzCtz(inst, "cttz"), |
| 1960 | 1964 | .popcount => try self.airPopCount(inst, "ctpop"), |
| 1965 | .tag_name => try self.airTagName(inst), | |
| 1961 | 1966 | |
| 1962 | 1967 | .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), |
| 1963 | 1968 | .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), |
| ... | ... | @@ -4093,6 +4098,119 @@ pub const FuncGen = struct { |
| 4093 | 4098 | } |
| 4094 | 4099 | } |
| 4095 | 4100 | |
| 4101 | fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 4102 | if (self.liveness.isUnused(inst)) return null; | |
| 4103 | ||
| 4104 | var arena_allocator = std.heap.ArenaAllocator.init(self.gpa); | |
| 4105 | defer arena_allocator.deinit(); | |
| 4106 | const arena = arena_allocator.allocator(); | |
| 4107 | ||
| 4108 | const un_op = self.air.instructions.items(.data)[inst].un_op; | |
| 4109 | const operand = try self.resolveInst(un_op); | |
| 4110 | const enum_ty = self.air.typeOf(un_op); | |
| 4111 | ||
| 4112 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{ | |
| 4113 | try enum_ty.getOwnerDecl().getFullyQualifiedName(arena), | |
| 4114 | }); | |
| 4115 | ||
| 4116 | const llvm_fn = try self.getEnumTagNameFunction(enum_ty, llvm_fn_name); | |
| 4117 | const params = [_]*const llvm.Value{operand}; | |
| 4118 | return self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, ""); | |
| 4119 | } | |
| 4120 | ||
| 4121 | fn getEnumTagNameFunction( | |
| 4122 | self: *FuncGen, | |
| 4123 | enum_ty: Type, | |
| 4124 | llvm_fn_name: [:0]const u8, | |
| 4125 | ) !*const llvm.Value { | |
| 4126 | // TODO: detect when the type changes and re-emit this function. | |
| 4127 | if (self.dg.object.llvm_module.getNamedFunction(llvm_fn_name)) |llvm_fn| { | |
| 4128 | return llvm_fn; | |
| 4129 | } | |
| 4130 | ||
| 4131 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | |
| 4132 | const llvm_ret_ty = try self.dg.llvmType(slice_ty); | |
| 4133 | const usize_llvm_ty = try self.dg.llvmType(Type.usize); | |
| 4134 | const target = self.dg.module.getTarget(); | |
| 4135 | const slice_alignment = slice_ty.abiAlignment(target); | |
| 4136 | ||
| 4137 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | |
| 4138 | const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer); | |
| 4139 | const param_types = [_]*const llvm.Type{try self.dg.llvmType(int_tag_ty)}; | |
| 4140 | ||
| 4141 | const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False); | |
| 4142 | const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); | |
| 4143 | fn_val.setLinkage(.Internal); | |
| 4144 | fn_val.setFunctionCallConv(.Fast); | |
| 4145 | self.dg.addCommonFnAttributes(fn_val); | |
| 4146 | ||
| 4147 | const prev_block = self.builder.getInsertBlock(); | |
| 4148 | const prev_debug_location = self.builder.getCurrentDebugLocation2(); | |
| 4149 | defer { | |
| 4150 | self.builder.positionBuilderAtEnd(prev_block); | |
| 4151 | if (!self.dg.module.comp.bin_file.options.strip) { | |
| 4152 | self.builder.setCurrentDebugLocation2(prev_debug_location); | |
| 4153 | } | |
| 4154 | } | |
| 4155 | ||
| 4156 | const entry_block = self.dg.context.appendBasicBlock(fn_val, "Entry"); | |
| 4157 | self.builder.positionBuilderAtEnd(entry_block); | |
| 4158 | self.builder.clearCurrentDebugLocation(); | |
| 4159 | ||
| 4160 | const fields = enum_ty.enumFields(); | |
| 4161 | const bad_value_block = self.dg.context.appendBasicBlock(fn_val, "BadValue"); | |
| 4162 | const tag_int_value = fn_val.getParam(0); | |
| 4163 | const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @intCast(c_uint, fields.count())); | |
| 4164 | ||
| 4165 | const array_ptr_indices = [_]*const llvm.Value{ | |
| 4166 | usize_llvm_ty.constNull(), usize_llvm_ty.constNull(), | |
| 4167 | }; | |
| 4168 | ||
| 4169 | for (fields.keys()) |name, field_index| { | |
| 4170 | const str_init = self.dg.context.constString(name.ptr, @intCast(c_uint, name.len), .False); | |
| 4171 | const str_global = self.dg.object.llvm_module.addGlobal(str_init.typeOf(), ""); | |
| 4172 | str_global.setInitializer(str_init); | |
| 4173 | str_global.setLinkage(.Private); | |
| 4174 | str_global.setGlobalConstant(.True); | |
| 4175 | str_global.setUnnamedAddr(.True); | |
| 4176 | str_global.setAlignment(1); | |
| 4177 | ||
| 4178 | const slice_fields = [_]*const llvm.Value{ | |
| 4179 | str_global.constInBoundsGEP(&array_ptr_indices, array_ptr_indices.len), | |
| 4180 | usize_llvm_ty.constInt(name.len, .False), | |
| 4181 | }; | |
| 4182 | const slice_init = llvm_ret_ty.constNamedStruct(&slice_fields, slice_fields.len); | |
| 4183 | const slice_global = self.dg.object.llvm_module.addGlobal(slice_init.typeOf(), ""); | |
| 4184 | slice_global.setInitializer(slice_init); | |
| 4185 | slice_global.setLinkage(.Private); | |
| 4186 | slice_global.setGlobalConstant(.True); | |
| 4187 | slice_global.setUnnamedAddr(.True); | |
| 4188 | slice_global.setAlignment(slice_alignment); | |
| 4189 | ||
| 4190 | const return_block = self.dg.context.appendBasicBlock(fn_val, "Name"); | |
| 4191 | const this_tag_int_value = int: { | |
| 4192 | var tag_val_payload: Value.Payload.U32 = .{ | |
| 4193 | .base = .{ .tag = .enum_field_index }, | |
| 4194 | .data = @intCast(u32, field_index), | |
| 4195 | }; | |
| 4196 | break :int try self.dg.genTypedValue(.{ | |
| 4197 | .ty = enum_ty, | |
| 4198 | .val = Value.initPayload(&tag_val_payload.base), | |
| 4199 | }); | |
| 4200 | }; | |
| 4201 | switch_instr.addCase(this_tag_int_value, return_block); | |
| 4202 | ||
| 4203 | self.builder.positionBuilderAtEnd(return_block); | |
| 4204 | const loaded = self.builder.buildLoad(slice_global, ""); | |
| 4205 | loaded.setAlignment(slice_alignment); | |
| 4206 | _ = self.builder.buildRet(loaded); | |
| 4207 | } | |
| 4208 | ||
| 4209 | self.builder.positionBuilderAtEnd(bad_value_block); | |
| 4210 | _ = self.builder.buildUnreachable(); | |
| 4211 | return fn_val; | |
| 4212 | } | |
| 4213 | ||
| 4096 | 4214 | /// Assumes the optional is not pointer-like and payload has bits. |
| 4097 | 4215 | fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value { |
| 4098 | 4216 | if (is_by_ref) { |
src/codegen/llvm/bindings.zig+15| ... | ... | @@ -785,8 +785,23 @@ pub const Builder = opaque { |
| 785 | 785 | |
| 786 | 786 | pub const buildExactSDiv = LLVMBuildExactSDiv; |
| 787 | 787 | extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 788 | ||
| 789 | pub const zigSetCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation; | |
| 790 | extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_int, column: c_int, scope: *DIScope) void; | |
| 791 | ||
| 792 | pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation; | |
| 793 | extern fn ZigLLVMClearCurrentDebugLocation(builder: *const Builder) void; | |
| 794 | ||
| 795 | pub const getCurrentDebugLocation2 = LLVMGetCurrentDebugLocation2; | |
| 796 | extern fn LLVMGetCurrentDebugLocation2(Builder: *const Builder) *Metadata; | |
| 797 | ||
| 798 | pub const setCurrentDebugLocation2 = LLVMSetCurrentDebugLocation2; | |
| 799 | extern fn LLVMSetCurrentDebugLocation2(Builder: *const Builder, Loc: *Metadata) void; | |
| 788 | 800 | }; |
| 789 | 801 | |
| 802 | pub const DIScope = opaque {}; | |
| 803 | pub const Metadata = opaque {}; | |
| 804 | ||
| 790 | 805 | pub const IntPredicate = enum(c_uint) { |
| 791 | 806 | EQ = 32, |
| 792 | 807 | NE = 33, |
src/print_air.zig+1| ... | ... | @@ -155,6 +155,7 @@ const Writer = struct { |
| 155 | 155 | .bool_to_int, |
| 156 | 156 | .ret, |
| 157 | 157 | .ret_load, |
| 158 | .tag_name, | |
| 158 | 159 | => try w.writeUnOp(s, inst), |
| 159 | 160 | |
| 160 | 161 | .breakpoint, |
src/type.zig+124-31| ... | ... | @@ -94,6 +94,7 @@ pub const Type = extern union { |
| 94 | 94 | |
| 95 | 95 | .single_const_pointer_to_comptime_int, |
| 96 | 96 | .const_slice_u8, |
| 97 | .const_slice_u8_sentinel_0, | |
| 97 | 98 | .single_const_pointer, |
| 98 | 99 | .single_mut_pointer, |
| 99 | 100 | .many_const_pointer, |
| ... | ... | @@ -107,6 +108,7 @@ pub const Type = extern union { |
| 107 | 108 | .inferred_alloc_mut, |
| 108 | 109 | .manyptr_u8, |
| 109 | 110 | .manyptr_const_u8, |
| 111 | .manyptr_const_u8_sentinel_0, | |
| 110 | 112 | => return .Pointer, |
| 111 | 113 | |
| 112 | 114 | .optional, |
| ... | ... | @@ -254,6 +256,7 @@ pub const Type = extern union { |
| 254 | 256 | .optional_single_mut_pointer, |
| 255 | 257 | .manyptr_u8, |
| 256 | 258 | .manyptr_const_u8, |
| 259 | .manyptr_const_u8_sentinel_0, | |
| 257 | 260 | => self.cast(Payload.ElemType), |
| 258 | 261 | |
| 259 | 262 | .inferred_alloc_const => unreachable, |
| ... | ... | @@ -275,9 +278,11 @@ pub const Type = extern union { |
| 275 | 278 | return switch (ty.tag()) { |
| 276 | 279 | .single_const_pointer_to_comptime_int, |
| 277 | 280 | .const_slice_u8, |
| 281 | .const_slice_u8_sentinel_0, | |
| 278 | 282 | .single_const_pointer, |
| 279 | 283 | .many_const_pointer, |
| 280 | 284 | .manyptr_const_u8, |
| 285 | .manyptr_const_u8_sentinel_0, | |
| 281 | 286 | .c_const_pointer, |
| 282 | 287 | .const_slice, |
| 283 | 288 | => false, |
| ... | ... | @@ -330,6 +335,18 @@ pub const Type = extern union { |
| 330 | 335 | .@"volatile" = false, |
| 331 | 336 | .size = .Slice, |
| 332 | 337 | } }, |
| 338 | .const_slice_u8_sentinel_0 => return .{ .data = .{ | |
| 339 | .pointee_type = Type.initTag(.u8), | |
| 340 | .sentinel = Value.zero, | |
| 341 | .@"align" = 0, | |
| 342 | .@"addrspace" = .generic, | |
| 343 | .bit_offset = 0, | |
| 344 | .host_size = 0, | |
| 345 | .@"allowzero" = false, | |
| 346 | .mutable = false, | |
| 347 | .@"volatile" = false, | |
| 348 | .size = .Slice, | |
| 349 | } }, | |
| 333 | 350 | .single_const_pointer => return .{ .data = .{ |
| 334 | 351 | .pointee_type = self.castPointer().?.data, |
| 335 | 352 | .sentinel = null, |
| ... | ... | @@ -378,6 +395,18 @@ pub const Type = extern union { |
| 378 | 395 | .@"volatile" = false, |
| 379 | 396 | .size = .Many, |
| 380 | 397 | } }, |
| 398 | .manyptr_const_u8_sentinel_0 => return .{ .data = .{ | |
| 399 | .pointee_type = Type.initTag(.u8), | |
| 400 | .sentinel = Value.zero, | |
| 401 | .@"align" = 0, | |
| 402 | .@"addrspace" = .generic, | |
| 403 | .bit_offset = 0, | |
| 404 | .host_size = 0, | |
| 405 | .@"allowzero" = false, | |
| 406 | .mutable = false, | |
| 407 | .@"volatile" = false, | |
| 408 | .size = .Many, | |
| 409 | } }, | |
| 381 | 410 | .many_mut_pointer => return .{ .data = .{ |
| 382 | 411 | .pointee_type = self.castPointer().?.data, |
| 383 | 412 | .sentinel = null, |
| ... | ... | @@ -784,6 +813,7 @@ pub const Type = extern union { |
| 784 | 813 | .fn_ccc_void_no_args, |
| 785 | 814 | .single_const_pointer_to_comptime_int, |
| 786 | 815 | .const_slice_u8, |
| 816 | .const_slice_u8_sentinel_0, | |
| 787 | 817 | .enum_literal, |
| 788 | 818 | .anyerror_void_error_union, |
| 789 | 819 | .inferred_alloc_const, |
| ... | ... | @@ -792,6 +822,7 @@ pub const Type = extern union { |
| 792 | 822 | .empty_struct_literal, |
| 793 | 823 | .manyptr_u8, |
| 794 | 824 | .manyptr_const_u8, |
| 825 | .manyptr_const_u8_sentinel_0, | |
| 795 | 826 | .atomic_order, |
| 796 | 827 | .atomic_rmw_op, |
| 797 | 828 | .calling_convention, |
| ... | ... | @@ -1016,6 +1047,7 @@ pub const Type = extern union { |
| 1016 | 1047 | |
| 1017 | 1048 | .anyerror_void_error_union => return writer.writeAll("anyerror!void"), |
| 1018 | 1049 | .const_slice_u8 => return writer.writeAll("[]const u8"), |
| 1050 | .const_slice_u8_sentinel_0 => return writer.writeAll("[:0]const u8"), | |
| 1019 | 1051 | .fn_noreturn_no_args => return writer.writeAll("fn() noreturn"), |
| 1020 | 1052 | .fn_void_no_args => return writer.writeAll("fn() void"), |
| 1021 | 1053 | .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"), |
| ... | ... | @@ -1023,6 +1055,7 @@ pub const Type = extern union { |
| 1023 | 1055 | .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"), |
| 1024 | 1056 | .manyptr_u8 => return writer.writeAll("[*]u8"), |
| 1025 | 1057 | .manyptr_const_u8 => return writer.writeAll("[*]const u8"), |
| 1058 | .manyptr_const_u8_sentinel_0 => return writer.writeAll("[*:0]const u8"), | |
| 1026 | 1059 | .atomic_order => return writer.writeAll("std.builtin.AtomicOrder"), |
| 1027 | 1060 | .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"), |
| 1028 | 1061 | .calling_convention => return writer.writeAll("std.builtin.CallingConvention"), |
| ... | ... | @@ -1308,6 +1341,7 @@ pub const Type = extern union { |
| 1308 | 1341 | |
| 1309 | 1342 | .anyerror_void_error_union => return "anyerror!void", |
| 1310 | 1343 | .const_slice_u8 => return "[]const u8", |
| 1344 | .const_slice_u8_sentinel_0 => return "[:0]const u8", | |
| 1311 | 1345 | .fn_noreturn_no_args => return "fn() noreturn", |
| 1312 | 1346 | .fn_void_no_args => return "fn() void", |
| 1313 | 1347 | .fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn", |
| ... | ... | @@ -1315,6 +1349,7 @@ pub const Type = extern union { |
| 1315 | 1349 | .single_const_pointer_to_comptime_int => return "*const comptime_int", |
| 1316 | 1350 | .manyptr_u8 => return "[*]u8", |
| 1317 | 1351 | .manyptr_const_u8 => return "[*]const u8", |
| 1352 | .manyptr_const_u8_sentinel_0 => return "[*:0]const u8", | |
| 1318 | 1353 | .atomic_order => return "AtomicOrder", |
| 1319 | 1354 | .atomic_rmw_op => return "AtomicRmwOp", |
| 1320 | 1355 | .calling_convention => return "CallingConvention", |
| ... | ... | @@ -1386,11 +1421,13 @@ pub const Type = extern union { |
| 1386 | 1421 | .extern_options, |
| 1387 | 1422 | .manyptr_u8, |
| 1388 | 1423 | .manyptr_const_u8, |
| 1424 | .manyptr_const_u8_sentinel_0, | |
| 1389 | 1425 | .fn_noreturn_no_args, |
| 1390 | 1426 | .fn_void_no_args, |
| 1391 | 1427 | .fn_naked_noreturn_no_args, |
| 1392 | 1428 | .fn_ccc_void_no_args, |
| 1393 | 1429 | .const_slice_u8, |
| 1430 | .const_slice_u8_sentinel_0, | |
| 1394 | 1431 | .anyerror_void_error_union, |
| 1395 | 1432 | .empty_struct_literal, |
| 1396 | 1433 | .function, |
| ... | ... | @@ -1498,9 +1535,11 @@ pub const Type = extern union { |
| 1498 | 1535 | .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type), |
| 1499 | 1536 | .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), |
| 1500 | 1537 | .const_slice_u8 => return Value.initTag(.const_slice_u8_type), |
| 1538 | .const_slice_u8_sentinel_0 => return Value.initTag(.const_slice_u8_sentinel_0_type), | |
| 1501 | 1539 | .enum_literal => return Value.initTag(.enum_literal_type), |
| 1502 | 1540 | .manyptr_u8 => return Value.initTag(.manyptr_u8_type), |
| 1503 | 1541 | .manyptr_const_u8 => return Value.initTag(.manyptr_const_u8_type), |
| 1542 | .manyptr_const_u8_sentinel_0 => return Value.initTag(.manyptr_const_u8_sentinel_0_type), | |
| 1504 | 1543 | .atomic_order => return Value.initTag(.atomic_order_type), |
| 1505 | 1544 | .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type), |
| 1506 | 1545 | .calling_convention => return Value.initTag(.calling_convention_type), |
| ... | ... | @@ -1550,6 +1589,7 @@ pub const Type = extern union { |
| 1550 | 1589 | .anyerror, |
| 1551 | 1590 | .single_const_pointer_to_comptime_int, |
| 1552 | 1591 | .const_slice_u8, |
| 1592 | .const_slice_u8_sentinel_0, | |
| 1553 | 1593 | .array_u8_sentinel_0, |
| 1554 | 1594 | .optional, |
| 1555 | 1595 | .optional_single_mut_pointer, |
| ... | ... | @@ -1561,6 +1601,7 @@ pub const Type = extern union { |
| 1561 | 1601 | .error_set_merged, |
| 1562 | 1602 | .manyptr_u8, |
| 1563 | 1603 | .manyptr_const_u8, |
| 1604 | .manyptr_const_u8_sentinel_0, | |
| 1564 | 1605 | .atomic_order, |
| 1565 | 1606 | .atomic_rmw_op, |
| 1566 | 1607 | .calling_convention, |
| ... | ... | @@ -1703,7 +1744,9 @@ pub const Type = extern union { |
| 1703 | 1744 | |
| 1704 | 1745 | .manyptr_u8, |
| 1705 | 1746 | .manyptr_const_u8, |
| 1747 | .manyptr_const_u8_sentinel_0, | |
| 1706 | 1748 | .const_slice_u8, |
| 1749 | .const_slice_u8_sentinel_0, | |
| 1707 | 1750 | => return 1, |
| 1708 | 1751 | |
| 1709 | 1752 | .pointer => { |
| ... | ... | @@ -1723,6 +1766,7 @@ pub const Type = extern union { |
| 1723 | 1766 | return switch (self.tag()) { |
| 1724 | 1767 | .single_const_pointer_to_comptime_int, |
| 1725 | 1768 | .const_slice_u8, |
| 1769 | .const_slice_u8_sentinel_0, | |
| 1726 | 1770 | .single_const_pointer, |
| 1727 | 1771 | .single_mut_pointer, |
| 1728 | 1772 | .many_const_pointer, |
| ... | ... | @@ -1735,6 +1779,7 @@ pub const Type = extern union { |
| 1735 | 1779 | .inferred_alloc_mut, |
| 1736 | 1780 | .manyptr_u8, |
| 1737 | 1781 | .manyptr_const_u8, |
| 1782 | .manyptr_const_u8_sentinel_0, | |
| 1738 | 1783 | => .generic, |
| 1739 | 1784 | |
| 1740 | 1785 | .pointer => self.castTag(.pointer).?.data.@"addrspace", |
| ... | ... | @@ -1785,6 +1830,7 @@ pub const Type = extern union { |
| 1785 | 1830 | .usize, |
| 1786 | 1831 | .single_const_pointer_to_comptime_int, |
| 1787 | 1832 | .const_slice_u8, |
| 1833 | .const_slice_u8_sentinel_0, | |
| 1788 | 1834 | .single_const_pointer, |
| 1789 | 1835 | .single_mut_pointer, |
| 1790 | 1836 | .many_const_pointer, |
| ... | ... | @@ -1798,6 +1844,7 @@ pub const Type = extern union { |
| 1798 | 1844 | .pointer, |
| 1799 | 1845 | .manyptr_u8, |
| 1800 | 1846 | .manyptr_const_u8, |
| 1847 | .manyptr_const_u8_sentinel_0, | |
| 1801 | 1848 | .@"anyframe", |
| 1802 | 1849 | .anyframe_T, |
| 1803 | 1850 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8), |
| ... | ... | @@ -2050,7 +2097,9 @@ pub const Type = extern union { |
| 2050 | 2097 | if (self.elemType().hasCodeGenBits()) return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2; |
| 2051 | 2098 | return @divExact(target.cpu.arch.ptrBitWidth(), 8); |
| 2052 | 2099 | }, |
| 2053 | .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, | |
| 2100 | .const_slice_u8, | |
| 2101 | .const_slice_u8_sentinel_0, | |
| 2102 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, | |
| 2054 | 2103 | |
| 2055 | 2104 | .optional_single_const_pointer, |
| 2056 | 2105 | .optional_single_mut_pointer, |
| ... | ... | @@ -2068,6 +2117,7 @@ pub const Type = extern union { |
| 2068 | 2117 | .pointer, |
| 2069 | 2118 | .manyptr_u8, |
| 2070 | 2119 | .manyptr_const_u8, |
| 2120 | .manyptr_const_u8_sentinel_0, | |
| 2071 | 2121 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8), |
| 2072 | 2122 | |
| 2073 | 2123 | .c_short => return @divExact(CType.short.sizeInBits(target), 8), |
| ... | ... | @@ -2223,7 +2273,9 @@ pub const Type = extern union { |
| 2223 | 2273 | return target.cpu.arch.ptrBitWidth(); |
| 2224 | 2274 | } |
| 2225 | 2275 | }, |
| 2226 | .const_slice_u8 => target.cpu.arch.ptrBitWidth() * 2, | |
| 2276 | .const_slice_u8, | |
| 2277 | .const_slice_u8_sentinel_0, | |
| 2278 | => target.cpu.arch.ptrBitWidth() * 2, | |
| 2227 | 2279 | |
| 2228 | 2280 | .optional_single_const_pointer, |
| 2229 | 2281 | .optional_single_mut_pointer, |
| ... | ... | @@ -2252,6 +2304,7 @@ pub const Type = extern union { |
| 2252 | 2304 | |
| 2253 | 2305 | .manyptr_u8, |
| 2254 | 2306 | .manyptr_const_u8, |
| 2307 | .manyptr_const_u8_sentinel_0, | |
| 2255 | 2308 | => return target.cpu.arch.ptrBitWidth(), |
| 2256 | 2309 | |
| 2257 | 2310 | .c_short => return CType.short.sizeInBits(target), |
| ... | ... | @@ -2337,12 +2390,14 @@ pub const Type = extern union { |
| 2337 | 2390 | .const_slice, |
| 2338 | 2391 | .mut_slice, |
| 2339 | 2392 | .const_slice_u8, |
| 2393 | .const_slice_u8_sentinel_0, | |
| 2340 | 2394 | => .Slice, |
| 2341 | 2395 | |
| 2342 | 2396 | .many_const_pointer, |
| 2343 | 2397 | .many_mut_pointer, |
| 2344 | 2398 | .manyptr_u8, |
| 2345 | 2399 | .manyptr_const_u8, |
| 2400 | .manyptr_const_u8_sentinel_0, | |
| 2346 | 2401 | => .Many, |
| 2347 | 2402 | |
| 2348 | 2403 | .c_const_pointer, |
| ... | ... | @@ -2367,6 +2422,7 @@ pub const Type = extern union { |
| 2367 | 2422 | .const_slice, |
| 2368 | 2423 | .mut_slice, |
| 2369 | 2424 | .const_slice_u8, |
| 2425 | .const_slice_u8_sentinel_0, | |
| 2370 | 2426 | => true, |
| 2371 | 2427 | |
| 2372 | 2428 | .pointer => self.castTag(.pointer).?.data.size == .Slice, |
| ... | ... | @@ -2383,6 +2439,7 @@ pub const Type = extern union { |
| 2383 | 2439 | pub fn slicePtrFieldType(self: Type, buffer: *SlicePtrFieldTypeBuffer) Type { |
| 2384 | 2440 | switch (self.tag()) { |
| 2385 | 2441 | .const_slice_u8 => return Type.initTag(.manyptr_const_u8), |
| 2442 | .const_slice_u8_sentinel_0 => return Type.initTag(.manyptr_const_u8_sentinel_0), | |
| 2386 | 2443 | |
| 2387 | 2444 | .const_slice => { |
| 2388 | 2445 | const elem_type = self.castTag(.const_slice).?.data; |
| ... | ... | @@ -2464,8 +2521,10 @@ pub const Type = extern union { |
| 2464 | 2521 | .c_const_pointer, |
| 2465 | 2522 | .single_const_pointer_to_comptime_int, |
| 2466 | 2523 | .const_slice_u8, |
| 2524 | .const_slice_u8_sentinel_0, | |
| 2467 | 2525 | .const_slice, |
| 2468 | 2526 | .manyptr_const_u8, |
| 2527 | .manyptr_const_u8_sentinel_0, | |
| 2469 | 2528 | => true, |
| 2470 | 2529 | |
| 2471 | 2530 | .pointer => !self.castTag(.pointer).?.data.mutable, |
| ... | ... | @@ -2513,6 +2572,7 @@ pub const Type = extern union { |
| 2513 | 2572 | .many_const_pointer, |
| 2514 | 2573 | .many_mut_pointer, |
| 2515 | 2574 | .manyptr_const_u8, |
| 2575 | .manyptr_const_u8_sentinel_0, | |
| 2516 | 2576 | .manyptr_u8, |
| 2517 | 2577 | .optional_single_const_pointer, |
| 2518 | 2578 | .optional_single_mut_pointer, |
| ... | ... | @@ -2648,9 +2708,11 @@ pub const Type = extern union { |
| 2648 | 2708 | .array_u8, |
| 2649 | 2709 | .array_u8_sentinel_0, |
| 2650 | 2710 | .const_slice_u8, |
| 2711 | .const_slice_u8_sentinel_0, | |
| 2651 | 2712 | .manyptr_u8, |
| 2652 | 2713 | .manyptr_const_u8, |
| 2653 | => Type.initTag(.u8), | |
| 2714 | .manyptr_const_u8_sentinel_0, | |
| 2715 | => Type.u8, | |
| 2654 | 2716 | |
| 2655 | 2717 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), |
| 2656 | 2718 | .pointer => ty.castTag(.pointer).?.data.pointee_type, |
| ... | ... | @@ -2690,9 +2752,11 @@ pub const Type = extern union { |
| 2690 | 2752 | .array_u8, |
| 2691 | 2753 | .array_u8_sentinel_0, |
| 2692 | 2754 | .const_slice_u8, |
| 2755 | .const_slice_u8_sentinel_0, | |
| 2693 | 2756 | .manyptr_u8, |
| 2694 | 2757 | .manyptr_const_u8, |
| 2695 | => Type.initTag(.u8), | |
| 2758 | .manyptr_const_u8_sentinel_0, | |
| 2759 | => Type.u8, | |
| 2696 | 2760 | |
| 2697 | 2761 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), |
| 2698 | 2762 | .pointer => { |
| ... | ... | @@ -2937,7 +3001,11 @@ pub const Type = extern union { |
| 2937 | 3001 | |
| 2938 | 3002 | .pointer => return self.castTag(.pointer).?.data.sentinel, |
| 2939 | 3003 | .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel, |
| 2940 | .array_u8_sentinel_0 => return Value.zero, | |
| 3004 | ||
| 3005 | .array_u8_sentinel_0, | |
| 3006 | .const_slice_u8_sentinel_0, | |
| 3007 | .manyptr_const_u8_sentinel_0, | |
| 3008 | => return Value.zero, | |
| 2941 | 3009 | |
| 2942 | 3010 | else => unreachable, |
| 2943 | 3011 | }; |
| ... | ... | @@ -3309,6 +3377,7 @@ pub const Type = extern union { |
| 3309 | 3377 | .array_sentinel, |
| 3310 | 3378 | .array_u8_sentinel_0, |
| 3311 | 3379 | .const_slice_u8, |
| 3380 | .const_slice_u8_sentinel_0, | |
| 3312 | 3381 | .const_slice, |
| 3313 | 3382 | .mut_slice, |
| 3314 | 3383 | .anyopaque, |
| ... | ... | @@ -3326,6 +3395,7 @@ pub const Type = extern union { |
| 3326 | 3395 | .var_args_param, |
| 3327 | 3396 | .manyptr_u8, |
| 3328 | 3397 | .manyptr_const_u8, |
| 3398 | .manyptr_const_u8_sentinel_0, | |
| 3329 | 3399 | .atomic_order, |
| 3330 | 3400 | .atomic_rmw_op, |
| 3331 | 3401 | .calling_convention, |
| ... | ... | @@ -3956,12 +4026,14 @@ pub const Type = extern union { |
| 3956 | 4026 | type_info, |
| 3957 | 4027 | manyptr_u8, |
| 3958 | 4028 | manyptr_const_u8, |
| 4029 | manyptr_const_u8_sentinel_0, | |
| 3959 | 4030 | fn_noreturn_no_args, |
| 3960 | 4031 | fn_void_no_args, |
| 3961 | 4032 | fn_naked_noreturn_no_args, |
| 3962 | 4033 | fn_ccc_void_no_args, |
| 3963 | 4034 | single_const_pointer_to_comptime_int, |
| 3964 | 4035 | const_slice_u8, |
| 4036 | const_slice_u8_sentinel_0, | |
| 3965 | 4037 | anyerror_void_error_union, |
| 3966 | 4038 | generic_poison, |
| 3967 | 4039 | /// This is a special type for variadic parameters of a function call. |
| ... | ... | @@ -4064,6 +4136,7 @@ pub const Type = extern union { |
| 4064 | 4136 | .single_const_pointer_to_comptime_int, |
| 4065 | 4137 | .anyerror_void_error_union, |
| 4066 | 4138 | .const_slice_u8, |
| 4139 | .const_slice_u8_sentinel_0, | |
| 4067 | 4140 | .generic_poison, |
| 4068 | 4141 | .inferred_alloc_const, |
| 4069 | 4142 | .inferred_alloc_mut, |
| ... | ... | @@ -4071,6 +4144,7 @@ pub const Type = extern union { |
| 4071 | 4144 | .empty_struct_literal, |
| 4072 | 4145 | .manyptr_u8, |
| 4073 | 4146 | .manyptr_const_u8, |
| 4147 | .manyptr_const_u8_sentinel_0, | |
| 4074 | 4148 | .atomic_order, |
| 4075 | 4149 | .atomic_rmw_op, |
| 4076 | 4150 | .calling_convention, |
| ... | ... | @@ -4322,36 +4396,55 @@ pub const Type = extern union { |
| 4322 | 4396 | |
| 4323 | 4397 | pub fn ptr(arena: Allocator, d: Payload.Pointer.Data) !Type { |
| 4324 | 4398 | assert(d.host_size == 0 or d.bit_offset < d.host_size * 8); |
| 4399 | if (d.size == .C) { | |
| 4400 | assert(d.@"allowzero"); // All C pointers must set allowzero to true. | |
| 4401 | } | |
| 4325 | 4402 | |
| 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") | |
| 4328 | 4405 | { |
| 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); | |
| 4331 | 4445 | } |
| 4332 | return Type.Tag.pointer.create(arena, d); | |
| 4333 | } | |
| 4334 | ||
| 4335 | if (!d.mutable and d.size == .Slice and d.pointee_type.eql(Type.initTag(.u8))) { | |
| 4336 | return Type.initTag(.const_slice_u8); | |
| 4337 | 4446 | } |
| 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); | |
| 4355 | 4448 | } |
| 4356 | 4449 | |
| 4357 | 4450 | pub fn array( |
src/value.zig+10| ... | ... | @@ -73,12 +73,14 @@ pub const Value = extern union { |
| 73 | 73 | type_info_type, |
| 74 | 74 | manyptr_u8_type, |
| 75 | 75 | manyptr_const_u8_type, |
| 76 | manyptr_const_u8_sentinel_0_type, | |
| 76 | 77 | fn_noreturn_no_args_type, |
| 77 | 78 | fn_void_no_args_type, |
| 78 | 79 | fn_naked_noreturn_no_args_type, |
| 79 | 80 | fn_ccc_void_no_args_type, |
| 80 | 81 | single_const_pointer_to_comptime_int_type, |
| 81 | 82 | const_slice_u8_type, |
| 83 | const_slice_u8_sentinel_0_type, | |
| 82 | 84 | anyerror_void_error_union_type, |
| 83 | 85 | generic_poison_type, |
| 84 | 86 | |
| ... | ... | @@ -221,6 +223,7 @@ pub const Value = extern union { |
| 221 | 223 | .single_const_pointer_to_comptime_int_type, |
| 222 | 224 | .anyframe_type, |
| 223 | 225 | .const_slice_u8_type, |
| 226 | .const_slice_u8_sentinel_0_type, | |
| 224 | 227 | .anyerror_void_error_union_type, |
| 225 | 228 | .generic_poison_type, |
| 226 | 229 | .enum_literal_type, |
| ... | ... | @@ -238,6 +241,7 @@ pub const Value = extern union { |
| 238 | 241 | .abi_align_default, |
| 239 | 242 | .manyptr_u8_type, |
| 240 | 243 | .manyptr_const_u8_type, |
| 244 | .manyptr_const_u8_sentinel_0_type, | |
| 241 | 245 | .atomic_order_type, |
| 242 | 246 | .atomic_rmw_op_type, |
| 243 | 247 | .calling_convention_type, |
| ... | ... | @@ -412,6 +416,7 @@ pub const Value = extern union { |
| 412 | 416 | .single_const_pointer_to_comptime_int_type, |
| 413 | 417 | .anyframe_type, |
| 414 | 418 | .const_slice_u8_type, |
| 419 | .const_slice_u8_sentinel_0_type, | |
| 415 | 420 | .anyerror_void_error_union_type, |
| 416 | 421 | .generic_poison_type, |
| 417 | 422 | .enum_literal_type, |
| ... | ... | @@ -429,6 +434,7 @@ pub const Value = extern union { |
| 429 | 434 | .abi_align_default, |
| 430 | 435 | .manyptr_u8_type, |
| 431 | 436 | .manyptr_const_u8_type, |
| 437 | .manyptr_const_u8_sentinel_0_type, | |
| 432 | 438 | .atomic_order_type, |
| 433 | 439 | .atomic_rmw_op_type, |
| 434 | 440 | .calling_convention_type, |
| ... | ... | @@ -642,12 +648,14 @@ pub const Value = extern union { |
| 642 | 648 | .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), |
| 643 | 649 | .anyframe_type => return out_stream.writeAll("anyframe"), |
| 644 | 650 | .const_slice_u8_type => return out_stream.writeAll("[]const u8"), |
| 651 | .const_slice_u8_sentinel_0_type => return out_stream.writeAll("[:0]const u8"), | |
| 645 | 652 | .anyerror_void_error_union_type => return out_stream.writeAll("anyerror!void"), |
| 646 | 653 | .generic_poison_type => return out_stream.writeAll("(generic poison type)"), |
| 647 | 654 | .generic_poison => return out_stream.writeAll("(generic poison)"), |
| 648 | 655 | .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"), |
| 649 | 656 | .manyptr_u8_type => return out_stream.writeAll("[*]u8"), |
| 650 | 657 | .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"), |
| 658 | .manyptr_const_u8_sentinel_0_type => return out_stream.writeAll("[*:0]const u8"), | |
| 651 | 659 | .atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"), |
| 652 | 660 | .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"), |
| 653 | 661 | .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"), |
| ... | ... | @@ -821,11 +829,13 @@ pub const Value = extern union { |
| 821 | 829 | .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int), |
| 822 | 830 | .anyframe_type => Type.initTag(.@"anyframe"), |
| 823 | 831 | .const_slice_u8_type => Type.initTag(.const_slice_u8), |
| 832 | .const_slice_u8_sentinel_0_type => Type.initTag(.const_slice_u8_sentinel_0), | |
| 824 | 833 | .anyerror_void_error_union_type => Type.initTag(.anyerror_void_error_union), |
| 825 | 834 | .generic_poison_type => Type.initTag(.generic_poison), |
| 826 | 835 | .enum_literal_type => Type.initTag(.enum_literal), |
| 827 | 836 | .manyptr_u8_type => Type.initTag(.manyptr_u8), |
| 828 | 837 | .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8), |
| 838 | .manyptr_const_u8_sentinel_0_type => Type.initTag(.manyptr_const_u8_sentinel_0), | |
| 829 | 839 | .atomic_order_type => Type.initTag(.atomic_order), |
| 830 | 840 | .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op), |
| 831 | 841 | .calling_convention_type => Type.initTag(.calling_convention), |
test/behavior.zig+1| ... | ... | @@ -75,6 +75,7 @@ test { |
| 75 | 75 | _ = @import("behavior/bugs/3112.zig"); |
| 76 | 76 | _ = @import("behavior/bugs/7250.zig"); |
| 77 | 77 | _ = @import("behavior/cast_llvm.zig"); |
| 78 | _ = @import("behavior/enum_llvm.zig"); | |
| 78 | 79 | _ = @import("behavior/eval.zig"); |
| 79 | 80 | _ = @import("behavior/floatop.zig"); |
| 80 | 81 | _ = @import("behavior/fn.zig"); |
test/behavior/enum.zig+123| ... | ... | @@ -699,3 +699,126 @@ test "single field non-exhaustive enum" { |
| 699 | 699 | try S.doTheTest(23); |
| 700 | 700 | comptime try S.doTheTest(23); |
| 701 | 701 | } |
| 702 | ||
| 703 | const EnumWithTagValues = enum(u4) { | |
| 704 | A = 1 << 0, | |
| 705 | B = 1 << 1, | |
| 706 | C = 1 << 2, | |
| 707 | D = 1 << 3, | |
| 708 | }; | |
| 709 | test "enum with tag values don't require parens" { | |
| 710 | try expect(@enumToInt(EnumWithTagValues.C) == 0b0100); | |
| 711 | } | |
| 712 | ||
| 713 | const 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 | ||
| 725 | test "cast integer literal to enum" { | |
| 726 | try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); | |
| 727 | try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); | |
| 728 | } | |
| 729 | ||
| 730 | test "enum with specified and unspecified tag values" { | |
| 731 | try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | |
| 732 | comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | |
| 733 | } | |
| 734 | ||
| 735 | fn 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 | ||
| 750 | const Small2 = enum(u2) { One, Two }; | |
| 751 | const Small = enum(u2) { One, Two, Three, Four }; | |
| 752 | ||
| 753 | test "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 | ||
| 766 | test "casting enum to its tag type" { | |
| 767 | try testCastEnumTag(Small2.Two); | |
| 768 | comptime try testCastEnumTag(Small2.Two); | |
| 769 | } | |
| 770 | ||
| 771 | fn testCastEnumTag(value: Small2) !void { | |
| 772 | try expect(@enumToInt(value) == 1); | |
| 773 | } | |
| 774 | ||
| 775 | test "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 | ||
| 782 | test "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 | ||
| 794 | test "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 | ||
| 805 | test "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 | ||
| 812 | test "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 | ||
| 821 | test "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 @@ |
| 1 | const std = @import("std"); | |
| 2 | const expect = std.testing.expect; | |
| 3 | const mem = std.mem; | |
| 4 | const Tag = std.meta.Tag; | |
| 5 | ||
| 6 | test "@tagName" { | |
| 7 | try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | |
| 8 | comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | |
| 9 | } | |
| 10 | ||
| 11 | fn testEnumTagNameBare(n: anytype) []const u8 { | |
| 12 | return @tagName(n); | |
| 13 | } | |
| 14 | ||
| 15 | const BareNumber = enum { One, Two, Three }; | |
| 16 | ||
| 17 | test "@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 | } | |
| 21 | const NonExhaustive = enum(u8) { A, B, _ }; | |
| 22 | ||
| 23 | test "@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 | ||
| 33 | test "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 | ||
| 42 | const Bar = enum { A, B, C, D }; | |
| 43 | ||
| 44 | test "enum literal casting to optional" { | |
| 45 | var bar: ?Bar = undefined; | |
| 46 | bar = .B; | |
| 47 | ||
| 48 | try expect(bar.? == Bar.B); | |
| 49 | } |
test/behavior/enum_stage1.zig-151| ... | ... | @@ -2,47 +2,7 @@ const expect = @import("std").testing.expect; |
| 2 | 2 | const mem = @import("std").mem; |
| 3 | 3 | const Tag = @import("std").meta.Tag; |
| 4 | 4 | |
| 5 | test "@tagName" { | |
| 6 | try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | |
| 7 | comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); | |
| 8 | } | |
| 9 | ||
| 10 | test "@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 | ||
| 15 | test "@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 | ||
| 25 | fn testEnumTagNameBare(n: anytype) []const u8 { | |
| 26 | return @tagName(n); | |
| 27 | } | |
| 28 | ||
| 29 | const BareNumber = enum { One, Two, Three }; | |
| 30 | const NonExhaustive = enum(u8) { A, B, _ }; | |
| 31 | 5 | const Small2 = enum(u2) { One, Two }; |
| 32 | const Small = enum(u2) { One, Two, Three, Four }; | |
| 33 | ||
| 34 | test "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 | } | |
| 46 | 6 | |
| 47 | 7 | const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 }; |
| 48 | 8 | const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 }; |
| ... | ... | @@ -87,15 +47,6 @@ fn getC(data: *const BitFieldOfEnums) C { |
| 87 | 47 | return data.c; |
| 88 | 48 | } |
| 89 | 49 | |
| 90 | test "casting enum to its tag type" { | |
| 91 | try testCastEnumTag(Small2.Two); | |
| 92 | comptime try testCastEnumTag(Small2.Two); | |
| 93 | } | |
| 94 | ||
| 95 | fn testCastEnumTag(value: Small2) !void { | |
| 96 | try expect(@enumToInt(value) == 1); | |
| 97 | } | |
| 98 | ||
| 99 | 50 | const MultipleChoice2 = enum(u32) { |
| 100 | 51 | Unspecified1, |
| 101 | 52 | A = 20, |
| ... | ... | @@ -108,31 +59,6 @@ const MultipleChoice2 = enum(u32) { |
| 108 | 59 | Unspecified5, |
| 109 | 60 | }; |
| 110 | 61 | |
| 111 | test "enum with specified and unspecified tag values" { | |
| 112 | try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | |
| 113 | comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | |
| 114 | } | |
| 115 | ||
| 116 | fn 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 | ||
| 131 | test "cast integer literal to enum" { | |
| 132 | try expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); | |
| 133 | try expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); | |
| 134 | } | |
| 135 | ||
| 136 | 62 | const EnumWithOneMember = enum { Eof }; |
| 137 | 63 | |
| 138 | 64 | fn doALoopThing(id: EnumWithOneMember) void { |
| ... | ... | @@ -157,32 +83,6 @@ test "switch on enum with one member is comptime known" { |
| 157 | 83 | @compileError("analysis should not reach here"); |
| 158 | 84 | } |
| 159 | 85 | |
| 160 | const EnumWithTagValues = enum(u4) { | |
| 161 | A = 1 << 0, | |
| 162 | B = 1 << 1, | |
| 163 | C = 1 << 2, | |
| 164 | D = 1 << 3, | |
| 165 | }; | |
| 166 | test "enum with tag values don't require parens" { | |
| 167 | try expect(@enumToInt(EnumWithTagValues.C) == 0b0100); | |
| 168 | } | |
| 169 | ||
| 170 | test "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 | ||
| 177 | test "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 | ||
| 186 | 86 | test "enum literal in array literal" { |
| 187 | 87 | const Items = enum { one, two }; |
| 188 | 88 | const array = [_]Items{ .one, .two }; |
| ... | ... | @@ -191,18 +91,6 @@ test "enum literal in array literal" { |
| 191 | 91 | try expect(array[1] == .two); |
| 192 | 92 | } |
| 193 | 93 | |
| 194 | test "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 | ||
| 206 | 94 | test "enum value allocation" { |
| 207 | 95 | const LargeEnum = enum(u32) { |
| 208 | 96 | A0 = 0x80000000, |
| ... | ... | @@ -235,26 +123,8 @@ test "enum literal casting to tagged union" { |
| 235 | 123 | } |
| 236 | 124 | } |
| 237 | 125 | |
| 238 | test "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 | ||
| 249 | 126 | const Bar = enum { A, B, C, D }; |
| 250 | 127 | |
| 251 | test "enum literal casting to optional" { | |
| 252 | var bar: ?Bar = undefined; | |
| 253 | bar = .B; | |
| 254 | ||
| 255 | try expect(bar.? == Bar.B); | |
| 256 | } | |
| 257 | ||
| 258 | 128 | test "enum literal casting to error union with payload enum" { |
| 259 | 129 | var bar: error{B}!Bar = undefined; |
| 260 | 130 | bar = .B; // should never cast to the error set |
| ... | ... | @@ -262,27 +132,6 @@ test "enum literal casting to error union with payload enum" { |
| 262 | 132 | try expect((try bar) == Bar.B); |
| 263 | 133 | } |
| 264 | 134 | |
| 265 | test "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 | ||
| 272 | test "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 | ||
| 281 | test "enum with one member default to u0 tag type" { | |
| 282 | const E0 = enum { X }; | |
| 283 | comptime try expect(Tag(E0) == u0); | |
| 284 | } | |
| 285 | ||
| 286 | 135 | test "tagName on enum literals" { |
| 287 | 136 | try expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); |
| 288 | 137 | comptime try expect(mem.eql(u8, @tagName(.FooBar), "FooBar")); |