Skip to content

Commit

Permalink
Parser: pointer value improvements
Browse files Browse the repository at this point in the history
Arrays decay to pointer values
Handle address-of locals as well as globals
  • Loading branch information
ehaas committed Oct 16, 2024
1 parent 0ee9317 commit 8cb454d
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 33 deletions.
56 changes: 29 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.reloc(.{ .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,29 @@ 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.*,
.compound_literal_expr,
.static_compound_literal_expr,
.thread_local_compound_literal_expr,
.static_thread_local_compound_literal_expr,
=> return Value.reloc(.{ .decl = @intFromEnum(node), .offset = .zero }, p.comp),
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 +7159,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 +7173,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
2 changes: 1 addition & 1 deletion src/backend/Interner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub const Key = union(enum) {
cf128: [2]f128,
};
pub const Pointer = struct {
/// NodeIndex of decl whose address we are offsetting from
/// NodeIndex of decl or compound literal whose address we are offsetting from
decl: u32,
/// Offset in bytes
offset: Ref,
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: )
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
3 changes: 3 additions & 0 deletions test/cases/relocations.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ 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, "");
#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" \
Expand Down

0 comments on commit 8cb454d

Please sign in to comment.