Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pointer value improvements #789

Merged
merged 6 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 24 additions & 27 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 @@ -4768,6 +4767,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 @@ -5550,7 +5558,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 +7065,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 +7080,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 +7094,24 @@ 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,
.deref_expr, .addr_of_expr => return offset_so_far.*,
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 +7154,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 +7168,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 Down
30 changes: 15 additions & 15 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 @@ -554,7 +554,7 @@ 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;
}

Expand Down Expand Up @@ -612,14 +612,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,7 +633,7 @@ 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;
}

Expand Down Expand Up @@ -1007,16 +1007,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
4 changes: 2 additions & 2 deletions test/cases/ast/_Float16.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn_def: 'fn (x: int, ...) void'
builtin_call_expr: 'void'
name: __builtin_va_start
args:
implicit_cast: (array_to_pointer) 'va_list': '*d[1]struct __va_list_tag'
implicit_cast: (array_to_pointer) 'va_list': '*d[1]struct __va_list_tag' (value: )
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice if pointer values printed the offset (if non-zero).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to ask about this - should I just print the offset (without the name of the variable)?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Printing the NodeIndex probably won't be too useful so I guess just the offset is good for now. Maybe add something to distinguish it from just ints.

Copy link
Collaborator Author

@ehaas ehaas Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we change the return type of Value.print from @TypeOf(w).Error!void to something like @TypeOf(w).Error!?NestedPrint where NestedPrint is

const NestedPrint = union(enum) {
    pointer: struct {
        node: u32,
        offset: Value,
    },
};

and then the caller can handle it?

decl_ref_expr: 'va_list': '[1]struct __va_list_tag' lvalue
name: va
decl_ref_expr: 'int' lvalue
Expand All @@ -39,7 +39,7 @@ fn_def: 'fn (x: int, ...) void'
builtin_call_expr_one: 'void'
name: __builtin_va_end
arg:
implicit_cast: (array_to_pointer) 'va_list': '*d[1]struct __va_list_tag'
implicit_cast: (array_to_pointer) 'va_list': '*d[1]struct __va_list_tag' (value: )
decl_ref_expr: 'va_list': '[1]struct __va_list_tag' lvalue
name: va

Expand Down
6 changes: 3 additions & 3 deletions test/cases/ast/stdckdint_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn_def: 'fn () void'
implicit_cast: (lval_to_rval) 'unsigned int'
decl_ref_expr: 'unsigned int' lvalue
name: y
addr_of_expr: '*long'
addr_of_expr: '*long' (value: )
operand:
decl_ref_expr: 'long' lvalue
name: res
Expand All @@ -53,7 +53,7 @@ fn_def: 'fn () void'
implicit_cast: (lval_to_rval) 'unsigned int'
decl_ref_expr: 'unsigned int' lvalue
name: y
addr_of_expr: '*long'
addr_of_expr: '*long' (value: )
operand:
decl_ref_expr: 'long' lvalue
name: res
Expand All @@ -72,7 +72,7 @@ fn_def: 'fn () void'
implicit_cast: (lval_to_rval) 'unsigned int'
decl_ref_expr: 'unsigned int' lvalue
name: y
addr_of_expr: '*long'
addr_of_expr: '*long' (value: )
operand:
decl_ref_expr: 'long' lvalue
name: res
Expand Down
10 changes: 10 additions & 0 deletions test/cases/relocations.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,19 @@ union Empty empty[10];
_Static_assert(&empty[4] - &empty[0] == 0, "");
_Static_assert(&empty[4] >= &empty[0], "");

_Static_assert(arr == arr, "");
_Static_assert(arr + 1 < arr + 2, "");
_Static_assert(arr != &x, "");

void foo(void) {
int local;
_Static_assert(&local < &local + 1, "");
_Static_assert(&(int){5} != &(int){5}, "");
}
#define EXPECTED_ERRORS "relocations.c:24:1: error: static assertion failed" \
"relocations.c:29:16: error: static_assert expression is not an integral constant expression" \
"relocations.c:30:16: error: static_assert expression is not an integral constant expression" \
"relocations.c:50:26: warning: subtraction of pointers to type 'union Empty' of zero size has undefined behavior [-Wpointer-arith]" \
"relocations.c:50:16: error: static_assert expression is not an integral constant expression" \
"relocations.c:60:20: error: static_assert expression is not an integral constant expression" \

Loading