authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-02-18 22:05:09+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-19 13:54:52-05:00
logf10950526ea781ee2d15df74398527420cca13a1
treeb49b1a4e0690cc7c8d7cb047c644a8301661ab6b
parent02f5d2673f1bb21e7329acdd664fed565ecd4317

implement `writeToMemory`/`readFromMemory` for pointers


6 files changed, 74 insertions(+), 36 deletions(-)

src/Sema.zig+30-21
......@@ -2529,7 +2529,7 @@ fn coerceResultPtr(
25292529 _ = try block.addBinOp(.store, new_ptr, null_inst);
25302530 return Air.Inst.Ref.void_value;
25312531 }
2532 return sema.bitCast(block, ptr_ty, new_ptr, src);
2532 return sema.bitCast(block, ptr_ty, new_ptr, src, null);
25332533 }
25342534
25352535 const trash_inst = trash_block.instructions.pop();
......@@ -2545,7 +2545,7 @@ fn coerceResultPtr(
25452545 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
25462546 new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val);
25472547 } else {
2548 new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src);
2548 new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null);
25492549 }
25502550 },
25512551 .wrap_optional => {
......@@ -9655,7 +9655,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
96559655 .Vector,
96569656 => {},
96579657 }
9658 return sema.bitCast(block, dest_ty, operand, operand_src);
9658 return sema.bitCast(block, dest_ty, operand, inst_data.src(), operand_src);
96599659}
96609660
96619661fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -9888,7 +9888,7 @@ fn zirSwitchCapture(
98889888
98899889 switch (operand_ty.zigTypeTag()) {
98909890 .ErrorSet => if (block.switch_else_err_ty) |some| {
9891 return sema.bitCast(block, some, operand, operand_src);
9891 return sema.bitCast(block, some, operand, operand_src, null);
98929892 } else {
98939893 try block.addUnreachable(false);
98949894 return Air.Inst.Ref.unreachable_value;
......@@ -9988,14 +9988,14 @@ fn zirSwitchCapture(
99889988 Module.ErrorSet.sortNames(&names);
99899989 const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names);
99909990
9991 return sema.bitCast(block, else_error_ty, operand, operand_src);
9991 return sema.bitCast(block, else_error_ty, operand, operand_src, null);
99929992 } else {
99939993 const item_ref = try sema.resolveInst(items[0]);
99949994 // Previous switch validation ensured this will succeed
99959995 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable;
99969996
99979997 const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?);
9998 return sema.bitCast(block, item_ty, operand, operand_src);
9998 return sema.bitCast(block, item_ty, operand, operand_src, null);
99999999 }
1000010000 },
1000110001 else => {
......@@ -19953,7 +19953,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1995319953 } else is_aligned;
1995419954 try sema.addSafetyCheck(block, ok, .incorrect_alignment);
1995519955 }
19956 return sema.bitCast(block, dest_ty, ptr, ptr_src);
19956 return sema.bitCast(block, dest_ty, ptr, ptr_src, null);
1995719957}
1995819958
1995919959fn zirBitCount(
......@@ -24141,8 +24141,9 @@ fn unionFieldVal(
2414124141 return sema.addConstant(field.ty, tag_and_val.val);
2414224142 } else {
2414324143 const old_ty = union_ty.unionFieldType(tag_and_val.tag, sema.mod);
24144 const new_val = try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0);
24145 return sema.addConstant(field.ty, new_val);
24144 if (try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0)) |new_val| {
24145 return sema.addConstant(field.ty, new_val);
24146 }
2414624147 }
2414724148 },
2414824149 }
......@@ -26514,8 +26515,12 @@ fn storePtrVal(
2651426515 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(target));
2651526516 const buffer = try sema.gpa.alloc(u8, abi_size);
2651626517 defer sema.gpa.free(buffer);
26517 reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer);
26518 operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]);
26518 reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer) catch |err| switch (err) {
26519 error.ReinterpretDeclRef => unreachable,
26520 };
26521 operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) {
26522 error.ReinterpretDeclRef => unreachable,
26523 };
2651926524
2652026525 const arena = mut_kit.beginArena(sema.mod);
2652126526 defer mut_kit.finishArena(sema.mod);
......@@ -27398,6 +27403,7 @@ fn bitCast(
2739827403 dest_ty_unresolved: Type,
2739927404 inst: Air.Inst.Ref,
2740027405 inst_src: LazySrcLoc,
27406 operand_src: ?LazySrcLoc,
2740127407) CompileError!Air.Inst.Ref {
2740227408 const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved);
2740327409 try sema.resolveTypeLayout(dest_ty);
......@@ -27419,10 +27425,11 @@ fn bitCast(
2741927425 }
2742027426
2742127427 if (try sema.resolveMaybeUndefVal(inst)) |val| {
27422 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0);
27423 return sema.addConstant(dest_ty, result_val);
27428 if (try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0)) |result_val| {
27429 return sema.addConstant(dest_ty, result_val);
27430 }
2742427431 }
27425 try sema.requireRuntimeBlock(block, inst_src, null);
27432 try sema.requireRuntimeBlock(block, inst_src, operand_src);
2742627433 return block.addBitCast(dest_ty, inst);
2742727434}
2742827435
......@@ -27434,7 +27441,7 @@ fn bitCastVal(
2743427441 old_ty: Type,
2743527442 new_ty: Type,
2743627443 buffer_offset: usize,
27437) !Value {
27444) !?Value {
2743827445 const target = sema.mod.getTarget();
2743927446 if (old_ty.eql(new_ty, sema.mod)) return val;
2744027447
......@@ -27443,8 +27450,10 @@ fn bitCastVal(
2744327450 const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(target));
2744427451 const buffer = try sema.gpa.alloc(u8, abi_size);
2744527452 defer sema.gpa.free(buffer);
27446 val.writeToMemory(old_ty, sema.mod, buffer);
27447 return Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena);
27453 val.writeToMemory(old_ty, sema.mod, buffer) catch |err| switch (err) {
27454 error.ReinterpretDeclRef => return null,
27455 };
27456 return try Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena);
2744827457}
2744927458
2745027459fn coerceArrayPtrToSlice(
......@@ -27551,7 +27560,7 @@ fn coerceCompatiblePtrs(
2755127560 } else is_non_zero;
2755227561 try sema.addSafetyCheck(block, ok, .cast_to_null);
2755327562 }
27554 return sema.bitCast(block, dest_ty, inst, inst_src);
27563 return sema.bitCast(block, dest_ty, inst, inst_src, null);
2755527564}
2755627565
2755727566fn coerceEnumToUnion(
......@@ -28291,7 +28300,7 @@ fn analyzeRef(
2829128300 try sema.storePtr(block, src, alloc, operand);
2829228301
2829328302 // TODO: Replace with sema.coerce when that supports adding pointer constness.
28294 return sema.bitCast(block, ptr_type, alloc, src);
28303 return sema.bitCast(block, ptr_type, alloc, src, null);
2829528304}
2829628305
2829728306fn analyzeLoad(
......@@ -32327,11 +32336,11 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value
3232732336
3232832337 // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`
3232932338 if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(tv.ty))
32330 return DerefResult{ .val = try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0) };
32339 return DerefResult{ .val = (try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0)) orelse return .runtime_load };
3233132340
3233232341 // If that fails, try to bit-cast from the largest parent value with a well-defined layout
3233332342 if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent.tv.ty))
32334 return DerefResult{ .val = try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset) };
32343 return DerefResult{ .val = (try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset)) orelse return .runtime_load };
3233532344
3233632345 if (deref.ty_without_well_defined_layout) |bad_ty| {
3233732346 // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem
src/arch/wasm/CodeGen.zig+2-2
......@@ -2896,7 +2896,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
28962896 const struct_obj = ty.castTag(.@"struct").?.data;
28972897 assert(struct_obj.layout == .Packed);
28982898 var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer
2899 val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0);
2899 val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable;
29002900 var payload: Value.Payload.U64 = .{
29012901 .base = .{ .tag = .int_u64 },
29022902 .data = std.mem.readIntLittle(u64, &buf),
......@@ -2907,7 +2907,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
29072907 .Vector => {
29082908 assert(determineSimdStoreStrategy(ty, target) == .direct);
29092909 var buf: [16]u8 = undefined;
2910 val.writeToMemory(ty, func.bin_file.base.options.module.?, &buf);
2910 val.writeToMemory(ty, func.bin_file.base.options.module.?, &buf) catch unreachable;
29112911 return func.storeSimdImmd(buf);
29122912 },
29132913 else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}),
src/codegen.zig+1-1
......@@ -527,7 +527,7 @@ pub fn generateSymbol(
527527 .fail => |em| return Result{ .fail = em },
528528 }
529529 } else {
530 field_val.writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits);
530 field_val.writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits) catch unreachable;
531531 }
532532 bits += @intCast(u16, field_ty.bitSize(target));
533533 }
src/value.zig+39-10
......@@ -1249,11 +1249,22 @@ pub const Value = extern union {
12491249 };
12501250 }
12511251
1252 fn isDeclRef(val: Value) bool {
1253 var check = val;
1254 while (true) switch (check.tag()) {
1255 .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return true,
1256 .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr,
1257 .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
1258 .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
1259 else => return false,
1260 };
1261 }
1262
12521263 /// Write a Value's contents to `buffer`.
12531264 ///
12541265 /// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past
12551266 /// the end of the value in memory.
1256 pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) void {
1267 pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ReinterpretDeclRef}!void {
12571268 const target = mod.getTarget();
12581269 const endian = target.cpu.arch.endian();
12591270 if (val.isUndef()) {
......@@ -1309,7 +1320,7 @@ pub const Value = extern union {
13091320 var buf_off: usize = 0;
13101321 while (elem_i < len) : (elem_i += 1) {
13111322 const elem_val = val.elemValueBuffer(mod, elem_i, &elem_value_buf);
1312 elem_val.writeToMemory(elem_ty, mod, buffer[buf_off..]);
1323 try elem_val.writeToMemory(elem_ty, mod, buffer[buf_off..]);
13131324 buf_off += elem_size;
13141325 }
13151326 },
......@@ -1317,7 +1328,7 @@ pub const Value = extern union {
13171328 // We use byte_count instead of abi_size here, so that any padding bytes
13181329 // follow the data bytes, on both big- and little-endian systems.
13191330 const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;
1320 writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
1331 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
13211332 },
13221333 .Struct => switch (ty.containerLayout()) {
13231334 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
......@@ -1326,12 +1337,12 @@ pub const Value = extern union {
13261337 const field_vals = val.castTag(.aggregate).?.data;
13271338 for (fields, 0..) |field, i| {
13281339 const off = @intCast(usize, ty.structFieldOffset(i, target));
1329 writeToMemory(field_vals[i], field.ty, mod, buffer[off..]);
1340 try writeToMemory(field_vals[i], field.ty, mod, buffer[off..]);
13301341 }
13311342 },
13321343 .Packed => {
13331344 const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;
1334 writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
1345 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
13351346 },
13361347 },
13371348 .ErrorSet => {
......@@ -1345,9 +1356,14 @@ pub const Value = extern union {
13451356 .Extern => @panic("TODO implement writeToMemory for extern unions"),
13461357 .Packed => {
13471358 const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;
1348 writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
1359 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
13491360 },
13501361 },
1362 .Pointer => {
1363 assert(!ty.isSlice()); // No well defined layout.
1364 if (val.isDeclRef()) return error.ReinterpretDeclRef;
1365 return val.writeToMemory(Type.usize, mod, buffer);
1366 },
13511367 else => @panic("TODO implement writeToMemory for more types"),
13521368 }
13531369 }
......@@ -1356,7 +1372,7 @@ pub const Value = extern union {
13561372 ///
13571373 /// Both the start and the end of the provided buffer must be tight, since
13581374 /// big-endian packed memory layouts start at the end of the buffer.
1359 pub fn writeToPackedMemory(val: Value, ty: Type, mod: *Module, buffer: []u8, bit_offset: usize) void {
1375 pub fn writeToPackedMemory(val: Value, ty: Type, mod: *Module, buffer: []u8, bit_offset: usize) error{ReinterpretDeclRef}!void {
13601376 const target = mod.getTarget();
13611377 const endian = target.cpu.arch.endian();
13621378 if (val.isUndef()) {
......@@ -1420,7 +1436,7 @@ pub const Value = extern union {
14201436 // On big-endian systems, LLVM reverses the element order of vectors by default
14211437 const tgt_elem_i = if (endian == .Big) len - elem_i - 1 else elem_i;
14221438 const elem_val = val.elemValueBuffer(mod, tgt_elem_i, &elem_value_buf);
1423 elem_val.writeToPackedMemory(elem_ty, mod, buffer, bit_offset + bits);
1439 try elem_val.writeToPackedMemory(elem_ty, mod, buffer, bit_offset + bits);
14241440 bits += elem_bit_size;
14251441 }
14261442 },
......@@ -1433,7 +1449,7 @@ pub const Value = extern union {
14331449 const field_vals = val.castTag(.aggregate).?.data;
14341450 for (fields, 0..) |field, i| {
14351451 const field_bits = @intCast(u16, field.ty.bitSize(target));
1436 field_vals[i].writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits);
1452 try field_vals[i].writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits);
14371453 bits += field_bits;
14381454 }
14391455 },
......@@ -1446,9 +1462,14 @@ pub const Value = extern union {
14461462 const field_type = ty.unionFields().values()[field_index.?].ty;
14471463 const field_val = val.fieldValue(field_type, field_index.?);
14481464
1449 field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
1465 return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
14501466 },
14511467 },
1468 .Pointer => {
1469 assert(!ty.isSlice()); // No well defined layout.
1470 if (val.isDeclRef()) return error.ReinterpretDeclRef;
1471 return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset);
1472 },
14521473 else => @panic("TODO implement writeToPackedMemory for more types"),
14531474 }
14541475 }
......@@ -1553,6 +1574,10 @@ pub const Value = extern union {
15531574 };
15541575 return Value.initPayload(&payload.base);
15551576 },
1577 .Pointer => {
1578 assert(!ty.isSlice()); // No well defined layout.
1579 return readFromMemory(Type.usize, mod, buffer, arena);
1580 },
15561581 else => @panic("TODO implement readFromMemory for more types"),
15571582 }
15581583 }
......@@ -1640,6 +1665,10 @@ pub const Value = extern union {
16401665 return Tag.aggregate.create(arena, field_vals);
16411666 },
16421667 },
1668 .Pointer => {
1669 assert(!ty.isSlice()); // No well defined layout.
1670 return readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena);
1671 },
16431672 else => @panic("TODO implement readFromPackedMemory for more types"),
16441673 }
16451674 }
test/cases/compile_errors/bitCast_same_size_but_bit_count_mismatch.zig+1-1
......@@ -7,4 +7,4 @@ export fn entry(byte: u8) void {
77// backend=stage2
88// target=native
99//
10// :2:29: error: @bitCast size mismatch: destination type 'u7' has 7 bits but source type 'u8' has 8 bits
10// :2:16: error: @bitCast size mismatch: destination type 'u7' has 7 bits but source type 'u8' has 8 bits
test/cases/compile_errors/bitCast_with_different_sizes_inside_an_expression.zig+1-1
......@@ -7,4 +7,4 @@ export fn entry() void {
77// backend=stage2
88// target=native
99//
10// :2:29: error: @bitCast size mismatch: destination type 'u8' has 8 bits but source type 'f32' has 32 bits
10// :2:16: error: @bitCast size mismatch: destination type 'u8' has 8 bits but source type 'f32' has 32 bits