diff --git a/src/aro/Parser.zig b/src/aro/Parser.zig index 3fba464c..95e56c92 100644 --- a/src/aro/Parser.zig +++ b/src/aro/Parser.zig @@ -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; @@ -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..]); } @@ -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 { @@ -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..]); } @@ -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)) { @@ -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); @@ -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); @@ -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 @@ -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); @@ -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); @@ -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); } diff --git a/src/aro/Tree.zig b/src/aro/Tree.zig index 3bab9453..106064c0 100644 --- a/src/aro/Tree.zig +++ b/src/aro/Tree.zig @@ -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) { diff --git a/src/aro/Value.zig b/src/aro/Value.zig index 1cf44cde..f3ec0bef 100644 --- a/src/aro/Value.zig +++ b/src/aro/Value.zig @@ -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 }); } @@ -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. @@ -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 { @@ -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; } @@ -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, @@ -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); @@ -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, @@ -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; @@ -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 { diff --git a/src/aro/target.zig b/src/aro/target.zig index f92d5744..e1cee824 100644 --- a/src/aro/target.zig +++ b/src/aro/target.zig @@ -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); @@ -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); diff --git a/src/backend/Interner.zig b/src/backend/Interner.zig index 3315a08d..2ca2ac99 100644 --- a/src/backend/Interner.zig +++ b/src/backend/Interner.zig @@ -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) { diff --git a/test/cases/ast/_Float16.c b/test/cases/ast/_Float16.c index d2dea202..717297f9 100644 --- a/test/cases/ast/_Float16.c +++ b/test/cases/ast/_Float16.c @@ -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: &va) decl_ref_expr: 'va_list': '[1]struct __va_list_tag' lvalue name: va decl_ref_expr: 'int' lvalue @@ -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: &va) decl_ref_expr: 'va_list': '[1]struct __va_list_tag' lvalue name: va diff --git a/test/cases/ast/stdckdint_ast.c b/test/cases/ast/stdckdint_ast.c index 496e288f..efcf0212 100644 --- a/test/cases/ast/stdckdint_ast.c +++ b/test/cases/ast/stdckdint_ast.c @@ -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: &res) operand: decl_ref_expr: 'long' lvalue name: res @@ -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: &res) operand: decl_ref_expr: 'long' lvalue name: res @@ -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: &res) operand: decl_ref_expr: 'long' lvalue name: res diff --git a/test/cases/relocations.c b/test/cases/relocations.c index 6c049d22..d0af50da 100644 --- a/test/cases/relocations.c +++ b/test/cases/relocations.c @@ -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" \