| author | |
| committer | |
| log | 00b690540e561391d17c65e45f818db6be8fecec |
| tree | 8e1018f7e4824ef36bba99d5defd1f291b4a5c1e |
| parent | fd6200eda6d4fe19c34a59430a88a9ce38d6d7a4 |
The bitcast of ABI size 1 elements was problematic for some types.4 files changed, 141 insertions(+), 92 deletions(-)
src/codegen/llvm.zig+12-2| ... | @@ -7939,11 +7939,15 @@ pub const FuncGen = struct { | ... | @@ -7939,11 +7939,15 @@ pub const FuncGen = struct { |
| 7939 | return self.builder.buildPtrToInt(operand_ptr, dest_llvm_ty, ""); | 7939 | return self.builder.buildPtrToInt(operand_ptr, dest_llvm_ty, ""); |
| 7940 | } | 7940 | } |
| 7941 | 7941 | ||
| 7942 | fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7942 | fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !*llvm.Value { |
| 7943 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7943 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7944 | const operand_ty = self.air.typeOf(ty_op.operand); | 7944 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 7945 | const inst_ty = self.air.typeOfIndex(inst); | 7945 | const inst_ty = self.air.typeOfIndex(inst); |
| 7946 | const operand = try self.resolveInst(ty_op.operand); | 7946 | const operand = try self.resolveInst(ty_op.operand); |
| 7947 | return self.bitCast(operand, operand_ty, inst_ty); | ||
| 7948 | } | ||
| 7949 | |||
| 7950 | fn bitCast(self: *FuncGen, operand: *llvm.Value, operand_ty: Type, inst_ty: Type) !*llvm.Value { | ||
| 7947 | const operand_is_ref = isByRef(operand_ty); | 7951 | const operand_is_ref = isByRef(operand_ty); |
| 7948 | const result_is_ref = isByRef(inst_ty); | 7952 | const result_is_ref = isByRef(inst_ty); |
| 7949 | const llvm_dest_ty = try self.dg.lowerType(inst_ty); | 7953 | const llvm_dest_ty = try self.dg.lowerType(inst_ty); |
| ... | @@ -7954,6 +7958,12 @@ pub const FuncGen = struct { | ... | @@ -7954,6 +7958,12 @@ pub const FuncGen = struct { |
| 7954 | return operand; | 7958 | return operand; |
| 7955 | } | 7959 | } |
| 7956 | 7960 | ||
| 7961 | if (llvm_dest_ty.getTypeKind() == .Integer and | ||
| 7962 | operand.typeOf().getTypeKind() == .Integer) | ||
| 7963 | { | ||
| 7964 | return self.builder.buildZExtOrBitCast(operand, llvm_dest_ty, ""); | ||
| 7965 | } | ||
| 7966 | |||
| 7957 | if (operand_ty.zigTypeTag() == .Int and inst_ty.isPtrAtRuntime()) { | 7967 | if (operand_ty.zigTypeTag() == .Int and inst_ty.isPtrAtRuntime()) { |
| 7958 | return self.builder.buildIntToPtr(operand, llvm_dest_ty, ""); | 7968 | return self.builder.buildIntToPtr(operand, llvm_dest_ty, ""); |
| 7959 | } | 7969 | } |
| ... | @@ -8442,7 +8452,7 @@ pub const FuncGen = struct { | ... | @@ -8442,7 +8452,7 @@ pub const FuncGen = struct { |
| 8442 | 8452 | ||
| 8443 | if (elem_abi_size == 1) { | 8453 | if (elem_abi_size == 1) { |
| 8444 | // In this case we can take advantage of LLVM's intrinsic. | 8454 | // In this case we can take advantage of LLVM's intrinsic. |
| 8445 | const fill_byte = self.builder.buildBitCast(value, u8_llvm_ty, ""); | 8455 | const fill_byte = try self.bitCast(value, elem_ty, Type.u8); |
| 8446 | const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); | 8456 | const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8447 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr()); | 8457 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr()); |
| 8448 | return null; | 8458 | return null; |
test/behavior.zig+1| ... | @@ -177,6 +177,7 @@ test { | ... | @@ -177,6 +177,7 @@ test { |
| 177 | _ = @import("behavior/math.zig"); | 177 | _ = @import("behavior/math.zig"); |
| 178 | _ = @import("behavior/maximum_minimum.zig"); | 178 | _ = @import("behavior/maximum_minimum.zig"); |
| 179 | _ = @import("behavior/member_func.zig"); | 179 | _ = @import("behavior/member_func.zig"); |
| 180 | _ = @import("behavior/memset.zig"); | ||
| 180 | _ = @import("behavior/merge_error_sets.zig"); | 181 | _ = @import("behavior/merge_error_sets.zig"); |
| 181 | _ = @import("behavior/muladd.zig"); | 182 | _ = @import("behavior/muladd.zig"); |
| 182 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); | 183 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); |
test/behavior/basic.zig-90| ... | @@ -353,96 +353,6 @@ fn f2(x: bool) []const u8 { | ... | @@ -353,96 +353,6 @@ fn f2(x: bool) []const u8 { |
| 353 | return (if (x) &fA else &fB)(); | 353 | return (if (x) &fA else &fB)(); |
| 354 | } | 354 | } |
| 355 | 355 | ||
| 356 | test "@memset on array pointers" { | ||
| 357 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 358 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 359 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | ||
| 360 | if (builtin.zig_backend == .stage2_wasm) { | ||
| 361 | // TODO: implement memset when element ABI size > 1 | ||
| 362 | return error.SkipZigTest; | ||
| 363 | } | ||
| 364 | |||
| 365 | try testMemsetArray(); | ||
| 366 | try comptime testMemsetArray(); | ||
| 367 | } | ||
| 368 | |||
| 369 | fn testMemsetArray() !void { | ||
| 370 | { | ||
| 371 | // memset array to non-undefined, ABI size == 1 | ||
| 372 | var foo: [20]u8 = undefined; | ||
| 373 | @memset(&foo, 'A'); | ||
| 374 | try expect(foo[0] == 'A'); | ||
| 375 | try expect(foo[11] == 'A'); | ||
| 376 | try expect(foo[19] == 'A'); | ||
| 377 | } | ||
| 378 | { | ||
| 379 | // memset array to non-undefined, ABI size > 1 | ||
| 380 | var foo: [20]u32 = undefined; | ||
| 381 | @memset(&foo, 1234); | ||
| 382 | try expect(foo[0] == 1234); | ||
| 383 | try expect(foo[11] == 1234); | ||
| 384 | try expect(foo[19] == 1234); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 388 | test "@memset on slices" { | ||
| 389 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 390 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 391 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | ||
| 392 | if (builtin.zig_backend == .stage2_wasm) { | ||
| 393 | // TODO: implement memset when element ABI size > 1 | ||
| 394 | // TODO: implement memset on slices | ||
| 395 | return error.SkipZigTest; | ||
| 396 | } | ||
| 397 | |||
| 398 | try testMemsetSlice(); | ||
| 399 | try comptime testMemsetSlice(); | ||
| 400 | } | ||
| 401 | |||
| 402 | fn testMemsetSlice() !void { | ||
| 403 | { | ||
| 404 | // memset slice to non-undefined, ABI size == 1 | ||
| 405 | var array: [20]u8 = undefined; | ||
| 406 | var len = array.len; | ||
| 407 | var slice = array[0..len]; | ||
| 408 | @memset(slice, 'A'); | ||
| 409 | try expect(slice[0] == 'A'); | ||
| 410 | try expect(slice[11] == 'A'); | ||
| 411 | try expect(slice[19] == 'A'); | ||
| 412 | } | ||
| 413 | { | ||
| 414 | // memset slice to non-undefined, ABI size > 1 | ||
| 415 | var array: [20]u32 = undefined; | ||
| 416 | var len = array.len; | ||
| 417 | var slice = array[0..len]; | ||
| 418 | @memset(slice, 1234); | ||
| 419 | try expect(slice[0] == 1234); | ||
| 420 | try expect(slice[11] == 1234); | ||
| 421 | try expect(slice[19] == 1234); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | test "memcpy and memset intrinsics" { | ||
| 426 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 427 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 428 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 429 | |||
| 430 | try testMemcpyMemset(); | ||
| 431 | try comptime testMemcpyMemset(); | ||
| 432 | } | ||
| 433 | |||
| 434 | fn testMemcpyMemset() !void { | ||
| 435 | var foo: [20]u8 = undefined; | ||
| 436 | var bar: [20]u8 = undefined; | ||
| 437 | |||
| 438 | @memset(&foo, 'A'); | ||
| 439 | @memcpy(&bar, &foo); | ||
| 440 | |||
| 441 | try expect(bar[0] == 'A'); | ||
| 442 | try expect(bar[11] == 'A'); | ||
| 443 | try expect(bar[19] == 'A'); | ||
| 444 | } | ||
| 445 | |||
| 446 | test "variable is allowed to be a pointer to an opaque type" { | 356 | test "variable is allowed to be a pointer to an opaque type" { |
| 447 | var x: i32 = 1234; | 357 | var x: i32 = 1234; |
| 448 | _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); | 358 | _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); |
test/behavior/memset.zig created+128| ... | @@ -0,0 +1,128 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | test "@memset on array pointers" { | ||
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | ||
| 9 | if (builtin.zig_backend == .stage2_wasm) { | ||
| 10 | // TODO: implement memset when element ABI size > 1 | ||
| 11 | return error.SkipZigTest; | ||
| 12 | } | ||
| 13 | |||
| 14 | try testMemsetArray(); | ||
| 15 | try comptime testMemsetArray(); | ||
| 16 | } | ||
| 17 | |||
| 18 | fn testMemsetArray() !void { | ||
| 19 | { | ||
| 20 | // memset array to non-undefined, ABI size == 1 | ||
| 21 | var foo: [20]u8 = undefined; | ||
| 22 | @memset(&foo, 'A'); | ||
| 23 | try expect(foo[0] == 'A'); | ||
| 24 | try expect(foo[11] == 'A'); | ||
| 25 | try expect(foo[19] == 'A'); | ||
| 26 | } | ||
| 27 | { | ||
| 28 | // memset array to non-undefined, ABI size > 1 | ||
| 29 | var foo: [20]u32 = undefined; | ||
| 30 | @memset(&foo, 1234); | ||
| 31 | try expect(foo[0] == 1234); | ||
| 32 | try expect(foo[11] == 1234); | ||
| 33 | try expect(foo[19] == 1234); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | test "@memset on slices" { | ||
| 38 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 39 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 40 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | ||
| 41 | if (builtin.zig_backend == .stage2_wasm) { | ||
| 42 | // TODO: implement memset when element ABI size > 1 | ||
| 43 | // TODO: implement memset on slices | ||
| 44 | return error.SkipZigTest; | ||
| 45 | } | ||
| 46 | |||
| 47 | try testMemsetSlice(); | ||
| 48 | try comptime testMemsetSlice(); | ||
| 49 | } | ||
| 50 | |||
| 51 | fn testMemsetSlice() !void { | ||
| 52 | { | ||
| 53 | // memset slice to non-undefined, ABI size == 1 | ||
| 54 | var array: [20]u8 = undefined; | ||
| 55 | var len = array.len; | ||
| 56 | var slice = array[0..len]; | ||
| 57 | @memset(slice, 'A'); | ||
| 58 | try expect(slice[0] == 'A'); | ||
| 59 | try expect(slice[11] == 'A'); | ||
| 60 | try expect(slice[19] == 'A'); | ||
| 61 | } | ||
| 62 | { | ||
| 63 | // memset slice to non-undefined, ABI size > 1 | ||
| 64 | var array: [20]u32 = undefined; | ||
| 65 | var len = array.len; | ||
| 66 | var slice = array[0..len]; | ||
| 67 | @memset(slice, 1234); | ||
| 68 | try expect(slice[0] == 1234); | ||
| 69 | try expect(slice[11] == 1234); | ||
| 70 | try expect(slice[19] == 1234); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | test "memset with bool element" { | ||
| 75 | var buf: [5]bool = undefined; | ||
| 76 | @memset(&buf, true); | ||
| 77 | try expect(buf[2]); | ||
| 78 | try expect(buf[4]); | ||
| 79 | } | ||
| 80 | |||
| 81 | test "memset with 1-byte struct element" { | ||
| 82 | const S = struct { x: bool }; | ||
| 83 | var buf: [5]S = undefined; | ||
| 84 | @memset(&buf, .{ .x = true }); | ||
| 85 | try expect(buf[2].x); | ||
| 86 | try expect(buf[4].x); | ||
| 87 | } | ||
| 88 | |||
| 89 | test "memset with 1-byte array element" { | ||
| 90 | const A = [1]bool; | ||
| 91 | var buf: [5]A = undefined; | ||
| 92 | @memset(&buf, .{true}); | ||
| 93 | try expect(buf[2][0]); | ||
| 94 | try expect(buf[4][0]); | ||
| 95 | } | ||
| 96 | |||
| 97 | test "memset with large array element" { | ||
| 98 | const A = [128]u64; | ||
| 99 | var buf: [5]A = undefined; | ||
| 100 | var runtime_known_element = [_]u64{0} ** 128; | ||
| 101 | @memset(&buf, runtime_known_element); | ||
| 102 | for (buf[0]) |elem| try expect(elem == 0); | ||
| 103 | for (buf[1]) |elem| try expect(elem == 0); | ||
| 104 | for (buf[2]) |elem| try expect(elem == 0); | ||
| 105 | for (buf[3]) |elem| try expect(elem == 0); | ||
| 106 | for (buf[4]) |elem| try expect(elem == 0); | ||
| 107 | } | ||
| 108 | |||
| 109 | test "memcpy and memset intrinsics" { | ||
| 110 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 111 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 112 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 113 | |||
| 114 | try testMemcpyMemset(); | ||
| 115 | try comptime testMemcpyMemset(); | ||
| 116 | } | ||
| 117 | |||
| 118 | fn testMemcpyMemset() !void { | ||
| 119 | var foo: [20]u8 = undefined; | ||
| 120 | var bar: [20]u8 = undefined; | ||
| 121 | |||
| 122 | @memset(&foo, 'A'); | ||
| 123 | @memcpy(&bar, &foo); | ||
| 124 | |||
| 125 | try expect(bar[0] == 'A'); | ||
| 126 | try expect(bar[11] == 'A'); | ||
| 127 | try expect(bar[19] == 'A'); | ||
| 128 | } | ||