| ... | @@ -187,7 +187,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -187,7 +187,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 187 | | 187 | |
| 188 | fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 188 | fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 189 | const air_tags = cg.air.instructions.items(.tag); | 189 | const air_tags = cg.air.instructions.items(.tag); |
| 190 | return switch (air_tags[@intFromEnum(inst)]) { | 190 | return switch (air_tags[@backingInt(inst)]) { |
| 191 | .inferred_alloc, .inferred_alloc_comptime => unreachable, | 191 | .inferred_alloc, .inferred_alloc_comptime => unreachable, |
| 192 | | 192 | |
| 193 | .add, | 193 | .add, |
| ... | @@ -431,7 +431,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -431,7 +431,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 431 | .legalize_vec_store_elem, | 431 | .legalize_vec_store_elem, |
| 432 | .legalize_vec_elem_val, | 432 | .legalize_vec_elem_val, |
| 433 | .legalize_compiler_rt_call, | 433 | .legalize_compiler_rt_call, |
| 434 | => |tag| return cg.fail("TODO: implement spork8 inst: {s}", .{@tagName(tag)}), | 434 | => |tag| return cg.fail("TODO: implement spork8 inst: {t}", .{tag}), |
| 435 | | 435 | |
| 436 | .unreach => cg.airUnreachable(inst), | 436 | .unreach => cg.airUnreachable(inst), |
| 437 | .assembly => cg.airAssembly(inst), | 437 | .assembly => cg.airAssembly(inst), |
| ... | @@ -473,21 +473,21 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -473,21 +473,21 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 473 | while (it.next()) |input| { | 473 | while (it.next()) |input| { |
| 474 | const constraint = input.constraint; | 474 | const constraint = input.constraint; |
| 475 | if (!mem.eql(u8, constraint, "I")) { | 475 | if (!mem.eql(u8, constraint, "I")) { |
| 476 | return cg.fail("Assembly constraint {q} not supported", .{constraint}); | 476 | return cg.fail("assembly constraint {q} not supported", .{constraint}); |
| 477 | } | 477 | } |
| 478 | const operand = input.operand.toInterned() orelse { | 478 | const operand = input.operand.toInterned() orelse { |
| 479 | return cg.fail("Immediate argument to inline assembly must be compile-time value", .{}); | 479 | return cg.fail("immediate argument to inline assembly must be compile-time value", .{}); |
| 480 | }; | 480 | }; |
| 481 | const name = input.name; | 481 | const name = input.name; |
| 482 | | 482 | |
| 483 | const value = switch (zcu.intern_pool.indexToKey(operand)) { | 483 | const value = switch (zcu.intern_pool.indexToKey(operand)) { |
| 484 | .int => |val| v: { | 484 | .int => |val| v: { |
| 485 | if (val.ty != .u8_type) { | 485 | if (val.ty != .u8_type) { |
| 486 | return cg.fail("Non-u8 type used in inline assembly value: {}", .{val.ty}); | 486 | return cg.fail("non-u8 type used in inline assembly value: {}", .{val.ty}); |
| 487 | } | 487 | } |
| 488 | break :v val.storage.u64; | 488 | break :v val.storage.u64; |
| 489 | }, | 489 | }, |
| 490 | else => return cg.fail("Non-int operands not supported", .{}), | 490 | else => return cg.fail("non-int operands not supported", .{}), |
| 491 | }; | 491 | }; |
| 492 | | 492 | |
| 493 | try constValues.put(zcu.gpa, name, @intCast(value)); | 493 | try constValues.put(zcu.gpa, name, @intCast(value)); |
| ... | @@ -500,18 +500,19 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -500,18 +500,19 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 500 | var tokens = mem.tokenizeScalar(u8, line, ' '); | 500 | var tokens = mem.tokenizeScalar(u8, line, ' '); |
| 501 | // If there's no tokens, then it must be a blank line, so just skip it. | 501 | // If there's no tokens, then it must be a blank line, so just skip it. |
| 502 | const op = tokens.next() orelse continue; | 502 | const op = tokens.next() orelse continue; |
| 503 | const instType = std.meta.stringToEnum(AsmInstType, op) orelse return cg.fail("Invalid asm instruction: {q}", .{op}); | 503 | const instType = std.meta.stringToEnum(AsmInstType, op) orelse return cg.fail("invalid asm instruction: {q}", .{op}); |
| 504 | switch (instType) { | 504 | switch (instType) { |
| 505 | .LoadI => { | 505 | .LoadI => { |
| 506 | const registerString = tokens.next() orelse return cg.fail("Missing register for LoadI instruction", .{}); | 506 | const registerString = tokens.next() orelse return cg.fail("missing register for LoadI instruction", .{}); |
| 507 | const register = std.meta.stringToEnum(Register, registerString) orelse return cg.fail("Invalid register: {q}", .{registerString}); | 507 | const register = std.meta.stringToEnum(Register, registerString) orelse return cg.fail("invalid register: {q}", .{registerString}); |
| 508 | const value = tokens.next() orelse return cg.fail("Missing immediate value for LoadI", .{}); | 508 | const value = tokens.next() orelse return cg.fail("missing immediate value for LoadI", .{}); |
| 509 | const intValue = v: { | 509 | const intValue = v: { |
| 510 | if (mem.startsWith(u8, value, "%[")) { | 510 | if (mem.startsWith(u8, value, "%[")) { |
| 511 | const name = value[2 .. value.len - 1]; | 511 | const name = value[2 .. value.len - 1]; |
| 512 | break :v constValues.get(name) orelse return cg.fail("Constraint name {q} not included in constraints for inline asm", .{name}); | 512 | break :v constValues.get(name) orelse return cg.fail("constraint name {q} not included in constraints for inline asm", .{name}); |
| 513 | } else { | 513 | } else { |
| 514 | break :v std.fmt.parseInt(u8, value, 0) catch return cg.fail("Couldn't parse u8 from LoadI immediate value", .{}); | 514 | break :v std.fmt.parseInt(u8, value, 0) catch |err| |
| | 515 | return cg.fail("invalid LoadI immediate value: {t}", .{err}); |
| 515 | } | 516 | } |
| 516 | }; | 517 | }; |
| 517 | if (register != .OutA) { | 518 | if (register != .OutA) { |
| ... | @@ -548,62 +549,118 @@ fn extraLen(cg: *const CodeGen) u32 { | ... | @@ -548,62 +549,118 @@ fn extraLen(cg: *const CodeGen) u32 { |
| 548 | } | 549 | } |
| 549 | | 550 | |
| 550 | const AsmInstType = enum(u8) { | 551 | const AsmInstType = enum(u8) { |
| 551 | SetPageReg, // Set the memory address high byte to a register value. | 552 | /// Set the memory address high byte to a register value. |
| 552 | SetPageI, // Set the memory address high byte to a constant value. | 553 | SetPageReg, |
| 553 | SetAddrReg, // Set the memory address low byte to a register value. | 554 | /// Set the memory address high byte to a constant value. |
| 554 | SetAddrI, // Set the memory address low byte to a constant value. | 555 | SetPageI, |
| 555 | Load, // Load a value from a constant address into a register. | 556 | /// Set the memory address low byte to a register value. |
| 556 | LoadI, // Load a constant value into a register. | 557 | SetAddrReg, |
| 557 | LoadP, // Load a value from a constant address (setting low byte only) into a register. | 558 | /// Set the memory address low byte to a constant value. |
| 558 | LoadInc, // Load a value from the currently set memory address into a register, and increment the address n times. | 559 | SetAddrI, |
| 559 | LoadStck, // Load a value from an offset on the current stack frame into a register. | 560 | /// Load a value from a constant address into a register. |
| 560 | Store, // Store a value to a constant address from a register. | 561 | Load, |
| 561 | StoreI, // Store a constant value into a constant address. | 562 | /// Load a constant value into a register. |
| 562 | StoreP, // Store a value to a constant address (low byte only) from a register. | 563 | LoadI, |
| 563 | StoreInc, // Store a value from the currently set memory address from a register, and increment the address n times. | 564 | /// Load a value from a constant address (setting low byte only) into a register. |
| 564 | StoreStck, // Store a value to an offset on the current stack frame, from a register. | 565 | LoadP, |
| 565 | StoreNStck, // Store a value to an offset on the next stack frame, from a register. | 566 | /// Load a value from the currently set memory address into a register, and increment the address n times. |
| 566 | StorePStck, // Store a value to an offset on the previous stack frame, from a register. | 567 | LoadInc, |
| 567 | StoreStckI, // Store a constant value to an offset on the current stack frame. | 568 | /// Load a value from an offset on the current stack frame into a register. |
| 568 | StoreNStckI, // Store a constant value to an offset on the next stack frame. | 569 | LoadStck, |
| 569 | StorePStckI, // Store a constant value to an offset on the previous stack frame. | 570 | /// Store a value to a constant address from a register. |
| 570 | Copy, // Copy a value from one register to another register. | 571 | Store, |
| 571 | Jump, // Jump to a constant location. | 572 | /// Store a constant value into a constant address. |
| 572 | JumpReg, // Jump to a register A (high byte) + register B (low byte). | 573 | StoreI, |
| 573 | JumpMem, // Jump to a location pointed to by memory at the current memory address (high byte first). | 574 | /// Store a value to a constant address (low byte only) from a register. |
| 574 | Call, // Call a function. | 575 | StoreP, |
| 575 | Return, // Return from a function. | 576 | /// Store a value from the currently set memory address from a register, and increment the address n times. |
| 576 | CmpI, // Compare A to a constant value (sets flags, but discards result). | 577 | StoreInc, |
| 577 | CmpAndI, // Compare A to a constant value with bitwise AND (sets flags, but discards result). | 578 | /// Store a value to an offset on the current stack frame, from a register. |
| 578 | Cmp, // Compare A to a value from memory (sets flags, but discards result). | 579 | StoreStck, |
| 579 | CmpAnd, // Compare A to a value in memory with bitwise AND (sets flags, but discards result). | 580 | /// Store a value to an offset on the next stack frame, from a register. |
| 580 | CmpReg, // Compare A to a value from a register (sets flags, but discards result). | 581 | StoreNStck, |
| 581 | CmpAndReg, // Compare A to a value from a register with bitwise AND (sets flags, but discards result). | 582 | /// Store a value to an offset on the previous stack frame, from a register. |
| 582 | ShiftL, // Shift B left by 1. | 583 | StorePStck, |
| 583 | ShiftR, // Shift B right by 1. | 584 | /// Store a constant value to an offset on the current stack frame. |
| 584 | RotateL, // Rotate B left by 1. | 585 | StoreStckI, |
| 585 | RotateR, // Rotate B right by 1. | 586 | /// Store a constant value to an offset on the next stack frame. |
| 586 | AddI, // Add a constant value to A. | 587 | StoreNStckI, |
| 587 | SubI, // Subtract a constant value from A. | 588 | /// Store a constant value to an offset on the previous stack frame. |
| 588 | AndI, // Bitwise-AND A with a constant value. | 589 | StorePStckI, |
| 589 | AddINF, // Add a constant value to A, without updating flags. | 590 | /// Copy a value from one register to another register. |
| 590 | SubINF, // Subtract a constant value from A, without updating flags. | 591 | Copy, |
| 591 | AndINF, // Bitwise-AND A with a constant value, without updating flags. | 592 | /// Jump to a constant location. |
| 592 | AccumulateAdd, // Add register B to A -> A. | 593 | Jump, |
| 593 | AccumulateSub, // Subtract register B from A -> A. | 594 | /// Jump to a register A (high byte) + register B (low byte). |
| 594 | AccumulateAnd, // A & B -> A. | 595 | JumpReg, |
| 595 | OrI, // Bitwise OR B with A -> A. | 596 | /// Jump to a location pointed to by memory at the current memory address (high byte first). |
| 596 | XorI, // Bitwise OR a constant value with A -> A. | 597 | JumpMem, |
| 597 | Not, // Invert register A. | 598 | /// Call a function. |
| 598 | Add, // Add a value from memory to A. | 599 | Call, |
| 599 | Sub, // Subtract a value from memory from A. | 600 | /// Return from a function. |
| 600 | And, // AND A with a value from memory. | 601 | Return, |
| 601 | Or, // OR A with a value from memory. | 602 | /// Compare A to a constant value (sets flags, but discards result). |
| 602 | Xor, // XOR A with a value from memory. | 603 | CmpI, |
| 603 | Nop, // No-op. | 604 | /// Compare A to a constant value with bitwise AND (sets flags, but discards result). |
| 604 | Nop1, // No-op with 1 extra clock cycle. | 605 | CmpAndI, |
| 605 | Nop2, // No-op with 2 extra clock cycles. | 606 | /// Compare A to a value from memory (sets flags, but discards result). |
| 606 | Halt, // Halt - stop the program forever (until reset). | 607 | Cmp, |
| | 608 | /// Compare A to a value in memory with bitwise AND (sets flags, but discards result). |
| | 609 | CmpAnd, |
| | 610 | /// Compare A to a value from a register (sets flags, but discards result). |
| | 611 | CmpReg, |
| | 612 | /// Compare A to a value from a register with bitwise AND (sets flags, but discards result). |
| | 613 | CmpAndReg, |
| | 614 | /// Shift B left by 1. |
| | 615 | ShiftL, |
| | 616 | /// Shift B right by 1. |
| | 617 | ShiftR, |
| | 618 | /// Rotate B left by 1. |
| | 619 | RotateL, |
| | 620 | /// Rotate B right by 1. |
| | 621 | RotateR, |
| | 622 | /// Add a constant value to A. |
| | 623 | AddI, |
| | 624 | /// Subtract a constant value from A. |
| | 625 | SubI, |
| | 626 | /// Bitwise-AND A with a constant value. |
| | 627 | AndI, |
| | 628 | /// Add a constant value to A, without updating flags. |
| | 629 | AddINF, |
| | 630 | /// Subtract a constant value from A, without updating flags. |
| | 631 | SubINF, |
| | 632 | /// Bitwise-AND A with a constant value, without updating flags. |
| | 633 | AndINF, |
| | 634 | /// Add register B to A -> A. |
| | 635 | AccumulateAdd, |
| | 636 | /// Subtract register B from A -> A. |
| | 637 | AccumulateSub, |
| | 638 | /// A & B -> A. |
| | 639 | AccumulateAnd, |
| | 640 | /// Bitwise OR B with A -> A. |
| | 641 | OrI, |
| | 642 | /// Bitwise OR a constant value with A -> A. |
| | 643 | XorI, |
| | 644 | /// Invert register A. |
| | 645 | Not, |
| | 646 | /// Add a value from memory to A. |
| | 647 | Add, |
| | 648 | /// Subtract a value from memory from A. |
| | 649 | Sub, |
| | 650 | /// AND A with a value from memory. |
| | 651 | And, |
| | 652 | /// OR A with a value from memory. |
| | 653 | Or, |
| | 654 | /// XOR A with a value from memory. |
| | 655 | Xor, |
| | 656 | /// No-op. |
| | 657 | Nop, |
| | 658 | /// No-op with 1 extra clock cycle. |
| | 659 | Nop1, |
| | 660 | /// No-op with 2 extra clock cycles. |
| | 661 | Nop2, |
| | 662 | /// Halt - stop the program forever (until reset). |
| | 663 | Halt, |
| 607 | }; | 664 | }; |
| 608 | | 665 | |
| 609 | const Register = enum(u8) { | 666 | const Register = enum(u8) { |