Skip to content

stage2 binds a value in an array by reference (?) where stage1 would copy.  #12642

@paoda

Description

@paoda

Zig Version

0.10.0-dev.3685+dae7aeb33

Steps to Reproduce

const std = @import("std");

/// This struct will just provide some example ARMv4 instructions to fill the pipeline with
const Cpu = struct {
    const Self = @This();
    pc: u32,

    pub fn fetch(self: *Self) u32 {
        defer self.pc += 1;

        return switch (self.pc) {
            0 => 0xea00002e,
            1 => 0x51aeff24,
            2 => 0xe59fd0d0,
            else => 0x00000000,
        };
    }
};

/// 3-stage Pipeline like what would be found in an ARM7TDMI
const Pipeline = struct {
    const Self = @This();

    /// Fetch and Decoding Stages of the pipeline
    stage: [2]?u32,

    pub fn init() Self {
        return .{ .stage = [_]?u32{null} ** 2 };
    }

    /// Progresses the state of the pipeline by "one stage"
    pub fn step(self: *Self, cpu: *Cpu) ?u32 {
        // In stage1, L38 would copy the contents of `self.stage[0]` so that
        // L40 could happen and the variable `opcode` which is declared and assigned in L38
        // would then hold the old value of `self.stage[0]`.
        //
        // However, in stage2, this is not the case. L40 changes the value held in `opcode`
        const opcode = self.stage[0];

        self.stage[0] = self.stage[1];
        self.stage[1] = cpu.fetch();

        return opcode;
    }
};

pub fn main() !void {
    std.debug.print("run zig build test on stage1 and then stage2!", .{});
}

test "pipeline struct behaves like a 3 stage pipeline" {
    var cpu: Cpu = .{ .pc = 0 };
    var pipeline = Pipeline.init();

    // On the third time calling Pipeline.step we should receive our first instruction
    try std.testing.expectEqual(@as(?u32, null), pipeline.step(&cpu));
    try std.testing.expectEqual(@as(?u32, null), pipeline.step(&cpu)); // stage 2 will fail here, as Pipeline.step returns 0xea00002e
    try std.testing.expectEqual(@as(?u32, 0xea00002e), pipeline.step(&cpu));
    try std.testing.expectEqual(@as(?u32, 0x51aeff24), pipeline.step(&cpu));
    try std.testing.expectEqual(@as(?u32, 0xe59fd0d0), pipeline.step(&cpu));
    try std.testing.expectEqual(@as(?u32, 0x00000000), pipeline.step(&cpu));
    try std.testing.expectEqual(@as(?u32, 0x00000000), pipeline.step(&cpu));
}

Expected Behavior

I expect the test to pass as it does on stage1.

To be more specific, I expect the line const opcode = self.stage[0]; to copy the value (it being a ?u32). So that the line below it self.stage[0] = self.stage[1]; does not mutate the value that opcode is bound to.

Actual Behavior

Currently, self.stage[0] = self.stage[1]; will mutate the value assigned to opcode.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugObserved behavior contradicts documented or intended behaviorfrontendTokenization, parsing, AstGen, Sema, and Liveness.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions