mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
stage2: LLVM backend: lower constant field/elem ptrs
This commit is contained in:
parent
07691db3ae
commit
e9d1e5e533
@ -1085,6 +1085,26 @@ pub const DeclGen = struct {
|
||||
const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False);
|
||||
return llvm_int.constIntToPtr(try self.llvmType(tv.ty));
|
||||
},
|
||||
.field_ptr => {
|
||||
const field_ptr = tv.val.castTag(.field_ptr).?.data;
|
||||
const parent_ptr = try self.lowerParentPtr(field_ptr.container_ptr);
|
||||
const llvm_u32 = self.context.intType(32);
|
||||
const indices: [2]*const llvm.Value = .{
|
||||
llvm_u32.constInt(0, .False),
|
||||
llvm_u32.constInt(field_ptr.field_index, .False),
|
||||
};
|
||||
return parent_ptr.constInBoundsGEP(&indices, indices.len);
|
||||
},
|
||||
.elem_ptr => {
|
||||
const elem_ptr = tv.val.castTag(.elem_ptr).?.data;
|
||||
const parent_ptr = try self.lowerParentPtr(elem_ptr.array_ptr);
|
||||
const llvm_usize = try self.llvmType(Type.usize);
|
||||
const indices: [2]*const llvm.Value = .{
|
||||
llvm_usize.constInt(0, .False),
|
||||
llvm_usize.constInt(elem_ptr.index, .False),
|
||||
};
|
||||
return parent_ptr.constInBoundsGEP(&indices, indices.len);
|
||||
},
|
||||
else => |tag| return self.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }),
|
||||
},
|
||||
.Array => switch (tv.val.tag()) {
|
||||
@ -1298,6 +1318,68 @@ pub const DeclGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
const ParentPtr = struct {
|
||||
ty: Type,
|
||||
llvm_ptr: *const llvm.Value,
|
||||
};
|
||||
|
||||
fn lowerParentPtrDecl(
|
||||
dg: *DeclGen,
|
||||
ptr_val: Value,
|
||||
decl: *Module.Decl,
|
||||
) Error!ParentPtr {
|
||||
var ptr_ty_payload: Type.Payload.ElemType = .{
|
||||
.base = .{ .tag = .single_mut_pointer },
|
||||
.data = decl.ty,
|
||||
};
|
||||
const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
|
||||
const llvm_ptr = try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl);
|
||||
return ParentPtr{
|
||||
.llvm_ptr = llvm_ptr,
|
||||
.ty = decl.ty,
|
||||
};
|
||||
}
|
||||
|
||||
fn lowerParentPtr(dg: *DeclGen, ptr_val: Value) Error!*const llvm.Value {
|
||||
switch (ptr_val.tag()) {
|
||||
.decl_ref_mut => {
|
||||
const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl;
|
||||
return (try dg.lowerParentPtrDecl(ptr_val, decl)).llvm_ptr;
|
||||
},
|
||||
.decl_ref => {
|
||||
const decl = ptr_val.castTag(.decl_ref).?.data;
|
||||
return (try dg.lowerParentPtrDecl(ptr_val, decl)).llvm_ptr;
|
||||
},
|
||||
.variable => {
|
||||
const decl = ptr_val.castTag(.variable).?.data.owner_decl;
|
||||
return (try dg.lowerParentPtrDecl(ptr_val, decl)).llvm_ptr;
|
||||
},
|
||||
.field_ptr => {
|
||||
const field_ptr = ptr_val.castTag(.field_ptr).?.data;
|
||||
const parent_ptr = try dg.lowerParentPtr(field_ptr.container_ptr);
|
||||
const llvm_u32 = dg.context.intType(32);
|
||||
const indices: [2]*const llvm.Value = .{
|
||||
llvm_u32.constInt(0, .False),
|
||||
llvm_u32.constInt(field_ptr.field_index, .False),
|
||||
};
|
||||
return parent_ptr.constInBoundsGEP(&indices, indices.len);
|
||||
},
|
||||
.elem_ptr => {
|
||||
const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
|
||||
const parent_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr);
|
||||
const llvm_usize = try dg.llvmType(Type.usize);
|
||||
const indices: [2]*const llvm.Value = .{
|
||||
llvm_usize.constInt(0, .False),
|
||||
llvm_usize.constInt(elem_ptr.index, .False),
|
||||
};
|
||||
return parent_ptr.constInBoundsGEP(&indices, indices.len);
|
||||
},
|
||||
.opt_payload_ptr => return dg.todo("implement lowerParentPtr for optional payload", .{}),
|
||||
.eu_payload_ptr => return dg.todo("implement lowerParentPtr for error union payload", .{}),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerDeclRefValue(
|
||||
self: *DeclGen,
|
||||
tv: TypedValue,
|
||||
@ -1323,12 +1405,13 @@ pub const DeclGen = struct {
|
||||
return self.context.constStruct(&fields, fields.len, .False);
|
||||
}
|
||||
|
||||
decl.alive = true;
|
||||
const llvm_type = try self.llvmType(tv.ty);
|
||||
if (!tv.ty.childType().hasCodeGenBits()) {
|
||||
return self.lowerPtrToVoid(tv.ty);
|
||||
}
|
||||
|
||||
decl.alive = true;
|
||||
|
||||
const llvm_val = if (decl.ty.zigTypeTag() == .Fn)
|
||||
try self.resolveLlvmFunction(decl)
|
||||
else
|
||||
|
||||
@ -39,6 +39,7 @@ test {
|
||||
_ = @import("behavior/math.zig");
|
||||
_ = @import("behavior/maximum_minimum.zig");
|
||||
_ = @import("behavior/member_func.zig");
|
||||
_ = @import("behavior/null.zig");
|
||||
_ = @import("behavior/optional.zig");
|
||||
_ = @import("behavior/pointers.zig");
|
||||
_ = @import("behavior/pub_enum.zig");
|
||||
@ -137,7 +138,7 @@ test {
|
||||
_ = @import("behavior/misc.zig");
|
||||
_ = @import("behavior/muladd.zig");
|
||||
_ = @import("behavior/namespace_depends_on_compile_var.zig");
|
||||
_ = @import("behavior/null.zig");
|
||||
_ = @import("behavior/null_stage1.zig");
|
||||
_ = @import("behavior/optional_stage1.zig");
|
||||
_ = @import("behavior/pointers_stage1.zig");
|
||||
_ = @import("behavior/popcount.zig");
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
const expect = @import("std").testing.expect;
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
test "optional type" {
|
||||
const x: ?bool = true;
|
||||
@ -58,31 +59,6 @@ fn foo(x: ?i32) ?bool {
|
||||
return value > 1234;
|
||||
}
|
||||
|
||||
test "if var maybe pointer" {
|
||||
try expect(shouldBeAPlus1(Particle{
|
||||
.a = 14,
|
||||
.b = 1,
|
||||
.c = 1,
|
||||
.d = 1,
|
||||
}) == 15);
|
||||
}
|
||||
fn shouldBeAPlus1(p: Particle) u64 {
|
||||
var maybe_particle: ?Particle = p;
|
||||
if (maybe_particle) |*particle| {
|
||||
particle.a += 1;
|
||||
}
|
||||
if (maybe_particle) |particle| {
|
||||
return particle.a;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const Particle = struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
d: u64,
|
||||
};
|
||||
|
||||
test "null literal outside function" {
|
||||
const is_null = here_is_a_null_literal.context == null;
|
||||
try expect(is_null);
|
||||
@ -146,17 +122,6 @@ test "null with default unwrap" {
|
||||
try expect(x == 1);
|
||||
}
|
||||
|
||||
test "optional types" {
|
||||
comptime {
|
||||
const opt_type_struct = StructWithOptionalType{ .t = u8 };
|
||||
try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8);
|
||||
}
|
||||
}
|
||||
|
||||
const StructWithOptionalType = struct {
|
||||
t: ?type,
|
||||
};
|
||||
|
||||
test "optional pointer to 0 bit type null value at runtime" {
|
||||
const EmptyStruct = struct {};
|
||||
var x: ?*EmptyStruct = null;
|
||||
|
||||
37
test/behavior/null_stage1.zig
Normal file
37
test/behavior/null_stage1.zig
Normal file
@ -0,0 +1,37 @@
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
test "if var maybe pointer" {
|
||||
try expect(shouldBeAPlus1(Particle{
|
||||
.a = 14,
|
||||
.b = 1,
|
||||
.c = 1,
|
||||
.d = 1,
|
||||
}) == 15);
|
||||
}
|
||||
fn shouldBeAPlus1(p: Particle) u64 {
|
||||
var maybe_particle: ?Particle = p;
|
||||
if (maybe_particle) |*particle| {
|
||||
particle.a += 1;
|
||||
}
|
||||
if (maybe_particle) |particle| {
|
||||
return particle.a;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const Particle = struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
d: u64,
|
||||
};
|
||||
|
||||
test "optional types" {
|
||||
comptime {
|
||||
const opt_type_struct = StructWithOptionalType{ .t = u8 };
|
||||
try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8);
|
||||
}
|
||||
}
|
||||
|
||||
const StructWithOptionalType = struct {
|
||||
t: ?type,
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user