aboutsummaryrefslogtreecommitdiff
path: root/src/value.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-04-29 00:19:55 -0700
committerGitHub <noreply@github.com>2023-04-29 00:19:55 -0700
commitd65b42e07caa00dfe2f2fbf221c593ce57882784 (patch)
tree7926cbea1499e0affe930bf6d7455dc24adf014e /src/value.zig
parentfd6200eda6d4fe19c34a59430a88a9ce38d6d7a4 (diff)
parentfa200ca0cad2705bad40eb723dedf4e3bf11f2ff (diff)
downloadzig-d65b42e07caa00dfe2f2fbf221c593ce57882784.tar.gz
zig-d65b42e07caa00dfe2f2fbf221c593ce57882784.zip
Merge pull request #15481 from ziglang/use-mem-intrinsics
actually use the new memory intrinsics
Diffstat (limited to 'src/value.zig')
-rw-r--r--src/value.zig53
1 files changed, 44 insertions, 9 deletions
diff --git a/src/value.zig b/src/value.zig
index 05e9d24ee2..16ccc0c642 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -875,7 +875,7 @@ pub const Value = extern union {
.repeated => {
const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt(target));
const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen()));
- std.mem.set(u8, result, byte);
+ @memset(result, byte);
return result;
},
.decl_ref => {
@@ -1278,12 +1278,16 @@ pub const Value = extern union {
///
/// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past
/// the end of the value in memory.
- pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ReinterpretDeclRef}!void {
+ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{
+ ReinterpretDeclRef,
+ IllDefinedMemoryLayout,
+ Unimplemented,
+ }!void {
const target = mod.getTarget();
const endian = target.cpu.arch.endian();
if (val.isUndef()) {
const size = @intCast(usize, ty.abiSize(target));
- std.mem.set(u8, buffer[0..size], 0xaa);
+ @memset(buffer[0..size], 0xaa);
return;
}
switch (ty.zigTypeTag()) {
@@ -1345,7 +1349,7 @@ pub const Value = extern union {
return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
},
.Struct => switch (ty.containerLayout()) {
- .Auto => unreachable, // Sema is supposed to have emitted a compile error already
+ .Auto => return error.IllDefinedMemoryLayout,
.Extern => {
const fields = ty.structFields().values();
const field_vals = val.castTag(.aggregate).?.data;
@@ -1366,20 +1370,20 @@ pub const Value = extern union {
std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], @intCast(Int, int), endian);
},
.Union => switch (ty.containerLayout()) {
- .Auto => unreachable,
- .Extern => @panic("TODO implement writeToMemory for extern unions"),
+ .Auto => return error.IllDefinedMemoryLayout,
+ .Extern => return error.Unimplemented,
.Packed => {
const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;
return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
},
},
.Pointer => {
- assert(!ty.isSlice()); // No well defined layout.
+ if (ty.isSlice()) return error.IllDefinedMemoryLayout;
if (val.isDeclRef()) return error.ReinterpretDeclRef;
return val.writeToMemory(Type.usize, mod, buffer);
},
.Optional => {
- assert(ty.isPtrLikeOptional());
+ if (!ty.isPtrLikeOptional()) return error.IllDefinedMemoryLayout;
var buf: Type.Payload.ElemType = undefined;
const child = ty.optionalChild(&buf);
const opt_val = val.optionalValue();
@@ -1389,7 +1393,7 @@ pub const Value = extern union {
return writeToMemory(Value.zero, Type.usize, mod, buffer);
}
},
- else => @panic("TODO implement writeToMemory for more types"),
+ else => return error.Unimplemented,
}
}
@@ -2785,6 +2789,7 @@ pub const Value = extern union {
.field_ptr => isComptimeMutablePtr(val.castTag(.field_ptr).?.data.container_ptr),
.eu_payload_ptr => isComptimeMutablePtr(val.castTag(.eu_payload_ptr).?.data.container_ptr),
.opt_payload_ptr => isComptimeMutablePtr(val.castTag(.opt_payload_ptr).?.data.container_ptr),
+ .slice => isComptimeMutablePtr(val.castTag(.slice).?.data.ptr),
else => false,
};
@@ -5381,6 +5386,36 @@ pub const Value = extern union {
}
}
+ /// If the value is represented in-memory as a series of bytes that all
+ /// have the same value, return that byte value, otherwise null.
+ pub fn hasRepeatedByteRepr(val: Value, ty: Type, mod: *Module, value_buffer: *Payload.U64) !?Value {
+ const target = mod.getTarget();
+ const abi_size = ty.abiSize(target);
+ assert(abi_size >= 1);
+ const byte_buffer = try mod.gpa.alloc(u8, abi_size);
+ defer mod.gpa.free(byte_buffer);
+
+ writeToMemory(val, ty, mod, byte_buffer) catch |err| switch (err) {
+ error.ReinterpretDeclRef => return null,
+ // TODO: The writeToMemory function was originally created for the purpose
+ // of comptime pointer casting. However, it is now additionally being used
+ // for checking the actual memory layout that will be generated by machine
+ // code late in compilation. So, this error handling is too aggressive and
+ // causes some false negatives, causing less-than-ideal code generation.
+ error.IllDefinedMemoryLayout => return null,
+ error.Unimplemented => return null,
+ };
+ const first_byte = byte_buffer[0];
+ for (byte_buffer[1..]) |byte| {
+ if (byte != first_byte) return null;
+ }
+ value_buffer.* = .{
+ .base = .{ .tag = .int_u64 },
+ .data = first_byte,
+ };
+ return initPayload(&value_buffer.base);
+ }
+
/// This type is not copyable since it may contain pointers to its inner data.
pub const Payload = struct {
tag: Tag,