Skip to content

Commit

Permalink
Merge pull request #789 from ehaas/array-value
Browse files Browse the repository at this point in the history
Pointer value improvements
  • Loading branch information
Vexu authored Oct 17, 2024
2 parents 0ee9317 + 7f3e780 commit 0620577
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 75 deletions.
68 changes: 38 additions & 30 deletions src/aro/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const Symbol = SymbolStack.Symbol;
const record_layout = @import("record_layout.zig");
const StrInt = @import("StringInterner.zig");
const StringId = StrInt.StringId;
const Pointer = @import("backend").Interner.Key.Pointer;
const Builtins = @import("Builtins.zig");
const Builtin = Builtins.Builtin;
const evalBuiltin = @import("Builtins/eval.zig").eval;
Expand Down Expand Up @@ -505,9 +504,13 @@ pub fn valueChangedStr(p: *Parser, res: *Result, old_value: Value, int_ty: Type)
try w.writeAll(" changes ");
if (res.val.isZero(p.comp)) try w.writeAll("non-zero ");
try w.writeAll("value from ");
try old_value.print(res.ty, p.comp, w);
if (try old_value.print(res.ty, p.comp, w)) |nested| switch (nested) {
.pointer => unreachable,
};
try w.writeAll(" to ");
try res.val.print(int_ty, p.comp, w);
if (try res.val.print(int_ty, p.comp, w)) |nested| switch (nested) {
.pointer => unreachable,
};

return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
}
Expand Down Expand Up @@ -4768,6 +4771,15 @@ fn compoundStmt(p: *Parser, is_fn_body: bool, stmt_expr_state: ?*StmtExprState)
return try p.addNode(node);
}

fn pointerValue(p: *Parser, node: NodeIndex, offset: Value) !Value {
const tag = p.nodes.items(.tag)[@intFromEnum(node)];
if (tag != .decl_ref_expr) return .{};
const decl_ref = p.nodes.items(.data)[@intFromEnum(node)].decl_ref;
const var_name = try p.comp.internString(p.tokSlice(decl_ref));
const sym = p.syms.findSymbol(var_name) orelse return .{};
return Value.pointer(.{ .decl = @intFromEnum(sym.node), .offset = offset.ref() }, p.comp);
}

const NoreturnKind = enum { no, yes, complex };

fn nodeIsNoreturn(p: *Parser, node: NodeIndex) NoreturnKind {
Expand Down Expand Up @@ -5197,7 +5209,14 @@ pub const Result = struct {
const strings_top = p.strings.items.len;
defer p.strings.items.len = strings_top;

try res.val.print(res.ty, p.comp, p.strings.writer());
if (try res.val.print(res.ty, p.comp, p.strings.writer())) |nested| switch (nested) {
.pointer => |ptr| {
const decl_data = p.nodes.items(.data)[ptr.decl].decl;
const decl_name = p.tokSlice(decl_data.name);
try ptr.offset.printPointer(decl_name, p.comp, p.strings.writer());
},
};

return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
}

Expand Down Expand Up @@ -5550,7 +5569,7 @@ pub const Result = struct {
}
try res.implicitCast(p, .function_to_pointer);
} else if (res.ty.isArray()) {
res.val = .{};
res.val = try p.pointerValue(res.node, .zero);
res.ty.decayArray();
try res.implicitCast(p, .array_to_pointer);
} else if (!p.in_macro and p.tmpTree().isLval(res.node)) {
Expand Down Expand Up @@ -7057,7 +7076,7 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, offset_kind: OffsetKind)
return Result{ .ty = base_ty, .val = val, .node = lhs.node };
}

fn computeOffsetExtra(p: *Parser, node: NodeIndex, offset_so_far: *Value) !Pointer {
fn computeOffsetExtra(p: *Parser, node: NodeIndex, offset_so_far: *Value) !Value {
const tys = p.nodes.items(.ty);
const tags = p.nodes.items(.tag);
const data = p.nodes.items(.data);
Expand All @@ -7072,16 +7091,12 @@ fn computeOffsetExtra(p: *Parser, node: NodeIndex, offset_so_far: *Value) !Point
};
},
.paren_expr => return p.computeOffsetExtra(data[@intFromEnum(node)].un, offset_so_far),
.decl_ref_expr => {
const var_name = try p.comp.internString(p.tokSlice(data[@intFromEnum(node)].decl_ref));
const sym = p.syms.findSymbol(var_name).?; // symbol must exist if we get here; otherwise it's a syntax error
return .{ .decl = @intFromEnum(sym.node), .offset = offset_so_far.ref() };
},
.decl_ref_expr => return p.pointerValue(node, offset_so_far.*),
.array_access_expr => {
const bin_data = data[@intFromEnum(node)].bin;
const ty = tys[@intFromEnum(node)];

const index_val = p.value_map.get(bin_data.rhs) orelse return error.InvalidReloc;
const index_val = p.value_map.get(bin_data.rhs) orelse return .{};
var size = try Value.int(ty.sizeof(p.comp).?, p.comp);
const mul_overflow = try size.mul(size, index_val, p.comp.types.ptrdiff, p.comp);

Expand All @@ -7090,22 +7105,23 @@ fn computeOffsetExtra(p: *Parser, node: NodeIndex, offset_so_far: *Value) !Point
_ = add_overflow;
return p.computeOffsetExtra(bin_data.lhs, offset_so_far);
},
.member_access_expr => {
.member_access_expr, .member_access_ptr_expr => {
const member = data[@intFromEnum(node)].member;
const record = tys[@intFromEnum(member.lhs)].getRecord().?;
// const field_offset: i64 = @intCast(@divExact(record.fields[member.index].layout.offset_bits, 8));
var ty = tys[@intFromEnum(member.lhs)];
if (ty.isPtr()) ty = ty.elemType();
const record = ty.getRecord().?;
const field_offset = try Value.int(@divExact(record.fields[member.index].layout.offset_bits, 8), p.comp);
_ = try offset_so_far.add(field_offset, offset_so_far.*, p.comp.types.ptrdiff, p.comp);
return p.computeOffsetExtra(member.lhs, offset_so_far);
},
else => return error.InvalidReloc,
else => return .{},
}
}

/// Compute the offset (in bytes) of an expression from a base pointer.
fn computeOffset(p: *Parser, node: NodeIndex) !Pointer {
var val: Value = .zero;
return p.computeOffsetExtra(node, &val);
fn computeOffset(p: *Parser, res: Result) !Value {
var val: Value = if (res.val.opt_ref == .none) .zero else res.val;
return p.computeOffsetExtra(res.node, &val);
}

/// unExpr
Expand Down Expand Up @@ -7148,7 +7164,6 @@ fn unExpr(p: *Parser) Error!Result {
try p.err(.invalid_preproc_operator);
return error.ParsingFailed;
}
const ampersand_tok = p.tok_i;
p.tok_i += 1;
var operand = try p.castExpr();
try operand.expect(p);
Expand All @@ -7163,16 +7178,8 @@ fn unExpr(p: *Parser) Error!Result {
const operand_ty_valid = !operand.ty.is(.invalid);
if (!tree.isLval(operand.node) and operand_ty_valid) {
try p.errTok(.addr_of_rvalue, tok);
} else if (operand_ty_valid and p.func.ty == null) {
// address of global
const reloc: Pointer = p.computeOffset(operand.node) catch |e| switch (e) {
error.InvalidReloc => blk: {
try p.errTok(.non_constant_initializer, ampersand_tok);
break :blk .{ .decl = @intFromEnum(NodeIndex.none), .offset = .zero };
},
else => |er| return er,
};
addr_val = try Value.reloc(reloc, p.comp);
} else if (operand_ty_valid) {
addr_val = try p.computeOffset(operand);
}
if (operand.ty.qual.register) try p.errTok(.addr_of_register, tok);

Expand All @@ -7198,6 +7205,7 @@ fn unExpr(p: *Parser) Error!Result {
if (operand.ty.isArray() or operand.ty.isPtr() or operand.ty.isFunc()) {
try operand.lvalConversion(p);
operand.ty = operand.ty.elemType();
operand.val = .{};
} else {
try p.errTok(.indirection_ptr, tok);
}
Expand Down
8 changes: 7 additions & 1 deletion src/aro/Tree.zig
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,13 @@ fn dumpNode(
if (tree.value_map.get(node)) |val| {
try config.setColor(w, LITERAL);
try w.writeAll(" (value: ");
try val.print(ty, tree.comp, w);
if (try val.print(ty, tree.comp, w)) |nested| switch (nested) {
.pointer => |ptr| {
const decl = tree.nodes.items(.data)[ptr.decl].decl;
const decl_name = tree.tokSlice(decl.name);
try ptr.offset.printPointer(decl_name, tree.comp, w);
},
};
try w.writeByte(')');
}
if (tag == .implicit_return and data.return_zero) {
Expand Down
88 changes: 51 additions & 37 deletions src/aro/Value.zig
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub fn int(i: anytype, comp: *Compilation) !Value {
}
}

pub fn reloc(r: Interner.Key.Pointer, comp: *Compilation) !Value {
pub fn pointer(r: Interner.Key.Pointer, comp: *Compilation) !Value {
return intern(comp, .{ .pointer = r });
}

Expand Down Expand Up @@ -259,7 +259,7 @@ pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !IntCastChangeKind
const dest_signed = dest_ty.signedness(comp) == .signed;

var space: BigIntSpace = undefined;
const big = keyToBigInt(key, &space);
const big = key.toBigInt(&space);
const value_bits = big.bitCountTwosComp();

// if big is negative, then is signed.
Expand Down Expand Up @@ -390,12 +390,8 @@ fn bigIntToFloat(limbs: []const std.math.big.Limb, positive: bool) f128 {
}
}

fn keyToBigInt(key: Interner.Key, space: *BigIntSpace) BigIntConst {
return key.int.toBigInt(space);
}

fn toBigInt(val: Value, space: *BigIntSpace, comp: *const Compilation) BigIntConst {
return keyToBigInt(comp.interner.get(val.ref()), space);
return comp.interner.get(val.ref()).toBigInt(space);
}

pub fn isZero(v: Value, comp: *const Compilation) bool {
Expand Down Expand Up @@ -486,7 +482,7 @@ pub fn toInt(v: Value, comptime T: type, comp: *const Compilation) ?T {
const key = comp.interner.get(v.ref());
if (key != .int) return null;
var space: BigIntSpace = undefined;
const big_int = keyToBigInt(key, &space);
const big_int = key.toBigInt(&space);
return big_int.to(T) catch null;
}

Expand Down Expand Up @@ -554,14 +550,14 @@ pub fn add(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b
const old_offset = fromRef(rel.offset);
const add_overflow = try total_offset.add(total_offset, old_offset, comp.types.ptrdiff, comp);
_ = try total_offset.intCast(comp.types.ptrdiff, comp);
res.* = try reloc(.{ .decl = rel.decl, .offset = total_offset.ref() }, comp);
res.* = try pointer(.{ .decl = rel.decl, .offset = total_offset.ref() }, comp);
return mul_overflow or add_overflow;
}

var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = keyToBigInt(lhs_key, &lhs_space);
const rhs_bigint = keyToBigInt(rhs_key, &rhs_space);
const lhs_bigint = lhs_key.toBigInt(&lhs_space);
const rhs_bigint = rhs_key.toBigInt(&rhs_space);

const limbs = try comp.gpa.alloc(
std.math.big.Limb,
Expand Down Expand Up @@ -612,14 +608,14 @@ pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, elem_size: u64, comp:
const lhs_key = comp.interner.get(lhs.ref());
const rhs_key = comp.interner.get(rhs.ref());
if (lhs_key == .pointer and rhs_key == .pointer) {
const lhs_reloc = lhs_key.pointer;
const rhs_reloc = rhs_key.pointer;
if (lhs_reloc.decl != rhs_reloc.decl) {
const lhs_pointer = lhs_key.pointer;
const rhs_pointer = rhs_key.pointer;
if (lhs_pointer.decl != rhs_pointer.decl) {
res.* = .{};
return false;
}
const lhs_offset = fromRef(lhs_reloc.offset);
const rhs_offset = fromRef(rhs_reloc.offset);
const lhs_offset = fromRef(lhs_pointer.offset);
const rhs_offset = fromRef(rhs_pointer.offset);
const overflowed = try res.sub(lhs_offset, rhs_offset, comp.types.ptrdiff, undefined, comp);
const rhs_size = try int(elem_size, comp);
_ = try res.div(res.*, rhs_size, comp.types.ptrdiff, comp);
Expand All @@ -633,14 +629,14 @@ pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, elem_size: u64, comp:
const old_offset = fromRef(rel.offset);
const add_overflow = try total_offset.sub(old_offset, total_offset, comp.types.ptrdiff, undefined, comp);
_ = try total_offset.intCast(comp.types.ptrdiff, comp);
res.* = try reloc(.{ .decl = rel.decl, .offset = total_offset.ref() }, comp);
res.* = try pointer(.{ .decl = rel.decl, .offset = total_offset.ref() }, comp);
return mul_overflow or add_overflow;
}

var lhs_space: BigIntSpace = undefined;
var rhs_space: BigIntSpace = undefined;
const lhs_bigint = keyToBigInt(lhs_key, &lhs_space);
const rhs_bigint = keyToBigInt(rhs_key, &rhs_space);
const lhs_bigint = lhs_key.toBigInt(&lhs_space);
const rhs_bigint = rhs_key.toBigInt(&rhs_space);

const limbs = try comp.gpa.alloc(
std.math.big.Limb,
Expand Down Expand Up @@ -1007,16 +1003,16 @@ pub fn comparePointers(lhs: Value, op: std.math.CompareOperator, rhs: Value, com
const rhs_key = comp.interner.get(rhs.ref());

if (lhs_key == .pointer and rhs_key == .pointer) {
const lhs_reloc = lhs_key.pointer;
const rhs_reloc = rhs_key.pointer;
const lhs_pointer = lhs_key.pointer;
const rhs_pointer = rhs_key.pointer;
switch (op) {
.eq => if (lhs_reloc.decl != rhs_reloc.decl) return false,
.neq => if (lhs_reloc.decl != rhs_reloc.decl) return true,
else => if (lhs_reloc.decl != rhs_reloc.decl) return null,
.eq => if (lhs_pointer.decl != rhs_pointer.decl) return false,
.neq => if (lhs_pointer.decl != rhs_pointer.decl) return true,
else => if (lhs_pointer.decl != rhs_pointer.decl) return null,
}

const lhs_offset = fromRef(lhs_reloc.offset);
const rhs_offset = fromRef(rhs_reloc.offset);
const lhs_offset = fromRef(lhs_pointer.offset);
const rhs_offset = fromRef(rhs_pointer.offset);
return lhs_offset.compare(op, rhs_offset, comp);
}
return null;
Expand Down Expand Up @@ -1058,29 +1054,47 @@ pub fn maxInt(ty: Type, comp: *Compilation) !Value {
return twosCompIntLimit(.max, ty, comp);
}

pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {
const NestedPrint = union(enum) {
pointer: struct {
decl: u32,
offset: Value,
},
};

pub fn printPointer(offset: Value, base: []const u8, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {
try w.writeByte('&');
try w.writeAll(base);
if (!offset.isZero(comp)) {
const maybe_nested = try offset.print(comp.types.ptrdiff, comp, w);
std.debug.assert(maybe_nested == null);
}
}

pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!?NestedPrint {
if (ty.is(.bool)) {
return w.writeAll(if (v.isZero(comp)) "false" else "true");
try w.writeAll(if (v.isZero(comp)) "false" else "true");
return null;
}
const key = comp.interner.get(v.ref());
switch (key) {
.null => return w.writeAll("nullptr_t"),
.null => try w.writeAll("nullptr_t"),
.int => |repr| switch (repr) {
inline else => |x| return w.print("{d}", .{x}),
inline else => |x| try w.print("{d}", .{x}),
},
.float => |repr| switch (repr) {
.f16 => |x| return w.print("{d}", .{@round(@as(f64, @floatCast(x)) * 1000) / 1000}),
.f32 => |x| return w.print("{d}", .{@round(@as(f64, @floatCast(x)) * 1000000) / 1000000}),
inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}),
.f16 => |x| try w.print("{d}", .{@round(@as(f64, @floatCast(x)) * 1000) / 1000}),
.f32 => |x| try w.print("{d}", .{@round(@as(f64, @floatCast(x)) * 1000000) / 1000000}),
inline else => |x| try w.print("{d}", .{@as(f64, @floatCast(x))}),
},
.bytes => |b| return printString(b, ty, comp, w),
.bytes => |b| try printString(b, ty, comp, w),
.complex => |repr| switch (repr) {
.cf32 => |components| return w.print("{d} + {d}i", .{ @round(@as(f64, @floatCast(components[0])) * 1000000) / 1000000, @round(@as(f64, @floatCast(components[1])) * 1000000) / 1000000 }),
inline else => |components| return w.print("{d} + {d}i", .{ @as(f64, @floatCast(components[0])), @as(f64, @floatCast(components[1])) }),
.cf32 => |components| try w.print("{d} + {d}i", .{ @round(@as(f64, @floatCast(components[0])) * 1000000) / 1000000, @round(@as(f64, @floatCast(components[1])) * 1000000) / 1000000 }),
inline else => |components| try w.print("{d} + {d}i", .{ @as(f64, @floatCast(components[0])), @as(f64, @floatCast(components[1])) }),
},
.pointer => {},
.pointer => |ptr| return .{ .pointer = .{ .decl = ptr.decl, .offset = fromRef(ptr.offset) } },
else => unreachable, // not a value
}
return null;
}

pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {
Expand Down
4 changes: 2 additions & 2 deletions src/aro/target.zig
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ pub fn isPICDefaultForced(target: std.Target) DefaultPIStatus {
test "alignment functions - smoke test" {
var target: std.Target = undefined;
const x86 = std.Target.Cpu.Arch.x86_64;
target.cpu = std.Target.Cpu.baseline(x86);
target.cpu = std.Target.Cpu.baseline(x86, .{ .tag = .linux, .version_range = std.Target.Os.VersionRange.default(.linux, x86) });
target.os = std.Target.Os.Tag.defaultVersionRange(.linux, x86);
target.abi = std.Target.Abi.default(x86, target.os);

Expand All @@ -961,7 +961,7 @@ test "alignment functions - smoke test" {
try std.testing.expect(systemCompiler(target) == .gcc);

const arm = std.Target.Cpu.Arch.arm;
target.cpu = std.Target.Cpu.baseline(arm);
target.cpu = std.Target.Cpu.baseline(arm, .{ .tag = .linux, .version_range = std.Target.Os.VersionRange.default(.linux, arm) });
target.os = std.Target.Os.Tag.defaultVersionRange(.ios, arm);
target.abi = std.Target.Abi.default(arm, target.os);

Expand Down
4 changes: 4 additions & 0 deletions src/backend/Interner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ pub const Key = union(enum) {
}
return null;
}

pub fn toBigInt(key: Key, space: *Tag.Int.BigIntSpace) BigIntConst {
return key.int.toBigInt(space);
}
};

pub const Ref = enum(u32) {
Expand Down
Loading

0 comments on commit 0620577

Please sign in to comment.