Skip to content

Commit 9183701

Browse files
committed
llvm: implement comptime field lowering
Closes #12963
1 parent e90583f commit 9183701

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed

src/codegen.zig

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,14 @@ fn lowerParentPtr(
756756
}),
757757
);
758758
},
759-
.comptime_field => unreachable,
759+
.comptime_field => |field_val| try lowerComptimeFieldRef(
760+
bin_file,
761+
src_loc,
762+
Type.fromInterned(ptr.ty),
763+
field_val,
764+
code,
765+
reloc_info,
766+
),
760767
};
761768
}
762769

@@ -769,6 +776,44 @@ const RelocInfo = struct {
769776
}
770777
};
771778

779+
fn lowerComptimeFieldRef(
780+
lf: *link.File,
781+
src_loc: Module.SrcLoc,
782+
ptr_ty: Type,
783+
field_val: InternPool.Index,
784+
code: *std.ArrayList(u8),
785+
reloc_info: RelocInfo,
786+
) CodeGenError!Result {
787+
const zcu = lf.comp.module.?;
788+
const target = lf.comp.root_mod.resolved_target.result;
789+
790+
const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
791+
const decl_ty = Type.fromInterned(zcu.intern_pool.typeOf(field_val));
792+
log.debug("lowerComptimeFieldRef: ty = {}", .{decl_ty.fmt(zcu)});
793+
794+
const alignment = ptr_ty.ptrAlignment(zcu);
795+
const res = try lf.lowerAnonDecl(field_val, alignment, src_loc);
796+
switch (res) {
797+
.ok => {},
798+
.fail => |em| return .{ .fail = em },
799+
}
800+
801+
const vaddr = try lf.getAnonDeclVAddr(field_val, .{
802+
.parent_atom_index = reloc_info.parent_atom_index,
803+
.offset = code.items.len,
804+
.addend = reloc_info.addend orelse 0,
805+
});
806+
const endian = target.cpu.arch.endian();
807+
switch (ptr_width_bytes) {
808+
2 => mem.writeInt(u16, try code.addManyAsArray(2), @intCast(vaddr), endian),
809+
4 => mem.writeInt(u32, try code.addManyAsArray(4), @intCast(vaddr), endian),
810+
8 => mem.writeInt(u64, try code.addManyAsArray(8), vaddr, endian),
811+
else => unreachable,
812+
}
813+
814+
return Result.ok;
815+
}
816+
772817
fn lowerAnonDeclRef(
773818
lf: *link.File,
774819
src_loc: Module.SrcLoc,

src/codegen/llvm.zig

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3816,7 +3816,10 @@ pub const Object = struct {
38163816
.elem,
38173817
.field,
38183818
=> try o.lowerParentPtr(val),
3819-
.comptime_field => unreachable,
3819+
.comptime_field => |field_val| {
3820+
const ptr_ty = Type.fromInterned(ptr.ty);
3821+
return o.lowerComptimeFieldRef(ptr_ty, field_val);
3822+
},
38203823
},
38213824
.slice => |slice| return o.builder.structConst(try o.lowerType(ty), &.{
38223825
try o.lowerValue(slice.ptr),
@@ -4311,7 +4314,10 @@ pub const Object = struct {
43114314

43124315
return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, null, &.{ .@"0", .@"0" });
43134316
},
4314-
.comptime_field => unreachable,
4317+
.comptime_field => |field_val| {
4318+
const ptr_ty = Type.fromInterned(ptr.ty);
4319+
return o.lowerComptimeFieldRef(ptr_ty, field_val);
4320+
},
43154321
.elem => |elem_ptr| {
43164322
const parent_ptr = try o.lowerParentPtr(Value.fromInterned(elem_ptr.base));
43174323
const elem_ty = Type.fromInterned(ip.typeOf(elem_ptr.base)).elemType2(mod);
@@ -4388,6 +4394,25 @@ pub const Object = struct {
43884394
};
43894395
}
43904396

4397+
fn lowerComptimeFieldRef(o: *Object, ptr_ty: Type, field_val: InternPool.Index) Error!Builder.Constant {
4398+
const mod = o.module;
4399+
const target = mod.getTarget();
4400+
const llvm_addr_space = toLlvmAddressSpace(ptr_ty.ptrAddressSpace(mod), target);
4401+
const alignment = ptr_ty.ptrAlignment(mod);
4402+
const llvm_global = (try o.resolveGlobalAnonDecl(field_val, llvm_addr_space, alignment)).ptrConst(&o.builder).global;
4403+
4404+
const llvm_val = try o.builder.convConst(
4405+
.unneeded,
4406+
llvm_global.toConst(),
4407+
try o.builder.ptrType(llvm_addr_space),
4408+
);
4409+
4410+
return o.builder.convConst(if (ptr_ty.isAbiInt(mod)) switch (ptr_ty.intInfo(mod).signedness) {
4411+
.signed => .signed,
4412+
.unsigned => .unsigned,
4413+
} else .unneeded, llvm_val, try o.lowerType(ptr_ty));
4414+
}
4415+
43914416
/// This logic is very similar to `lowerDeclRefValue` but for anonymous declarations.
43924417
/// Maybe the logic could be unified.
43934418
fn lowerAnonDeclRef(

test/behavior/struct.zig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2150,3 +2150,17 @@ test "matching captures causes struct equivalence" {
21502150
comptime assert(@TypeOf(a) == @TypeOf(b));
21512151
try expect(a.x == b.x);
21522152
}
2153+
2154+
test "pointer to comptime field loaded at runtime" {
2155+
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2156+
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2157+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2158+
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
2159+
2160+
const T = struct {
2161+
comptime a: u32 = 2,
2162+
};
2163+
var t: T = undefined;
2164+
const ptr = &t.a;
2165+
try expect(ptr.* == 2);
2166+
}

0 commit comments

Comments
 (0)