Skip to content

Commit

Permalink
Merge pull request ziglang#21210 from jacobly0/eh-frame
Browse files Browse the repository at this point in the history
Dwarf: implement .eh_frame
  • Loading branch information
jacobly0 authored Aug 27, 2024
2 parents 93cb44c + f289b82 commit 1a178d4
Show file tree
Hide file tree
Showing 27 changed files with 1,419 additions and 346 deletions.
2 changes: 1 addition & 1 deletion ci/x86_64-linux-debug.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ stage3-debug/bin/zig build \

stage3-debug/bin/zig build test docs \
--maxrss 21000000000 \
-Dlldb=$HOME/deps/lldb-zig/Debug-62538077d/bin/lldb \
-Dlldb=$HOME/deps/lldb-zig/Debug-70b8227f1/bin/lldb \
-fqemu \
-fwasmtime \
-Dstatic-llvm \
Expand Down
2 changes: 1 addition & 1 deletion ci/x86_64-linux-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ stage3-release/bin/zig build \

stage3-release/bin/zig build test docs \
--maxrss 21000000000 \
-Dlldb=$HOME/deps/lldb-zig/Release-62538077d/bin/lldb \
-Dlldb=$HOME/deps/lldb-zig/Release-70b8227f1/bin/lldb \
-fqemu \
-fwasmtime \
-Dstatic-llvm \
Expand Down
2 changes: 1 addition & 1 deletion lib/std/leb128.zig
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ pub const readILEB128 = readIleb128;
pub fn writeIleb128(writer: anytype, arg: anytype) !void {
const Arg = @TypeOf(arg);
const Int = switch (Arg) {
comptime_int => std.math.IntFittingRange(-arg - 1, arg),
comptime_int => std.math.IntFittingRange(-@abs(arg), @abs(arg)),
else => Arg,
};
const Signed = if (@typeInfo(Int).Int.bits < 8) i8 else Int;
Expand Down
5 changes: 3 additions & 2 deletions lib/std/os/linux/x86_64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,15 @@ pub fn clone() callconv(.Naked) usize {
\\ movq %%rcx,(%%rsi)
\\ syscall
\\ testq %%rax,%%rax
\\ jnz 1f
\\ jz 1f
\\ retq
\\1: .cfi_undefined %%rip
\\ xorl %%ebp,%%ebp
\\ popq %%rdi
\\ callq *%%r9
\\ movl %%eax,%%edi
\\ movl $60,%%eax // SYS_exit
\\ syscall
\\1: ret
\\
);
}
Expand Down
1 change: 1 addition & 0 deletions lib/std/start.zig
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ fn _start() callconv(.Naked) noreturn {
// linker explicitly.
asm volatile (switch (native_arch) {
.x86_64 =>
\\ .cfi_undefined %%rip
\\ xorl %%ebp, %%ebp
\\ movq %%rsp, %%rdi
\\ andq $-16, %%rsp
Expand Down
5 changes: 4 additions & 1 deletion src/Air.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const Value = @import("Value.zig");
const Type = @import("Type.zig");
const InternPool = @import("InternPool.zig");
const Zcu = @import("Zcu.zig");
const types_resolved = @import("Air/types_resolved.zig");

instructions: std.MultiArrayList(Inst).Slice,
/// The meaning of this data is determined by `Inst.Tag` value.
Expand Down Expand Up @@ -1899,4 +1900,6 @@ pub fn unwrapSwitch(air: *const Air, switch_inst: Inst.Index) UnwrappedSwitch {
};
}

pub const typesFullyResolved = @import("Air/types_resolved.zig").typesFullyResolved;
pub const typesFullyResolved = types_resolved.typesFullyResolved;
pub const typeFullyResolved = types_resolved.checkType;
pub const valFullyResolved = types_resolved.checkVal;
12 changes: 8 additions & 4 deletions src/Air/types_resolved.zig
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,10 @@ fn checkRef(ref: Air.Inst.Ref, zcu: *Zcu) bool {
return checkVal(Value.fromInterned(ip_index), zcu);
}

fn checkVal(val: Value, zcu: *Zcu) bool {
if (!checkType(val.typeOf(zcu), zcu)) return false;
pub fn checkVal(val: Value, zcu: *Zcu) bool {
const ty = val.typeOf(zcu);
if (!checkType(ty, zcu)) return false;
if (ty.toIntern() == .type_type and !checkType(val.toType(), zcu)) return false;
// Check for lazy values
switch (zcu.intern_pool.indexToKey(val.toIntern())) {
.int => |int| switch (int.storage) {
Expand All @@ -446,9 +448,11 @@ fn checkVal(val: Value, zcu: *Zcu) bool {
}
}

fn checkType(ty: Type, zcu: *Zcu) bool {
pub fn checkType(ty: Type, zcu: *Zcu) bool {
const ip = &zcu.intern_pool;
return switch (ty.zigTypeTag(zcu)) {
return switch (ty.zigTypeTagOrPoison(zcu) catch |err| switch (err) {
error.GenericPoison => return true,
}) {
.Type,
.Void,
.Bool,
Expand Down
64 changes: 23 additions & 41 deletions src/Value.zig
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,12 @@ pub fn toBigIntAdvanced(
zcu: *Zcu,
tid: strat.Tid(),
) Zcu.CompileError!BigIntConst {
const ip = &zcu.intern_pool;
return switch (val.toIntern()) {
.bool_false => BigIntMutable.init(&space.limbs, 0).toConst(),
.bool_true => BigIntMutable.init(&space.limbs, 1).toConst(),
.null_value => BigIntMutable.init(&space.limbs, 0).toConst(),
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
else => switch (ip.indexToKey(val.toIntern())) {
.int => |int| switch (int.storage) {
.u64, .i64, .big_int => int.storage.toBigInt(space),
.lazy_align, .lazy_size => |ty| {
Expand All @@ -214,6 +215,7 @@ pub fn toBigIntAdvanced(
&space.limbs,
(try val.getUnsignedIntInner(strat, zcu, tid)).?,
).toConst(),
.err => |err| BigIntMutable.init(&space.limbs, ip.getErrorValueIfExists(err.name).?).toConst(),
else => unreachable,
},
};
Expand Down Expand Up @@ -326,15 +328,11 @@ pub fn toBool(val: Value) bool {
};
}

fn ptrHasIntAddr(val: Value, zcu: *Zcu) bool {
return zcu.intern_pool.getBackingAddrTag(val.toIntern()).? == .int;
}

/// Write a Value's contents to `buffer`.
///
/// 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, pt: Zcu.PerThread, buffer: []u8) error{
pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
ReinterpretDeclRef,
IllDefinedMemoryLayout,
Unimplemented,
Expand All @@ -343,19 +341,25 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
const zcu = pt.zcu;
const target = zcu.getTarget();
const endian = target.cpu.arch.endian();
const ip = &zcu.intern_pool;
const ty = val.typeOf(zcu);
if (val.isUndef(zcu)) {
const size: usize = @intCast(ty.abiSize(zcu));
@memset(buffer[0..size], 0xaa);
return;
}
const ip = &zcu.intern_pool;
switch (ty.zigTypeTag(zcu)) {
.Void => {},
.Bool => {
buffer[0] = @intFromBool(val.toBool());
},
.Int, .Enum => {
const int_info = ty.intInfo(zcu);
.Int, .Enum, .ErrorSet, .Pointer => |tag| {
const int_ty = if (tag == .Pointer) int_ty: {
if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout;
if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
break :int_ty Type.usize;
} else ty;
const int_info = int_ty.intInfo(zcu);
const bits = int_info.bits;
const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8);

Expand All @@ -379,7 +383,7 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
var buf_off: usize = 0;
while (elem_i < len) : (elem_i += 1) {
const elem_val = try val.elemValue(pt, elem_i);
try elem_val.writeToMemory(elem_ty, pt, buffer[buf_off..]);
try elem_val.writeToMemory(pt, buffer[buf_off..]);
buf_off += elem_size;
}
},
Expand All @@ -403,31 +407,14 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
.elems => |elems| elems[field_index],
.repeated_elem => |elem| elem,
});
const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
try writeToMemory(field_val, field_ty, pt, buffer[off..]);
try writeToMemory(field_val, pt, buffer[off..]);
},
.@"packed" => {
const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8;
return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0);
},
}
},
.ErrorSet => {
const bits = zcu.errorSetBits();
const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8);

const name = switch (ip.indexToKey(val.toIntern())) {
.err => |err| err.name,
.error_union => |error_union| error_union.val.err_name,
else => unreachable,
};
var bigint_buffer: BigIntSpace = undefined;
const bigint = BigIntMutable.init(
&bigint_buffer.limbs,
ip.getErrorValueIfExists(name).?,
).toConst();
bigint.writeTwosComplement(buffer[0..byte_count], endian);
},
.Union => switch (ty.containerLayout(zcu)) {
.auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already
.@"extern" => {
Expand All @@ -437,11 +424,11 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
const field_val = try val.fieldValue(pt, field_index);
const byte_count: usize = @intCast(field_type.abiSize(zcu));
return writeToMemory(field_val, field_type, pt, buffer[0..byte_count]);
return writeToMemory(field_val, pt, buffer[0..byte_count]);
} else {
const backing_ty = try ty.unionBackingType(pt);
const byte_count: usize = @intCast(backing_ty.abiSize(zcu));
return writeToMemory(val.unionValue(zcu), backing_ty, pt, buffer[0..byte_count]);
return writeToMemory(val.unionValue(zcu), pt, buffer[0..byte_count]);
}
},
.@"packed" => {
Expand All @@ -450,19 +437,13 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0);
},
},
.Pointer => {
if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout;
if (!val.ptrHasIntAddr(zcu)) return error.ReinterpretDeclRef;
return val.writeToMemory(Type.usize, pt, buffer);
},
.Optional => {
if (!ty.isPtrLikeOptional(zcu)) return error.IllDefinedMemoryLayout;
const child = ty.optionalChild(zcu);
const opt_val = val.optionalValue(zcu);
if (opt_val) |some| {
return some.writeToMemory(child, pt, buffer);
return some.writeToMemory(pt, buffer);
} else {
return writeToMemory(try pt.intValue(Type.usize, 0), Type.usize, pt, buffer);
return writeToMemory(try pt.intValue(Type.usize, 0), pt, buffer);
}
},
else => return error.Unimplemented,
Expand Down Expand Up @@ -582,7 +563,7 @@ pub fn writeToPackedMemory(
},
.Pointer => {
assert(!ty.isSlice(zcu)); // No well defined layout.
if (!val.ptrHasIntAddr(zcu)) return error.ReinterpretDeclRef;
if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
return val.writeToPackedMemory(Type.usize, pt, buffer, bit_offset);
},
.Optional => {
Expand Down Expand Up @@ -3658,14 +3639,15 @@ pub fn mulAddScalar(

/// 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, pt: Zcu.PerThread) !?u8 {
pub fn hasRepeatedByteRepr(val: Value, pt: Zcu.PerThread) !?u8 {
const zcu = pt.zcu;
const ty = val.typeOf(zcu);
const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null;
assert(abi_size >= 1);
const byte_buffer = try zcu.gpa.alloc(u8, abi_size);
defer zcu.gpa.free(byte_buffer);

writeToMemory(val, ty, pt, byte_buffer) catch |err| switch (err) {
writeToMemory(val, pt, byte_buffer) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.ReinterpretDeclRef => return null,
// TODO: The writeToMemory function was originally created for the purpose
Expand Down
15 changes: 12 additions & 3 deletions src/Zcu/PerThread.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2560,12 +2560,17 @@ pub fn populateTestFunctions(
pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
const zcu = pt.zcu;
const comp = zcu.comp;
const ip = &zcu.intern_pool;

const nav = zcu.intern_pool.getNav(nav_index);
const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(&zcu.intern_pool), 0);
const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(ip), 0);
defer codegen_prog_node.end();

if (comp.bin_file) |lf| {
if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {
// The value of this nav failed to resolve. This is a transitive failure.
// TODO: do we need to mark this failure anywhere? I don't think so, since compilation
// will fail due to the type error anyway.
} else if (comp.bin_file) |lf| {
lf.updateNav(pt, nav_index) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
Expand Down Expand Up @@ -2605,7 +2610,11 @@ pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) !void
const codegen_prog_node = zcu.codegen_prog_node.start(Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), 0);
defer codegen_prog_node.end();

if (comp.bin_file) |lf| {
if (!Air.typeFullyResolved(Type.fromInterned(ty), zcu)) {
// This type failed to resolve. This is a transitive failure.
// TODO: do we need to mark this failure anywhere? I don't think so, since compilation
// will fail due to the type error anyway.
} else if (comp.bin_file) |lf| {
lf.updateContainerType(pt, ty) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
else => |e| log.err("codegen type failed: {s}", .{@errorName(e)}),
Expand Down
2 changes: 1 addition & 1 deletion src/arch/wasm/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3357,7 +3357,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.vector_type => {
assert(determineSimdStoreStrategy(ty, zcu, func.target.*) == .direct);
var buf: [16]u8 = undefined;
val.writeToMemory(ty, pt, &buf) catch unreachable;
val.writeToMemory(pt, &buf) catch unreachable;
return func.storeSimdImmd(buf);
},
.struct_type => {
Expand Down
Loading

0 comments on commit 1a178d4

Please sign in to comment.