Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

copy of overlapping values produces wrong results #22872

Open
Fri3dNstuff opened this issue Feb 12, 2025 · 1 comment
Open

copy of overlapping values produces wrong results #22872

Fri3dNstuff opened this issue Feb 12, 2025 · 1 comment
Labels
bug Observed behavior contradicts documented or intended behavior

Comments

@Fri3dNstuff
Copy link
Contributor

Zig Version

0.14.0-dev.3199+4162f401c

Steps to Reproduce and Observed Behavior

Test the following program:

test {
    var arr: [3]usize = .{ 0, 1, 2 };
    arr[1..3].* = arr[0..2].*;
    // fails! found `.{ 0, 0, 0 }`
    try std.testing.expectEqual(.{ 0, 0, 1 }, arr);
}

The call to std.testing.expectEqual fails, as arr's value is .{ 0, 0, 0 } at that point.

Expected Behavior

The assignment should copy the sub-array .{ 0, 1 } into positions 1..3, resulting in arr's complete value being .{ 0, 0, 1 }.

This might be yet another manifestation of RLS's oddities (e.g. #12064), or it might not, as those only seem to crop up in places where the right-hand-side of the assignment is an aggregate literal...

@Fri3dNstuff Fri3dNstuff added the bug Observed behavior contradicts documented or intended behavior label Feb 12, 2025
@dweiller
Copy link
Contributor

dweiller commented Feb 13, 2025

Looks to me like this is due to something in the LLVM backend; the x86_64 backend has it pass for me. Compiling this file:

// bug.zig
export fn foo(arr: *[3]usize) void {
    arr.* = .{ 0, 1, 2 };
    arr[1..3].* = arr[0..2].*;
}

with zig build-obj --verbose-air --verbose-llvm-ir -OReleaseFast bug.zig gives this AIR:

# Begin Function AIR: bug.foo:
# Total AIR+Liveness bytes: 473B
# AIR Instructions:         25 (225B)
# AIR Extra Data:           32 (128B)
# Liveness tomb_bits:       16B
# Liveness Extra Data:      0 (0B)
# Liveness special table:   0 (0B)
  %0 = arg(*[3]usize, "arr")
  %1 = alloc(**[3]usize)
  %2!= store(%1, %0)
  %3 = bitcast(*const *[3]usize, %1!)
  %4!= dbg_stmt(2:5)
  %11!= store(%0!, <[3]usize, .{ 0, 1, 2 }>)
  %12!= dbg_stmt(3:8)
  %13 = load(*[3]usize, %3)
  %14 = bitcast([*]usize, %13!)
  %15 = ptr_add([*]usize, %14!, @Air.Inst.Ref.one_usize)
  %16 = bitcast(*[2]usize, %15!)
  %17!= dbg_stmt(3:22)
  %18 = load(*[3]usize, %3!)
  %19 = bitcast([*]usize, %18!)
  %20 = ptr_add([*]usize, %19!, @Air.Inst.Ref.zero_usize)
  %21 = bitcast(*[2]usize, %20!)
  %22 = load([2]usize, %21!)
  %23!= store(%16!, %22!)
  %24!= ret(@Air.Inst.Ref.void_value)
# End Function AIR: bug.foo

and LLVM IR:

@0 = private unnamed_addr constant [3 x i64] [i64 0, i64 1, i64 2], align 8

; Function Attrs: nounwind uwtable nosanitize_coverage skipprofile
define dso_local void @foo(ptr align 8 nonnull %0) #0 !dbg !3 {
Entry:
  %1 = alloca [8 x i8], align 8
  call void @llvm.dbg.value(metadata ptr %0, metadata !5, metadata !DIExpression()), !dbg !4
  store ptr %0, ptr %1, align 8, !dbg !4
  call void @llvm.memcpy.p0.p0.i64(ptr align 8 %0, ptr align 8 @0, i64 24, i1 false), !dbg !6
  %2 = load ptr, ptr %1, align 8, !dbg !7
  %3 = getelementptr inbounds i64, ptr %2, i64 1, !dbg !7
  %4 = load ptr, ptr %1, align 8, !dbg !8
  %5 = getelementptr inbounds i64, ptr %4, i64 0, !dbg !8
  call void @llvm.memcpy.p0.p0.i64(ptr align 8 %3, ptr align 8 %5, i64 16, i1 false), !dbg !8
  ret void, !dbg !8
}

The AIR looks okay to me (though I'm not 100% sure of the semantics of AIR, someone else will have to confirm), but the second call to @llvm.memcpy in the LLVM IR would cause the observed bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior
Projects
None yet
Development

No branches or pull requests

2 participants