mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
stage2: rework Value Payload layout
This is the same as the previous commit but for Value instead of Type. Add `Value.castTag` and note that it is preferable to call than `Value.cast`. This matches other abstractions in the codebase. Added a convenience function `Value.Tag.create` which really cleans up the callsites of creating `Value` objects. `Value` tags can now share payload types. This is in preparation for another improvement that I want to do.
This commit is contained in:
parent
133da8692e
commit
3f7d9b5fc1
@ -1457,11 +1457,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
|
||||
|
||||
.complete, .codegen_failure_retryable => {
|
||||
const module = self.bin_file.options.module.?;
|
||||
if (decl.typed_value.most_recent.typed_value.val.cast(Value.Payload.Function)) |payload| {
|
||||
switch (payload.func.analysis) {
|
||||
.queued => module.analyzeFnBody(decl, payload.func) catch |err| switch (err) {
|
||||
if (decl.typed_value.most_recent.typed_value.val.castTag(.function)) |payload| {
|
||||
const func = payload.data;
|
||||
switch (func.analysis) {
|
||||
.queued => module.analyzeFnBody(decl, func) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
assert(payload.func.analysis != .in_progress);
|
||||
assert(func.analysis != .in_progress);
|
||||
continue;
|
||||
},
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
@ -1475,7 +1476,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
|
||||
var decl_arena = decl.typed_value.most_recent.arena.?.promote(module.gpa);
|
||||
defer decl.typed_value.most_recent.arena.?.* = decl_arena.state;
|
||||
log.debug("analyze liveness of {}\n", .{decl.name});
|
||||
try liveness.analyze(module.gpa, &decl_arena.allocator, payload.func.analysis.success);
|
||||
try liveness.analyze(module.gpa, &decl_arena.allocator, func.analysis.success);
|
||||
}
|
||||
|
||||
assert(decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits());
|
||||
|
||||
193
src/Module.zig
193
src/Module.zig
@ -1092,16 +1092,12 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
||||
|
||||
tvm.deinit(self.gpa);
|
||||
}
|
||||
const value_payload = try decl_arena.allocator.create(Value.Payload.ExternFn);
|
||||
value_payload.* = .{ .decl = decl };
|
||||
const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl);
|
||||
|
||||
decl_arena_state.* = decl_arena.state;
|
||||
decl.typed_value = .{
|
||||
.most_recent = .{
|
||||
.typed_value = .{
|
||||
.ty = fn_type,
|
||||
.val = Value.initPayload(&value_payload.base),
|
||||
},
|
||||
.typed_value = .{ .ty = fn_type, .val = fn_val },
|
||||
.arena = decl_arena_state,
|
||||
},
|
||||
};
|
||||
@ -1187,7 +1183,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
||||
.analysis = .{ .queued = fn_zir },
|
||||
.owner_decl = decl,
|
||||
};
|
||||
fn_payload.* = .{ .func = new_func };
|
||||
fn_payload.* = .{
|
||||
.base = .{ .tag = .function },
|
||||
.data = new_func,
|
||||
};
|
||||
|
||||
var prev_type_has_bits = false;
|
||||
var type_changed = true;
|
||||
@ -1375,7 +1374,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
||||
}
|
||||
|
||||
const new_variable = try decl_arena.allocator.create(Var);
|
||||
const var_payload = try decl_arena.allocator.create(Value.Payload.Variable);
|
||||
new_variable.* = .{
|
||||
.owner_decl = decl,
|
||||
.init = var_info.val orelse undefined,
|
||||
@ -1383,14 +1381,14 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
||||
.is_mutable = is_mutable,
|
||||
.is_threadlocal = is_threadlocal,
|
||||
};
|
||||
var_payload.* = .{ .variable = new_variable };
|
||||
const var_val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
|
||||
|
||||
decl_arena_state.* = decl_arena.state;
|
||||
decl.typed_value = .{
|
||||
.most_recent = .{
|
||||
.typed_value = .{
|
||||
.ty = var_info.ty,
|
||||
.val = Value.initPayload(&var_payload.base),
|
||||
.val = var_val,
|
||||
},
|
||||
.arena = decl_arena_state,
|
||||
},
|
||||
@ -2232,52 +2230,43 @@ pub fn constBool(self: *Module, scope: *Scope, src: usize, v: bool) !*Inst {
|
||||
}
|
||||
|
||||
pub fn constIntUnsigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: u64) !*Inst {
|
||||
const int_payload = try scope.arena().create(Value.Payload.Int_u64);
|
||||
int_payload.* = .{ .int = int };
|
||||
|
||||
return self.constInst(scope, src, .{
|
||||
.ty = ty,
|
||||
.val = Value.initPayload(&int_payload.base),
|
||||
.val = try Value.Tag.int_u64.create(scope.arena(), int),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn constIntSigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: i64) !*Inst {
|
||||
const int_payload = try scope.arena().create(Value.Payload.Int_i64);
|
||||
int_payload.* = .{ .int = int };
|
||||
|
||||
return self.constInst(scope, src, .{
|
||||
.ty = ty,
|
||||
.val = Value.initPayload(&int_payload.base),
|
||||
.val = try Value.Tag.int_i64.create(scope.arena(), int),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigIntConst) !*Inst {
|
||||
const val_payload = if (big_int.positive) blk: {
|
||||
if (big_int.positive) {
|
||||
if (big_int.to(u64)) |x| {
|
||||
return self.constIntUnsigned(scope, src, ty, x);
|
||||
} else |err| switch (err) {
|
||||
error.NegativeIntoUnsigned => unreachable,
|
||||
error.TargetTooSmall => {}, // handled below
|
||||
}
|
||||
const big_int_payload = try scope.arena().create(Value.Payload.IntBigPositive);
|
||||
big_int_payload.* = .{ .limbs = big_int.limbs };
|
||||
break :blk &big_int_payload.base;
|
||||
} else blk: {
|
||||
return self.constInst(scope, src, .{
|
||||
.ty = ty,
|
||||
.val = try Value.Tag.int_big_positive.create(scope.arena(), big_int.limbs),
|
||||
});
|
||||
} else {
|
||||
if (big_int.to(i64)) |x| {
|
||||
return self.constIntSigned(scope, src, ty, x);
|
||||
} else |err| switch (err) {
|
||||
error.NegativeIntoUnsigned => unreachable,
|
||||
error.TargetTooSmall => {}, // handled below
|
||||
}
|
||||
const big_int_payload = try scope.arena().create(Value.Payload.IntBigNegative);
|
||||
big_int_payload.* = .{ .limbs = big_int.limbs };
|
||||
break :blk &big_int_payload.base;
|
||||
};
|
||||
|
||||
return self.constInst(scope, src, .{
|
||||
.ty = ty,
|
||||
.val = Value.initPayload(val_payload),
|
||||
});
|
||||
return self.constInst(scope, src, .{
|
||||
.ty = ty,
|
||||
.val = try Value.Tag.int_big_negative.create(scope.arena(), big_int.limbs),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn createAnonymousDecl(
|
||||
@ -2346,26 +2335,20 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
|
||||
if (decl_tv.val.tag() == .variable) {
|
||||
return self.analyzeVarRef(scope, src, decl_tv);
|
||||
}
|
||||
const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One);
|
||||
const val_payload = try scope.arena().create(Value.Payload.DeclRef);
|
||||
val_payload.* = .{ .decl = decl };
|
||||
|
||||
return self.constInst(scope, src, .{
|
||||
.ty = ty,
|
||||
.val = Value.initPayload(&val_payload.base),
|
||||
.ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One),
|
||||
.val = try Value.Tag.decl_ref.create(scope.arena(), decl),
|
||||
});
|
||||
}
|
||||
|
||||
fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst {
|
||||
const variable = tv.val.cast(Value.Payload.Variable).?.variable;
|
||||
const variable = tv.val.castTag(.variable).?.data;
|
||||
|
||||
const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One);
|
||||
if (!variable.is_mutable and !variable.is_extern) {
|
||||
const val_payload = try scope.arena().create(Value.Payload.RefVal);
|
||||
val_payload.* = .{ .val = variable.init };
|
||||
return self.constInst(scope, src, .{
|
||||
.ty = ty,
|
||||
.val = Value.initPayload(&val_payload.base),
|
||||
.val = try Value.Tag.ref_val.create(scope.arena(), variable.init),
|
||||
});
|
||||
}
|
||||
|
||||
@ -3107,17 +3090,11 @@ pub fn intAdd(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
|
||||
result_bigint.add(lhs_bigint, rhs_bigint);
|
||||
const result_limbs = result_bigint.limbs[0..result_bigint.len];
|
||||
|
||||
const val_payload = if (result_bigint.positive) blk: {
|
||||
const val_payload = try allocator.create(Value.Payload.IntBigPositive);
|
||||
val_payload.* = .{ .limbs = result_limbs };
|
||||
break :blk &val_payload.base;
|
||||
} else blk: {
|
||||
const val_payload = try allocator.create(Value.Payload.IntBigNegative);
|
||||
val_payload.* = .{ .limbs = result_limbs };
|
||||
break :blk &val_payload.base;
|
||||
};
|
||||
|
||||
return Value.initPayload(val_payload);
|
||||
if (result_bigint.positive) {
|
||||
return Value.Tag.int_big_positive.create(allocator, result_limbs);
|
||||
} else {
|
||||
return Value.Tag.int_big_negative.create(allocator, result_limbs);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
|
||||
@ -3135,85 +3112,81 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
|
||||
result_bigint.sub(lhs_bigint, rhs_bigint);
|
||||
const result_limbs = result_bigint.limbs[0..result_bigint.len];
|
||||
|
||||
const val_payload = if (result_bigint.positive) blk: {
|
||||
const val_payload = try allocator.create(Value.Payload.IntBigPositive);
|
||||
val_payload.* = .{ .limbs = result_limbs };
|
||||
break :blk &val_payload.base;
|
||||
} else blk: {
|
||||
const val_payload = try allocator.create(Value.Payload.IntBigNegative);
|
||||
val_payload.* = .{ .limbs = result_limbs };
|
||||
break :blk &val_payload.base;
|
||||
};
|
||||
|
||||
return Value.initPayload(val_payload);
|
||||
if (result_bigint.positive) {
|
||||
return Value.Tag.int_big_positive.create(allocator, result_limbs);
|
||||
} else {
|
||||
return Value.Tag.int_big_negative.create(allocator, result_limbs);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
|
||||
var bit_count = switch (float_type.tag()) {
|
||||
.comptime_float => 128,
|
||||
else => float_type.floatBits(self.getTarget()),
|
||||
};
|
||||
|
||||
const allocator = scope.arena();
|
||||
const val_payload = switch (bit_count) {
|
||||
16 => {
|
||||
return self.fail(scope, src, "TODO Implement addition for soft floats", .{});
|
||||
pub fn floatAdd(
|
||||
self: *Module,
|
||||
scope: *Scope,
|
||||
float_type: Type,
|
||||
src: usize,
|
||||
lhs: Value,
|
||||
rhs: Value,
|
||||
) !Value {
|
||||
const arena = scope.arena();
|
||||
switch (float_type.tag()) {
|
||||
.f16 => {
|
||||
@panic("TODO add __trunctfhf2 to compiler-rt");
|
||||
//const lhs_val = lhs.toFloat(f16);
|
||||
//const rhs_val = rhs.toFloat(f16);
|
||||
//return Value.Tag.float_16.create(arena, lhs_val + rhs_val);
|
||||
},
|
||||
32 => blk: {
|
||||
.f32 => {
|
||||
const lhs_val = lhs.toFloat(f32);
|
||||
const rhs_val = rhs.toFloat(f32);
|
||||
const val_payload = try allocator.create(Value.Payload.Float_32);
|
||||
val_payload.* = .{ .val = lhs_val + rhs_val };
|
||||
break :blk &val_payload.base;
|
||||
return Value.Tag.float_32.create(arena, lhs_val + rhs_val);
|
||||
},
|
||||
64 => blk: {
|
||||
.f64 => {
|
||||
const lhs_val = lhs.toFloat(f64);
|
||||
const rhs_val = rhs.toFloat(f64);
|
||||
const val_payload = try allocator.create(Value.Payload.Float_64);
|
||||
val_payload.* = .{ .val = lhs_val + rhs_val };
|
||||
break :blk &val_payload.base;
|
||||
return Value.Tag.float_64.create(arena, lhs_val + rhs_val);
|
||||
},
|
||||
128 => {
|
||||
return self.fail(scope, src, "TODO Implement addition for big floats", .{});
|
||||
.f128, .comptime_float, .c_longdouble => {
|
||||
const lhs_val = lhs.toFloat(f128);
|
||||
const rhs_val = rhs.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, lhs_val + rhs_val);
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
return Value.initPayload(val_payload);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
|
||||
var bit_count = switch (float_type.tag()) {
|
||||
.comptime_float => 128,
|
||||
else => float_type.floatBits(self.getTarget()),
|
||||
};
|
||||
|
||||
const allocator = scope.arena();
|
||||
const val_payload = switch (bit_count) {
|
||||
16 => {
|
||||
return self.fail(scope, src, "TODO Implement substraction for soft floats", .{});
|
||||
pub fn floatSub(
|
||||
self: *Module,
|
||||
scope: *Scope,
|
||||
float_type: Type,
|
||||
src: usize,
|
||||
lhs: Value,
|
||||
rhs: Value,
|
||||
) !Value {
|
||||
const arena = scope.arena();
|
||||
switch (float_type.tag()) {
|
||||
.f16 => {
|
||||
@panic("TODO add __trunctfhf2 to compiler-rt");
|
||||
//const lhs_val = lhs.toFloat(f16);
|
||||
//const rhs_val = rhs.toFloat(f16);
|
||||
//return Value.Tag.float_16.create(arena, lhs_val - rhs_val);
|
||||
},
|
||||
32 => blk: {
|
||||
.f32 => {
|
||||
const lhs_val = lhs.toFloat(f32);
|
||||
const rhs_val = rhs.toFloat(f32);
|
||||
const val_payload = try allocator.create(Value.Payload.Float_32);
|
||||
val_payload.* = .{ .val = lhs_val - rhs_val };
|
||||
break :blk &val_payload.base;
|
||||
return Value.Tag.float_32.create(arena, lhs_val - rhs_val);
|
||||
},
|
||||
64 => blk: {
|
||||
.f64 => {
|
||||
const lhs_val = lhs.toFloat(f64);
|
||||
const rhs_val = rhs.toFloat(f64);
|
||||
const val_payload = try allocator.create(Value.Payload.Float_64);
|
||||
val_payload.* = .{ .val = lhs_val - rhs_val };
|
||||
break :blk &val_payload.base;
|
||||
return Value.Tag.float_64.create(arena, lhs_val - rhs_val);
|
||||
},
|
||||
128 => {
|
||||
return self.fail(scope, src, "TODO Implement substraction for big floats", .{});
|
||||
.f128, .comptime_float, .c_longdouble => {
|
||||
const lhs_val = lhs.toFloat(f128);
|
||||
const rhs_val = rhs.toFloat(f128);
|
||||
return Value.Tag.float_128.create(arena, lhs_val - rhs_val);
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
return Value.initPayload(val_payload);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type {
|
||||
|
||||
@ -1956,13 +1956,13 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
|
||||
32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type),
|
||||
64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),
|
||||
else => {
|
||||
const int_type_payload = try scope.arena().create(Value.Payload.IntType);
|
||||
int_type_payload.* = .{ .signed = is_signed, .bits = bit_count };
|
||||
const result = try addZIRInstConst(mod, scope, src, .{
|
||||
return rlWrap(mod, scope, rl, try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initPayload(&int_type_payload.base),
|
||||
});
|
||||
return rlWrap(mod, scope, rl, result);
|
||||
.val = try Value.Tag.int_type.create(scope.arena(), .{
|
||||
.signed = is_signed,
|
||||
.bits = bit_count,
|
||||
}),
|
||||
}));
|
||||
},
|
||||
};
|
||||
const result = try addZIRInstConst(mod, scope, src, .{
|
||||
@ -2062,11 +2062,9 @@ fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst
|
||||
},
|
||||
};
|
||||
|
||||
const int_payload = try scope.arena().create(Value.Payload.Int_u64);
|
||||
int_payload.* = .{ .int = value };
|
||||
return addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.comptime_int),
|
||||
.val = Value.initPayload(&int_payload.base),
|
||||
.val = try Value.Tag.int_u64.create(scope.arena(), value),
|
||||
});
|
||||
}
|
||||
|
||||
@ -2089,12 +2087,10 @@ fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) Inne
|
||||
prefixed_bytes[2..];
|
||||
|
||||
if (std.fmt.parseInt(u64, bytes, base)) |small_int| {
|
||||
const int_payload = try arena.create(Value.Payload.Int_u64);
|
||||
int_payload.* = .{ .int = small_int };
|
||||
const src = tree.token_locs[int_lit.token].start;
|
||||
return addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.comptime_int),
|
||||
.val = Value.initPayload(&int_payload.base),
|
||||
.val = try Value.Tag.int_u64.create(arena, small_int),
|
||||
});
|
||||
} else |err| {
|
||||
return mod.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{});
|
||||
@ -2109,15 +2105,13 @@ fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.OneToken) Inne
|
||||
return mod.failTok(scope, float_lit.token, "TODO hex floats", .{});
|
||||
}
|
||||
|
||||
const val = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
|
||||
const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
|
||||
error.InvalidCharacter => unreachable, // validated by tokenizer
|
||||
};
|
||||
const float_payload = try arena.create(Value.Payload.Float_128);
|
||||
float_payload.* = .{ .val = val };
|
||||
const src = tree.token_locs[float_lit.token].start;
|
||||
return addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.comptime_float),
|
||||
.val = Value.initPayload(&float_payload.base),
|
||||
.val = try Value.Tag.float_128.create(arena, float_number),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -137,7 +137,7 @@ pub fn generateSymbol(
|
||||
},
|
||||
.Array => {
|
||||
// TODO populate .debug_info for the array
|
||||
if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
|
||||
if (typed_value.val.castTag(.bytes)) |payload| {
|
||||
if (typed_value.ty.sentinel()) |sentinel| {
|
||||
try code.ensureCapacity(code.items.len + payload.data.len + 1);
|
||||
code.appendSliceAssumeCapacity(payload.data);
|
||||
@ -168,8 +168,8 @@ pub fn generateSymbol(
|
||||
},
|
||||
.Pointer => {
|
||||
// TODO populate .debug_info for the pointer
|
||||
if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
|
||||
const decl = payload.decl;
|
||||
if (typed_value.val.castTag(.decl_ref)) |payload| {
|
||||
const decl = payload.data;
|
||||
if (decl.analysis != .complete) return error.AnalysisFail;
|
||||
// TODO handle the dependency of this symbol on the decl's vaddr.
|
||||
// If the decl changes vaddr, then this symbol needs to get regenerated.
|
||||
@ -432,7 +432,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
@panic("Attempted to compile for architecture that was disabled by build configuration");
|
||||
}
|
||||
|
||||
const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
|
||||
const module_fn = typed_value.val.castTag(.function).?.data;
|
||||
|
||||
const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty;
|
||||
|
||||
@ -1579,9 +1579,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
}
|
||||
}
|
||||
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
const func = func_payload.data;
|
||||
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
@ -1607,9 +1607,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
.riscv64 => {
|
||||
if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
|
||||
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
const func = func_payload.data;
|
||||
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
@ -1631,12 +1631,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
}
|
||||
},
|
||||
.spu_2 => {
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (info.args.len != 0) {
|
||||
return self.fail(inst.base.src, "TODO implement call with more than 0 parameters", .{});
|
||||
}
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
const func = func_payload.data;
|
||||
const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
|
||||
const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
|
||||
break :blk @intCast(u16, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * 2);
|
||||
@ -1705,9 +1705,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
}
|
||||
}
|
||||
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
const func = func_payload.data;
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
|
||||
@ -1766,9 +1766,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
}
|
||||
}
|
||||
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
const func = func_payload.data;
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
|
||||
@ -1825,9 +1825,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
}
|
||||
}
|
||||
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
const func = func_payload.data;
|
||||
const text_segment = &macho_file.load_commands.items[macho_file.text_segment_cmd_index.?].Segment;
|
||||
const got = &text_segment.sections.items[macho_file.got_section_index.?];
|
||||
const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
|
||||
@ -3223,20 +3223,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
switch (typed_value.ty.zigTypeTag()) {
|
||||
.Pointer => {
|
||||
if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
|
||||
if (typed_value.val.castTag(.decl_ref)) |payload| {
|
||||
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
const decl = payload.decl;
|
||||
const decl = payload.data;
|
||||
const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
|
||||
const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
|
||||
return MCValue{ .memory = got_addr };
|
||||
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
const decl = payload.decl;
|
||||
const decl = payload.data;
|
||||
const text_segment = &macho_file.load_commands.items[macho_file.text_segment_cmd_index.?].Segment;
|
||||
const got = &text_segment.sections.items[macho_file.got_section_index.?];
|
||||
const got_addr = got.addr + decl.link.macho.offset_table_index * ptr_bytes;
|
||||
return MCValue{ .memory = got_addr };
|
||||
} else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
|
||||
const decl = payload.decl;
|
||||
const decl = payload.data;
|
||||
const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
|
||||
return MCValue{ .memory = got_addr };
|
||||
} else {
|
||||
|
||||
@ -138,25 +138,25 @@ fn renderValue(
|
||||
.undef, .zero => try writer.writeAll("0"),
|
||||
.one => try writer.writeAll("1"),
|
||||
.decl_ref => {
|
||||
const decl_ref_payload = val.cast(Value.Payload.DeclRef).?;
|
||||
const decl = val.castTag(.decl_ref).?.data;
|
||||
|
||||
// Determine if we must pointer cast.
|
||||
const decl_tv = decl_ref_payload.decl.typed_value.most_recent.typed_value;
|
||||
const decl_tv = decl.typed_value.most_recent.typed_value;
|
||||
if (t.eql(decl_tv.ty)) {
|
||||
try writer.print("&{s}", .{decl_ref_payload.decl.name});
|
||||
try writer.print("&{s}", .{decl.name});
|
||||
} else {
|
||||
try writer.writeAll("(");
|
||||
try renderType(ctx, writer, t);
|
||||
try writer.print(")&{s}", .{decl_ref_payload.decl.name});
|
||||
try writer.print(")&{s}", .{decl.name});
|
||||
}
|
||||
},
|
||||
.function => {
|
||||
const payload = val.cast(Value.Payload.Function).?;
|
||||
try writer.print("{s}", .{payload.func.owner_decl.name});
|
||||
const func = val.castTag(.function).?.data;
|
||||
try writer.print("{s}", .{func.owner_decl.name});
|
||||
},
|
||||
.extern_fn => {
|
||||
const payload = val.cast(Value.Payload.ExternFn).?;
|
||||
try writer.print("{s}", .{payload.decl.name});
|
||||
const decl = val.castTag(.extern_fn).?.data;
|
||||
try writer.print("{s}", .{decl.name});
|
||||
},
|
||||
else => |e| return ctx.fail(
|
||||
ctx.decl.src(),
|
||||
@ -169,7 +169,7 @@ fn renderValue(
|
||||
switch (val.tag()) {
|
||||
.undef, .empty_struct_value, .empty_array => try writer.writeAll("{}"),
|
||||
.bytes => {
|
||||
const bytes = val.cast(Value.Payload.Bytes).?.data;
|
||||
const bytes = val.castTag(.bytes).?.data;
|
||||
// TODO: make our own C string escape instead of using {Z}
|
||||
try writer.print("\"{Z}\"", .{bytes});
|
||||
},
|
||||
@ -209,7 +209,7 @@ fn renderFunctionSignature(
|
||||
switch (tv.val.tag()) {
|
||||
.extern_fn => break :blk true,
|
||||
.function => {
|
||||
const func = tv.val.cast(Value.Payload.Function).?.func;
|
||||
const func = tv.val.castTag(.function).?.data;
|
||||
break :blk ctx.module.decl_exports.contains(func.owner_decl);
|
||||
},
|
||||
else => unreachable,
|
||||
@ -268,13 +268,13 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
|
||||
ctx.deinit();
|
||||
}
|
||||
|
||||
if (tv.val.cast(Value.Payload.Function)) |func_payload| {
|
||||
if (tv.val.castTag(.function)) |func_payload| {
|
||||
const writer = file.main.writer();
|
||||
try renderFunctionSignature(&ctx, writer, decl);
|
||||
|
||||
try writer.writeAll(" {");
|
||||
|
||||
const func: *Module.Fn = func_payload.func;
|
||||
const func: *Module.Fn = func_payload.data;
|
||||
const instructions = func.analysis.success.instructions;
|
||||
if (instructions.len > 0) {
|
||||
try writer.writeAll("\n");
|
||||
@ -480,10 +480,10 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 {
|
||||
const writer = file.main.writer();
|
||||
const header = file.header.buf.writer();
|
||||
if (inst.func.castTag(.constant)) |func_inst| {
|
||||
const fn_decl = if (func_inst.val.cast(Value.Payload.ExternFn)) |extern_fn|
|
||||
extern_fn.decl
|
||||
else if (func_inst.val.cast(Value.Payload.Function)) |func_val|
|
||||
func_val.func.owner_decl
|
||||
const fn_decl = if (func_inst.val.castTag(.extern_fn)) |extern_fn|
|
||||
extern_fn.data
|
||||
else if (func_inst.val.castTag(.function)) |func_payload|
|
||||
func_payload.data.owner_decl
|
||||
else
|
||||
unreachable;
|
||||
|
||||
@ -513,8 +513,8 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 {
|
||||
if (i > 0) {
|
||||
try writer.writeAll(", ");
|
||||
}
|
||||
if (arg.cast(Inst.Constant)) |con| {
|
||||
try renderValue(ctx, writer, arg.ty, con.val);
|
||||
if (arg.value()) |val| {
|
||||
try renderValue(ctx, writer, arg.ty, val);
|
||||
} else {
|
||||
const val = try ctx.resolveInst(arg);
|
||||
try writer.print("{}", .{val});
|
||||
|
||||
@ -62,7 +62,7 @@ pub fn genCode(buf: *ArrayList(u8), decl: *Decl) !void {
|
||||
// Write instructions
|
||||
// TODO: check for and handle death of instructions
|
||||
const tv = decl.typed_value.most_recent.typed_value;
|
||||
const mod_fn = tv.val.cast(Value.Payload.Function).?.func;
|
||||
const mod_fn = tv.val.castTag(.function).?.data;
|
||||
for (mod_fn.analysis.success.instructions) |inst| try genInst(buf, decl, inst);
|
||||
|
||||
// Write 'end' opcode
|
||||
@ -125,8 +125,8 @@ fn genRet(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.UnOp) !void {
|
||||
|
||||
fn genCall(buf: *ArrayList(u8), decl: *Decl, inst: *Inst.Call) !void {
|
||||
const func_inst = inst.func.castTag(.constant).?;
|
||||
const func_val = func_inst.val.cast(Value.Payload.Function).?;
|
||||
const target = func_val.func.owner_decl;
|
||||
const func = func_inst.val.castTag(.function).?.data;
|
||||
const target = func.owner_decl;
|
||||
const target_ty = target.typed_value.most_recent.typed_value.ty;
|
||||
|
||||
if (inst.args.len != 0) return error.TODOImplementMoreWasmCodegen;
|
||||
|
||||
@ -2183,7 +2183,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
|
||||
for (zir_dumps) |fn_name| {
|
||||
if (mem.eql(u8, mem.spanZ(decl.name), fn_name)) {
|
||||
std.debug.print("\n{}\n", .{decl.name});
|
||||
typed_value.val.cast(Value.Payload.Function).?.func.dump(module.*);
|
||||
typed_value.val.castTag(.function).?.data.dump(module.*);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,7 +280,7 @@ pub const LLVMIRModule = struct {
|
||||
fn gen(self: *LLVMIRModule, module: *Module, typed_value: TypedValue, src: usize) !void {
|
||||
switch (typed_value.ty.zigTypeTag()) {
|
||||
.Fn => {
|
||||
const func = typed_value.val.cast(Value.Payload.Function).?.func;
|
||||
const func = typed_value.val.castTag(.function).?.data;
|
||||
|
||||
const llvm_func = try self.resolveLLVMFunction(func);
|
||||
|
||||
@ -314,9 +314,9 @@ pub const LLVMIRModule = struct {
|
||||
}
|
||||
|
||||
fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !void {
|
||||
if (inst.func.cast(Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
const func = func_payload.data;
|
||||
const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;
|
||||
const llvm_fn = try self.resolveLLVMFunction(func);
|
||||
|
||||
|
||||
43
src/type.zig
43
src/type.zig
@ -733,11 +733,7 @@ pub const Type = extern union {
|
||||
.single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
|
||||
.const_slice_u8 => return Value.initTag(.const_slice_u8_type),
|
||||
.enum_literal => return Value.initTag(.enum_literal_type),
|
||||
else => {
|
||||
const ty_payload = try allocator.create(Value.Payload.Ty);
|
||||
ty_payload.* = .{ .ty = self };
|
||||
return Value.initPayload(&ty_payload.base);
|
||||
},
|
||||
else => return Value.Tag.ty.create(allocator, self),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2951,11 +2947,8 @@ pub const Type = extern union {
|
||||
}
|
||||
|
||||
if ((info.bits - 1) <= std.math.maxInt(u6)) {
|
||||
const payload = try arena.allocator.create(Value.Payload.Int_i64);
|
||||
payload.* = .{
|
||||
.int = -(@as(i64, 1) << @truncate(u6, info.bits - 1)),
|
||||
};
|
||||
return Value.initPayload(&payload.base);
|
||||
const n: i64 = -(@as(i64, 1) << @truncate(u6, info.bits - 1));
|
||||
return Value.Tag.int_i64.create(&arena.allocator, n);
|
||||
}
|
||||
|
||||
var res = try std.math.big.int.Managed.initSet(&arena.allocator, 1);
|
||||
@ -2964,13 +2957,9 @@ pub const Type = extern union {
|
||||
|
||||
const res_const = res.toConst();
|
||||
if (res_const.positive) {
|
||||
const val_payload = try arena.allocator.create(Value.Payload.IntBigPositive);
|
||||
val_payload.* = .{ .limbs = res_const.limbs };
|
||||
return Value.initPayload(&val_payload.base);
|
||||
return Value.Tag.int_big_positive.create(&arena.allocator, res_const.limbs);
|
||||
} else {
|
||||
const val_payload = try arena.allocator.create(Value.Payload.IntBigNegative);
|
||||
val_payload.* = .{ .limbs = res_const.limbs };
|
||||
return Value.initPayload(&val_payload.base);
|
||||
return Value.Tag.int_big_negative.create(&arena.allocator, res_const.limbs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2980,17 +2969,11 @@ pub const Type = extern union {
|
||||
const info = self.intInfo(target);
|
||||
|
||||
if (info.signedness == .signed and (info.bits - 1) <= std.math.maxInt(u6)) {
|
||||
const payload = try arena.allocator.create(Value.Payload.Int_i64);
|
||||
payload.* = .{
|
||||
.int = (@as(i64, 1) << @truncate(u6, info.bits - 1)) - 1,
|
||||
};
|
||||
return Value.initPayload(&payload.base);
|
||||
const n: i64 = (@as(i64, 1) << @truncate(u6, info.bits - 1)) - 1;
|
||||
return Value.Tag.int_i64.create(&arena.allocator, n);
|
||||
} else if (info.signedness == .signed and info.bits <= std.math.maxInt(u6)) {
|
||||
const payload = try arena.allocator.create(Value.Payload.Int_u64);
|
||||
payload.* = .{
|
||||
.int = (@as(u64, 1) << @truncate(u6, info.bits)) - 1,
|
||||
};
|
||||
return Value.initPayload(&payload.base);
|
||||
const n: u64 = (@as(u64, 1) << @truncate(u6, info.bits)) - 1;
|
||||
return Value.Tag.int_u64.create(&arena.allocator, n);
|
||||
}
|
||||
|
||||
var res = try std.math.big.int.Managed.initSet(&arena.allocator, 1);
|
||||
@ -3003,13 +2986,9 @@ pub const Type = extern union {
|
||||
|
||||
const res_const = res.toConst();
|
||||
if (res_const.positive) {
|
||||
const val_payload = try arena.allocator.create(Value.Payload.IntBigPositive);
|
||||
val_payload.* = .{ .limbs = res_const.limbs };
|
||||
return Value.initPayload(&val_payload.base);
|
||||
return Value.Tag.int_big_positive.create(&arena.allocator, res_const.limbs);
|
||||
} else {
|
||||
const val_payload = try arena.allocator.create(Value.Payload.IntBigNegative);
|
||||
val_payload.* = .{ .limbs = res_const.limbs };
|
||||
return Value.initPayload(&val_payload.base);
|
||||
return Value.Tag.int_big_negative.create(&arena.allocator, res_const.limbs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
599
src/value.zig
599
src/value.zig
@ -84,11 +84,16 @@ pub const Value = extern union {
|
||||
function,
|
||||
extern_fn,
|
||||
variable,
|
||||
/// Represents a pointer to another immutable value.
|
||||
ref_val,
|
||||
/// Represents a pointer to a decl, not the value of the decl.
|
||||
decl_ref,
|
||||
elem_ptr,
|
||||
/// A slice of u8 whose memory is managed externally.
|
||||
bytes,
|
||||
repeated, // the value is a value repeated some number of times
|
||||
/// This value is repeated some number of times. The amount of times to repeat
|
||||
/// is stored externally.
|
||||
repeated,
|
||||
float_16,
|
||||
float_32,
|
||||
float_64,
|
||||
@ -99,6 +104,106 @@ pub const Value = extern union {
|
||||
|
||||
pub const last_no_payload_tag = Tag.bool_false;
|
||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||
|
||||
pub fn Type(comptime t: Tag) type {
|
||||
return switch (t) {
|
||||
.u8_type,
|
||||
.i8_type,
|
||||
.u16_type,
|
||||
.i16_type,
|
||||
.u32_type,
|
||||
.i32_type,
|
||||
.u64_type,
|
||||
.i64_type,
|
||||
.usize_type,
|
||||
.isize_type,
|
||||
.c_short_type,
|
||||
.c_ushort_type,
|
||||
.c_int_type,
|
||||
.c_uint_type,
|
||||
.c_long_type,
|
||||
.c_ulong_type,
|
||||
.c_longlong_type,
|
||||
.c_ulonglong_type,
|
||||
.c_longdouble_type,
|
||||
.f16_type,
|
||||
.f32_type,
|
||||
.f64_type,
|
||||
.f128_type,
|
||||
.c_void_type,
|
||||
.bool_type,
|
||||
.void_type,
|
||||
.type_type,
|
||||
.anyerror_type,
|
||||
.comptime_int_type,
|
||||
.comptime_float_type,
|
||||
.noreturn_type,
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.undef,
|
||||
.zero,
|
||||
.one,
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.empty_struct_value,
|
||||
.empty_array,
|
||||
.null_value,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
=> @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
|
||||
|
||||
.int_big_positive,
|
||||
.int_big_negative,
|
||||
=> Payload.BigInt,
|
||||
|
||||
.extern_fn,
|
||||
.decl_ref,
|
||||
=> Payload.Decl,
|
||||
|
||||
.ref_val,
|
||||
.repeated,
|
||||
=> Payload.SubValue,
|
||||
|
||||
.bytes,
|
||||
.enum_literal,
|
||||
=> Payload.Bytes,
|
||||
|
||||
.ty => Payload.Ty,
|
||||
.int_type => Payload.IntType,
|
||||
.int_u64 => Payload.U64,
|
||||
.int_i64 => Payload.I64,
|
||||
.function => Payload.Function,
|
||||
.variable => Payload.Variable,
|
||||
.elem_ptr => Payload.ElemPtr,
|
||||
.float_16 => Payload.Float_16,
|
||||
.float_32 => Payload.Float_32,
|
||||
.float_64 => Payload.Float_64,
|
||||
.float_128 => Payload.Float_128,
|
||||
.error_set => Payload.ErrorSet,
|
||||
.@"error" => Payload.Error,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Value {
|
||||
const ptr = try ally.create(t.Type());
|
||||
ptr.* = .{
|
||||
.base = .{ .tag = t },
|
||||
.data = data,
|
||||
};
|
||||
return Value{ .ptr_otherwise = &ptr.base };
|
||||
}
|
||||
|
||||
pub fn Data(comptime t: Tag) type {
|
||||
return std.meta.fieldInfo(t.Type(), "data").field_type;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn initTag(small_tag: Tag) Value {
|
||||
@ -119,15 +224,36 @@ pub const Value = extern union {
|
||||
}
|
||||
}
|
||||
|
||||
/// Prefer `castTag` to this.
|
||||
pub fn cast(self: Value, comptime T: type) ?*T {
|
||||
if (@hasField(T, "base_tag")) {
|
||||
return base.castTag(T.base_tag);
|
||||
}
|
||||
if (self.tag_if_small_enough < Tag.no_payload_count) {
|
||||
return null;
|
||||
}
|
||||
inline for (@typeInfo(Tag).Enum.fields) |field| {
|
||||
if (field.value < Tag.no_payload_count)
|
||||
continue;
|
||||
const t = @intToEnum(Tag, field.value);
|
||||
if (self.ptr_otherwise.tag == t) {
|
||||
if (T == t.Type()) {
|
||||
return @fieldParentPtr(T, "base", self.ptr_otherwise);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub fn castTag(self: Value, comptime t: Tag) ?*t.Type() {
|
||||
if (self.tag_if_small_enough < Tag.no_payload_count)
|
||||
return null;
|
||||
|
||||
const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag;
|
||||
if (self.ptr_otherwise.tag != expected_tag)
|
||||
return null;
|
||||
if (self.ptr_otherwise.tag == t)
|
||||
return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise);
|
||||
|
||||
return @fieldParentPtr(T, "base", self.ptr_otherwise);
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value {
|
||||
@ -188,17 +314,17 @@ pub const Value = extern union {
|
||||
=> unreachable,
|
||||
|
||||
.ty => {
|
||||
const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise);
|
||||
const payload = self.castTag(.ty).?;
|
||||
const new_payload = try allocator.create(Payload.Ty);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.ty = try payload.ty.copy(allocator),
|
||||
.data = try payload.data.copy(allocator),
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.int_type => return self.copyPayloadShallow(allocator, Payload.IntType),
|
||||
.int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),
|
||||
.int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),
|
||||
.int_u64 => return self.copyPayloadShallow(allocator, Payload.U64),
|
||||
.int_i64 => return self.copyPayloadShallow(allocator, Payload.I64),
|
||||
.int_big_positive => {
|
||||
@panic("TODO implement copying of big ints");
|
||||
},
|
||||
@ -206,35 +332,37 @@ pub const Value = extern union {
|
||||
@panic("TODO implement copying of big ints");
|
||||
},
|
||||
.function => return self.copyPayloadShallow(allocator, Payload.Function),
|
||||
.extern_fn => return self.copyPayloadShallow(allocator, Payload.ExternFn),
|
||||
.extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),
|
||||
.variable => return self.copyPayloadShallow(allocator, Payload.Variable),
|
||||
.ref_val => {
|
||||
const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.RefVal);
|
||||
const payload = self.castTag(.ref_val).?;
|
||||
const new_payload = try allocator.create(Payload.SubValue);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.val = try payload.val.copy(allocator),
|
||||
.data = try payload.data.copy(allocator),
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef),
|
||||
.decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),
|
||||
.elem_ptr => {
|
||||
const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
|
||||
const payload = self.castTag(.elem_ptr).?;
|
||||
const new_payload = try allocator.create(Payload.ElemPtr);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.array_ptr = try payload.array_ptr.copy(allocator),
|
||||
.index = payload.index,
|
||||
.data = .{
|
||||
.array_ptr = try payload.data.array_ptr.copy(allocator),
|
||||
.index = payload.data.index,
|
||||
},
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
|
||||
.repeated => {
|
||||
const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.Repeated);
|
||||
const payload = self.castTag(.repeated).?;
|
||||
const new_payload = try allocator.create(Payload.SubValue);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.val = try payload.val.copy(allocator),
|
||||
.data = try payload.data.copy(allocator),
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
@ -243,7 +371,7 @@ pub const Value = extern union {
|
||||
.float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),
|
||||
.float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128),
|
||||
.enum_literal => {
|
||||
const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise);
|
||||
const payload = self.castTag(.enum_literal).?;
|
||||
const new_payload = try allocator.create(Payload.Bytes);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
@ -259,7 +387,7 @@ pub const Value = extern union {
|
||||
}
|
||||
|
||||
fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value {
|
||||
const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
|
||||
const payload = self.cast(T).?;
|
||||
const new_payload = try allocator.create(T);
|
||||
new_payload.* = payload.*;
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
@ -326,45 +454,45 @@ pub const Value = extern union {
|
||||
.unreachable_value => return out_stream.writeAll("unreachable"),
|
||||
.bool_true => return out_stream.writeAll("true"),
|
||||
.bool_false => return out_stream.writeAll("false"),
|
||||
.ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream),
|
||||
.ty => return val.castTag(.ty).?.data.format("", options, out_stream),
|
||||
.int_type => {
|
||||
const int_type = val.cast(Payload.IntType).?;
|
||||
const int_type = val.castTag(.int_type).?.data;
|
||||
return out_stream.print("{}{}", .{
|
||||
if (int_type.signed) "s" else "u",
|
||||
int_type.bits,
|
||||
});
|
||||
},
|
||||
.int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream),
|
||||
.int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream),
|
||||
.int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
|
||||
.int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),
|
||||
.int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", options, out_stream),
|
||||
.int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream),
|
||||
.int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
|
||||
.int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
|
||||
.function => return out_stream.writeAll("(function)"),
|
||||
.extern_fn => return out_stream.writeAll("(extern function)"),
|
||||
.variable => return out_stream.writeAll("(variable)"),
|
||||
.ref_val => {
|
||||
const ref_val = val.cast(Payload.RefVal).?;
|
||||
const ref_val = val.castTag(.ref_val).?.data;
|
||||
try out_stream.writeAll("&const ");
|
||||
val = ref_val.val;
|
||||
val = ref_val;
|
||||
},
|
||||
.decl_ref => return out_stream.writeAll("(decl ref)"),
|
||||
.elem_ptr => {
|
||||
const elem_ptr = val.cast(Payload.ElemPtr).?;
|
||||
const elem_ptr = val.castTag(.elem_ptr).?.data;
|
||||
try out_stream.print("&[{}] ", .{elem_ptr.index});
|
||||
val = elem_ptr.array_ptr;
|
||||
},
|
||||
.empty_array => return out_stream.writeAll(".{}"),
|
||||
.enum_literal => return out_stream.print(".{z}", .{self.cast(Payload.Bytes).?.data}),
|
||||
.bytes => return out_stream.print("\"{Z}\"", .{self.cast(Payload.Bytes).?.data}),
|
||||
.enum_literal => return out_stream.print(".{z}", .{self.castTag(.enum_literal).?.data}),
|
||||
.bytes => return out_stream.print("\"{Z}\"", .{self.castTag(.bytes).?.data}),
|
||||
.repeated => {
|
||||
try out_stream.writeAll("(repeated) ");
|
||||
val = val.cast(Payload.Repeated).?.val;
|
||||
val = val.castTag(.repeated).?.data;
|
||||
},
|
||||
.float_16 => return out_stream.print("{}", .{val.cast(Payload.Float_16).?.val}),
|
||||
.float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}),
|
||||
.float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}),
|
||||
.float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
|
||||
.float_16 => return out_stream.print("{}", .{val.castTag(.float_16).?.data}),
|
||||
.float_32 => return out_stream.print("{}", .{val.castTag(.float_32).?.data}),
|
||||
.float_64 => return out_stream.print("{}", .{val.castTag(.float_64).?.data}),
|
||||
.float_128 => return out_stream.print("{}", .{val.castTag(.float_128).?.data}),
|
||||
.error_set => {
|
||||
const error_set = val.cast(Payload.ErrorSet).?;
|
||||
const error_set = val.castTag(.error_set).?.data;
|
||||
try out_stream.writeAll("error{");
|
||||
var it = error_set.fields.iterator();
|
||||
while (it.next()) |entry| {
|
||||
@ -372,21 +500,24 @@ pub const Value = extern union {
|
||||
}
|
||||
return out_stream.writeAll("}");
|
||||
},
|
||||
.@"error" => return out_stream.print("error.{}", .{val.cast(Payload.Error).?.name}),
|
||||
.@"error" => return out_stream.print("error.{}", .{val.castTag(.@"error").?.data.name}),
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts that the value is representable as an array of bytes.
|
||||
/// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
|
||||
pub fn toAllocatedBytes(self: Value, allocator: *Allocator) ![]u8 {
|
||||
if (self.cast(Payload.Bytes)) |bytes| {
|
||||
return std.mem.dupe(allocator, u8, bytes.data);
|
||||
if (self.castTag(.bytes)) |payload| {
|
||||
return std.mem.dupe(allocator, u8, payload.data);
|
||||
}
|
||||
if (self.cast(Payload.Repeated)) |repeated| {
|
||||
if (self.castTag(.enum_literal)) |payload| {
|
||||
return std.mem.dupe(allocator, u8, payload.data);
|
||||
}
|
||||
if (self.castTag(.repeated)) |payload| {
|
||||
@panic("TODO implement toAllocatedBytes for this Value tag");
|
||||
}
|
||||
if (self.cast(Payload.DeclRef)) |declref| {
|
||||
const val = try declref.decl.value();
|
||||
if (self.castTag(.decl_ref)) |payload| {
|
||||
const val = try payload.data.value();
|
||||
return val.toAllocatedBytes(allocator);
|
||||
}
|
||||
unreachable;
|
||||
@ -395,7 +526,7 @@ pub const Value = extern union {
|
||||
/// Asserts that the value is representable as a type.
|
||||
pub fn toType(self: Value, allocator: *Allocator) !Type {
|
||||
return switch (self.tag()) {
|
||||
.ty => self.cast(Payload.Ty).?.ty,
|
||||
.ty => self.castTag(.ty).?.data,
|
||||
.u8_type => Type.initTag(.u8),
|
||||
.i8_type => Type.initTag(.i8),
|
||||
.u16_type => Type.initTag(.u16),
|
||||
@ -439,7 +570,7 @@ pub const Value = extern union {
|
||||
.anyframe_type => Type.initTag(.@"anyframe"),
|
||||
|
||||
.int_type => {
|
||||
const payload = self.cast(Payload.IntType).?;
|
||||
const payload = self.castTag(.int_type).?.data;
|
||||
const new = try allocator.create(Type.Payload.Bits);
|
||||
new.* = .{
|
||||
.base = .{
|
||||
@ -450,7 +581,7 @@ pub const Value = extern union {
|
||||
return Type.initPayload(&new.base);
|
||||
},
|
||||
.error_set => {
|
||||
const payload = self.cast(Payload.ErrorSet).?;
|
||||
const payload = self.castTag(.error_set).?.data;
|
||||
return Type.Tag.error_set.create(allocator, payload.decl);
|
||||
},
|
||||
|
||||
@ -564,10 +695,10 @@ pub const Value = extern union {
|
||||
.bool_true,
|
||||
=> return BigIntMutable.init(&space.limbs, 1).toConst(),
|
||||
|
||||
.int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(),
|
||||
.int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(),
|
||||
.int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(),
|
||||
.int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt(),
|
||||
.int_u64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_u64).?.data).toConst(),
|
||||
.int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),
|
||||
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),
|
||||
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -649,10 +780,10 @@ pub const Value = extern union {
|
||||
.bool_true,
|
||||
=> return 1,
|
||||
|
||||
.int_u64 => return self.cast(Payload.Int_u64).?.int,
|
||||
.int_i64 => return @intCast(u64, self.cast(Payload.Int_i64).?.int),
|
||||
.int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable,
|
||||
.int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(u64) catch unreachable,
|
||||
.int_u64 => return self.castTag(.int_u64).?.data,
|
||||
.int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),
|
||||
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,
|
||||
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -734,10 +865,10 @@ pub const Value = extern union {
|
||||
.bool_true,
|
||||
=> return 1,
|
||||
|
||||
.int_u64 => return @intCast(i64, self.cast(Payload.Int_u64).?.int),
|
||||
.int_i64 => return self.cast(Payload.Int_i64).?.int,
|
||||
.int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(i64) catch unreachable,
|
||||
.int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(i64) catch unreachable,
|
||||
.int_u64 => return @intCast(i64, self.castTag(.int_u64).?.data),
|
||||
.int_i64 => return self.castTag(.int_i64).?.data,
|
||||
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
|
||||
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -753,14 +884,14 @@ pub const Value = extern union {
|
||||
pub fn toFloat(self: Value, comptime T: type) T {
|
||||
return switch (self.tag()) {
|
||||
.float_16 => @panic("TODO soft float"),
|
||||
.float_32 => @floatCast(T, self.cast(Payload.Float_32).?.val),
|
||||
.float_64 => @floatCast(T, self.cast(Payload.Float_64).?.val),
|
||||
.float_128 => @floatCast(T, self.cast(Payload.Float_128).?.val),
|
||||
.float_32 => @floatCast(T, self.castTag(.float_32).?.data),
|
||||
.float_64 => @floatCast(T, self.castTag(.float_64).?.data),
|
||||
.float_128 => @floatCast(T, self.castTag(.float_128).?.data),
|
||||
|
||||
.zero => 0,
|
||||
.one => 1,
|
||||
.int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int),
|
||||
.int_i64 => @intToFloat(T, self.cast(Payload.Int_i64).?.int),
|
||||
.int_u64 => @intToFloat(T, self.castTag(.int_u64).?.data),
|
||||
.int_i64 => @intToFloat(T, self.castTag(.int_i64).?.data),
|
||||
|
||||
.int_big_positive, .int_big_negative => @panic("big int to f128"),
|
||||
else => unreachable,
|
||||
@ -846,15 +977,15 @@ pub const Value = extern union {
|
||||
=> return 1,
|
||||
|
||||
.int_u64 => {
|
||||
const x = self.cast(Payload.Int_u64).?.int;
|
||||
const x = self.castTag(.int_u64).?.data;
|
||||
if (x == 0) return 0;
|
||||
return @intCast(usize, std.math.log2(x) + 1);
|
||||
},
|
||||
.int_i64 => {
|
||||
@panic("TODO implement i64 intBitCountTwosComp");
|
||||
},
|
||||
.int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().bitCountTwosComp(),
|
||||
.int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().bitCountTwosComp(),
|
||||
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
|
||||
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -943,7 +1074,7 @@ pub const Value = extern union {
|
||||
|
||||
.int_u64 => switch (ty.zigTypeTag()) {
|
||||
.Int => {
|
||||
const x = self.cast(Payload.Int_u64).?.int;
|
||||
const x = self.castTag(.int_u64).?.data;
|
||||
if (x == 0) return true;
|
||||
const info = ty.intInfo(target);
|
||||
const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
|
||||
@ -954,7 +1085,7 @@ pub const Value = extern union {
|
||||
},
|
||||
.int_i64 => switch (ty.zigTypeTag()) {
|
||||
.Int => {
|
||||
const x = self.cast(Payload.Int_i64).?.int;
|
||||
const x = self.castTag(.int_i64).?.data;
|
||||
if (x == 0) return true;
|
||||
const info = ty.intInfo(target);
|
||||
if (info.signedness == .unsigned and x < 0)
|
||||
@ -967,7 +1098,7 @@ pub const Value = extern union {
|
||||
.int_big_positive => switch (ty.zigTypeTag()) {
|
||||
.Int => {
|
||||
const info = ty.intInfo(target);
|
||||
return self.cast(Payload.IntBigPositive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
|
||||
return self.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
|
||||
},
|
||||
.ComptimeInt => return true,
|
||||
else => unreachable,
|
||||
@ -975,7 +1106,7 @@ pub const Value = extern union {
|
||||
.int_big_negative => switch (ty.zigTypeTag()) {
|
||||
.Int => {
|
||||
const info = ty.intInfo(target);
|
||||
return self.cast(Payload.IntBigNegative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
|
||||
return self.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
|
||||
},
|
||||
.ComptimeInt => return true,
|
||||
else => unreachable,
|
||||
@ -986,42 +1117,28 @@ pub const Value = extern union {
|
||||
/// Converts an integer or a float to a float.
|
||||
/// Returns `error.Overflow` if the value does not fit in the new type.
|
||||
pub fn floatCast(self: Value, allocator: *Allocator, ty: Type, target: Target) !Value {
|
||||
const dest_bit_count = switch (ty.tag()) {
|
||||
.comptime_float => 128,
|
||||
else => ty.floatBits(target),
|
||||
};
|
||||
switch (dest_bit_count) {
|
||||
16, 32, 64, 128 => {},
|
||||
else => std.debug.panic("TODO float cast bit count {}\n", .{dest_bit_count}),
|
||||
}
|
||||
if (ty.isInt()) {
|
||||
@panic("TODO int to float");
|
||||
}
|
||||
|
||||
switch (dest_bit_count) {
|
||||
16 => {
|
||||
@panic("TODO soft float");
|
||||
// var res_payload = Value.Payload.Float_16{.val = self.toFloat(f16)};
|
||||
// if (!self.eql(Value.initPayload(&res_payload.base)))
|
||||
// return error.Overflow;
|
||||
// return Value.initPayload(&res_payload.base).copy(allocator);
|
||||
switch (ty.tag()) {
|
||||
.f16 => {
|
||||
@panic("TODO add __trunctfhf2 to compiler-rt");
|
||||
//const res = try Value.Tag.float_16.create(allocator, self.toFloat(f16));
|
||||
//if (!self.eql(res))
|
||||
// return error.Overflow;
|
||||
//return res;
|
||||
},
|
||||
32 => {
|
||||
var res_payload = Value.Payload.Float_32{ .val = self.toFloat(f32) };
|
||||
if (!self.eql(Value.initPayload(&res_payload.base)))
|
||||
.f32 => {
|
||||
const res = try Value.Tag.float_32.create(allocator, self.toFloat(f32));
|
||||
if (!self.eql(res))
|
||||
return error.Overflow;
|
||||
return Value.initPayload(&res_payload.base).copy(allocator);
|
||||
return res;
|
||||
},
|
||||
64 => {
|
||||
var res_payload = Value.Payload.Float_64{ .val = self.toFloat(f64) };
|
||||
if (!self.eql(Value.initPayload(&res_payload.base)))
|
||||
.f64 => {
|
||||
const res = try Value.Tag.float_64.create(allocator, self.toFloat(f64));
|
||||
if (!self.eql(res))
|
||||
return error.Overflow;
|
||||
return Value.initPayload(&res_payload.base).copy(allocator);
|
||||
return res;
|
||||
},
|
||||
128 => {
|
||||
const float_payload = try allocator.create(Value.Payload.Float_128);
|
||||
float_payload.* = .{ .val = self.toFloat(f128) };
|
||||
return Value.initPayload(&float_payload.base);
|
||||
.f128, .comptime_float, .c_longdouble => {
|
||||
return Value.Tag.float_128.create(allocator, self.toFloat(f128));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -1102,10 +1219,10 @@ pub const Value = extern union {
|
||||
.one,
|
||||
=> false,
|
||||
|
||||
.float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0,
|
||||
.float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0,
|
||||
.float_64 => @rem(self.cast(Payload.Float_64).?.val, 1) != 0,
|
||||
// .float_128 => @rem(self.cast(Payload.Float_128).?.val, 1) != 0,
|
||||
.float_16 => @rem(self.castTag(.float_16).?.data, 1) != 0,
|
||||
.float_32 => @rem(self.castTag(.float_32).?.data, 1) != 0,
|
||||
.float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,
|
||||
// .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
|
||||
.float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
|
||||
};
|
||||
}
|
||||
@ -1182,15 +1299,15 @@ pub const Value = extern union {
|
||||
.bool_true,
|
||||
=> .gt,
|
||||
|
||||
.int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),
|
||||
.int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),
|
||||
.int_big_positive => lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0),
|
||||
.int_big_negative => lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0),
|
||||
.int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
|
||||
.int_i64 => std.math.order(lhs.castTag(.int_i64).?.data, 0),
|
||||
.int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0),
|
||||
.int_big_negative => lhs.castTag(.int_big_negative).?.asBigInt().orderAgainstScalar(0),
|
||||
|
||||
.float_16 => std.math.order(lhs.cast(Payload.Float_16).?.val, 0),
|
||||
.float_32 => std.math.order(lhs.cast(Payload.Float_32).?.val, 0),
|
||||
.float_64 => std.math.order(lhs.cast(Payload.Float_64).?.val, 0),
|
||||
.float_128 => std.math.order(lhs.cast(Payload.Float_128).?.val, 0),
|
||||
.float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0),
|
||||
.float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
|
||||
.float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
|
||||
.float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
|
||||
};
|
||||
}
|
||||
|
||||
@ -1208,10 +1325,10 @@ pub const Value = extern union {
|
||||
if (lhs_float and rhs_float) {
|
||||
if (lhs_tag == rhs_tag) {
|
||||
return switch (lhs.tag()) {
|
||||
.float_16 => return std.math.order(lhs.cast(Payload.Float_16).?.val, rhs.cast(Payload.Float_16).?.val),
|
||||
.float_32 => return std.math.order(lhs.cast(Payload.Float_32).?.val, rhs.cast(Payload.Float_32).?.val),
|
||||
.float_64 => return std.math.order(lhs.cast(Payload.Float_64).?.val, rhs.cast(Payload.Float_64).?.val),
|
||||
.float_128 => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val),
|
||||
.float_16 => return std.math.order(lhs.castTag(.float_16).?.data, rhs.castTag(.float_16).?.data),
|
||||
.float_32 => return std.math.order(lhs.castTag(.float_32).?.data, rhs.castTag(.float_32).?.data),
|
||||
.float_64 => return std.math.order(lhs.castTag(.float_64).?.data, rhs.castTag(.float_64).?.data),
|
||||
.float_128 => return std.math.order(lhs.castTag(.float_128).?.data, rhs.castTag(.float_128).?.data),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
@ -1244,8 +1361,8 @@ pub const Value = extern union {
|
||||
if (a.tag() == .void_value or a.tag() == .null_value) {
|
||||
return true;
|
||||
} else if (a.tag() == .enum_literal) {
|
||||
const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data;
|
||||
const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data;
|
||||
const a_name = a.castTag(.enum_literal).?.data;
|
||||
const b_name = b.castTag(.enum_literal).?.data;
|
||||
return std.mem.eql(u8, a_name, b_name);
|
||||
}
|
||||
}
|
||||
@ -1313,11 +1430,11 @@ pub const Value = extern union {
|
||||
},
|
||||
.error_set => {
|
||||
// Payload.decl should be same for all instances of the type.
|
||||
const payload = @fieldParentPtr(Payload.ErrorSet, "base", self.ptr_otherwise);
|
||||
const payload = self.castTag(.error_set).?.data;
|
||||
std.hash.autoHash(&hasher, payload.decl);
|
||||
},
|
||||
.int_type => {
|
||||
const payload = self.cast(Payload.IntType).?;
|
||||
const payload = self.castTag(.int_type).?.data;
|
||||
var int_payload = Type.Payload.Bits{
|
||||
.base = .{
|
||||
.tag = if (payload.signed) .int_signed else .int_unsigned,
|
||||
@ -1341,25 +1458,29 @@ pub const Value = extern union {
|
||||
.one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)),
|
||||
|
||||
.float_16, .float_32, .float_64, .float_128 => {},
|
||||
.enum_literal, .bytes => {
|
||||
const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise);
|
||||
.enum_literal => {
|
||||
const payload = self.castTag(.enum_literal).?;
|
||||
hasher.update(payload.data);
|
||||
},
|
||||
.bytes => {
|
||||
const payload = self.castTag(.bytes).?;
|
||||
hasher.update(payload.data);
|
||||
},
|
||||
.int_u64 => {
|
||||
const payload = @fieldParentPtr(Payload.Int_u64, "base", self.ptr_otherwise);
|
||||
std.hash.autoHash(&hasher, payload.int);
|
||||
const payload = self.castTag(.int_u64).?;
|
||||
std.hash.autoHash(&hasher, payload.data);
|
||||
},
|
||||
.int_i64 => {
|
||||
const payload = @fieldParentPtr(Payload.Int_i64, "base", self.ptr_otherwise);
|
||||
std.hash.autoHash(&hasher, payload.int);
|
||||
const payload = self.castTag(.int_i64).?;
|
||||
std.hash.autoHash(&hasher, payload.data);
|
||||
},
|
||||
.repeated => {
|
||||
const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
|
||||
std.hash.autoHash(&hasher, payload.val.hash());
|
||||
const payload = self.castTag(.repeated).?;
|
||||
std.hash.autoHash(&hasher, payload.data.hash());
|
||||
},
|
||||
.ref_val => {
|
||||
const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
|
||||
std.hash.autoHash(&hasher, payload.val.hash());
|
||||
const payload = self.castTag(.ref_val).?;
|
||||
std.hash.autoHash(&hasher, payload.data.hash());
|
||||
},
|
||||
.int_big_positive, .int_big_negative => {
|
||||
var space: BigIntSpace = undefined;
|
||||
@ -1379,28 +1500,28 @@ pub const Value = extern union {
|
||||
}
|
||||
},
|
||||
.elem_ptr => {
|
||||
const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
|
||||
const payload = self.castTag(.elem_ptr).?.data;
|
||||
std.hash.autoHash(&hasher, payload.array_ptr.hash());
|
||||
std.hash.autoHash(&hasher, payload.index);
|
||||
},
|
||||
.decl_ref => {
|
||||
const payload = @fieldParentPtr(Payload.DeclRef, "base", self.ptr_otherwise);
|
||||
std.hash.autoHash(&hasher, payload.decl);
|
||||
const decl = self.castTag(.decl_ref).?.data;
|
||||
std.hash.autoHash(&hasher, decl);
|
||||
},
|
||||
.function => {
|
||||
const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
|
||||
std.hash.autoHash(&hasher, payload.func);
|
||||
const func = self.castTag(.function).?.data;
|
||||
std.hash.autoHash(&hasher, func);
|
||||
},
|
||||
.extern_fn => {
|
||||
const payload = @fieldParentPtr(Payload.ExternFn, "base", self.ptr_otherwise);
|
||||
std.hash.autoHash(&hasher, payload.decl);
|
||||
const decl = self.castTag(.extern_fn).?.data;
|
||||
std.hash.autoHash(&hasher, decl);
|
||||
},
|
||||
.variable => {
|
||||
const payload = @fieldParentPtr(Payload.Variable, "base", self.ptr_otherwise);
|
||||
std.hash.autoHash(&hasher, payload.variable);
|
||||
const variable = self.castTag(.variable).?.data;
|
||||
std.hash.autoHash(&hasher, variable);
|
||||
},
|
||||
.@"error" => {
|
||||
const payload = @fieldParentPtr(Payload.Error, "base", self.ptr_otherwise);
|
||||
const payload = self.castTag(.@"error").?.data;
|
||||
hasher.update(payload.name);
|
||||
std.hash.autoHash(&hasher, payload.value);
|
||||
},
|
||||
@ -1483,10 +1604,10 @@ pub const Value = extern union {
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.ref_val => self.cast(Payload.RefVal).?.val,
|
||||
.decl_ref => self.cast(Payload.DeclRef).?.decl.value(),
|
||||
.ref_val => self.castTag(.ref_val).?.data,
|
||||
.decl_ref => self.castTag(.decl_ref).?.data.value(),
|
||||
.elem_ptr => {
|
||||
const elem_ptr = self.cast(Payload.ElemPtr).?;
|
||||
const elem_ptr = self.castTag(.elem_ptr).?.data;
|
||||
const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
|
||||
return array_val.elemValue(allocator, elem_ptr.index);
|
||||
},
|
||||
@ -1570,26 +1691,26 @@ pub const Value = extern union {
|
||||
|
||||
.empty_array => unreachable, // out of bounds array index
|
||||
|
||||
.bytes => {
|
||||
const int_payload = try allocator.create(Payload.Int_u64);
|
||||
int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] };
|
||||
return Value.initPayload(&int_payload.base);
|
||||
},
|
||||
.bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),
|
||||
|
||||
// No matter the index; all the elements are the same!
|
||||
.repeated => return self.cast(Payload.Repeated).?.val,
|
||||
.repeated => return self.castTag(.repeated).?.data,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a pointer to the element value at the index.
|
||||
pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {
|
||||
const payload = try allocator.create(Payload.ElemPtr);
|
||||
if (self.cast(Payload.ElemPtr)) |elem_ptr| {
|
||||
payload.* = .{ .array_ptr = elem_ptr.array_ptr, .index = elem_ptr.index + index };
|
||||
} else {
|
||||
payload.* = .{ .array_ptr = self, .index = index };
|
||||
if (self.castTag(.elem_ptr)) |elem_ptr| {
|
||||
return Tag.elem_ptr.create(allocator, .{
|
||||
.array_ptr = elem_ptr.data.array_ptr,
|
||||
.index = elem_ptr.data.index + index,
|
||||
});
|
||||
}
|
||||
return Value.initPayload(&payload.base);
|
||||
|
||||
return Tag.elem_ptr.create(allocator, .{
|
||||
.array_ptr = self,
|
||||
.index = index,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn isUndef(self: Value) bool {
|
||||
@ -1776,131 +1897,128 @@ pub const Value = extern union {
|
||||
pub const Payload = struct {
|
||||
tag: Tag,
|
||||
|
||||
pub const Int_u64 = struct {
|
||||
base: Payload = Payload{ .tag = .int_u64 },
|
||||
int: u64,
|
||||
pub const U64 = struct {
|
||||
base: Payload,
|
||||
data: u64,
|
||||
};
|
||||
|
||||
pub const Int_i64 = struct {
|
||||
base: Payload = Payload{ .tag = .int_i64 },
|
||||
int: i64,
|
||||
pub const I64 = struct {
|
||||
base: Payload,
|
||||
data: i64,
|
||||
};
|
||||
|
||||
pub const IntBigPositive = struct {
|
||||
base: Payload = Payload{ .tag = .int_big_positive },
|
||||
limbs: []const std.math.big.Limb,
|
||||
pub const BigInt = struct {
|
||||
base: Payload,
|
||||
data: []const std.math.big.Limb,
|
||||
|
||||
pub fn asBigInt(self: IntBigPositive) BigIntConst {
|
||||
return BigIntConst{ .limbs = self.limbs, .positive = true };
|
||||
}
|
||||
};
|
||||
|
||||
pub const IntBigNegative = struct {
|
||||
base: Payload = Payload{ .tag = .int_big_negative },
|
||||
limbs: []const std.math.big.Limb,
|
||||
|
||||
pub fn asBigInt(self: IntBigNegative) BigIntConst {
|
||||
return BigIntConst{ .limbs = self.limbs, .positive = false };
|
||||
pub fn asBigInt(self: BigInt) BigIntConst {
|
||||
const positive = switch (self.base.tag) {
|
||||
.int_big_positive => true,
|
||||
.int_big_negative => false,
|
||||
else => unreachable,
|
||||
};
|
||||
return BigIntConst{ .limbs = self.data, .positive = positive };
|
||||
}
|
||||
};
|
||||
|
||||
pub const Function = struct {
|
||||
base: Payload = Payload{ .tag = .function },
|
||||
func: *Module.Fn,
|
||||
base: Payload,
|
||||
data: *Module.Fn,
|
||||
};
|
||||
|
||||
pub const ExternFn = struct {
|
||||
base: Payload = Payload{ .tag = .extern_fn },
|
||||
decl: *Module.Decl,
|
||||
pub const Decl = struct {
|
||||
base: Payload,
|
||||
data: *Module.Decl,
|
||||
};
|
||||
|
||||
pub const Variable = struct {
|
||||
base: Payload = Payload{ .tag = .variable },
|
||||
variable: *Module.Var,
|
||||
base: Payload,
|
||||
data: *Module.Var,
|
||||
};
|
||||
|
||||
pub const ArraySentinel0_u8_Type = struct {
|
||||
base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },
|
||||
len: u64,
|
||||
};
|
||||
|
||||
/// Represents a pointer to another immutable value.
|
||||
pub const RefVal = struct {
|
||||
base: Payload = Payload{ .tag = .ref_val },
|
||||
val: Value,
|
||||
};
|
||||
|
||||
/// Represents a pointer to a decl, not the value of the decl.
|
||||
pub const DeclRef = struct {
|
||||
base: Payload = Payload{ .tag = .decl_ref },
|
||||
decl: *Module.Decl,
|
||||
pub const SubValue = struct {
|
||||
base: Payload,
|
||||
data: Value,
|
||||
};
|
||||
|
||||
pub const ElemPtr = struct {
|
||||
base: Payload = Payload{ .tag = .elem_ptr },
|
||||
array_ptr: Value,
|
||||
index: usize,
|
||||
pub const base_tag = Tag.elem_ptr;
|
||||
|
||||
base: Payload = Payload{ .tag = base_tag },
|
||||
data: struct {
|
||||
array_ptr: Value,
|
||||
index: usize,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Bytes = struct {
|
||||
base: Payload = Payload{ .tag = .bytes },
|
||||
base: Payload,
|
||||
data: []const u8,
|
||||
};
|
||||
|
||||
pub const Ty = struct {
|
||||
base: Payload = Payload{ .tag = .ty },
|
||||
ty: Type,
|
||||
base: Payload,
|
||||
data: Type,
|
||||
};
|
||||
|
||||
pub const IntType = struct {
|
||||
base: Payload = Payload{ .tag = .int_type },
|
||||
bits: u16,
|
||||
signed: bool,
|
||||
};
|
||||
pub const base_tag = Tag.int_type;
|
||||
|
||||
pub const Repeated = struct {
|
||||
base: Payload = Payload{ .tag = .ty },
|
||||
/// This value is repeated some number of times. The amount of times to repeat
|
||||
/// is stored externally.
|
||||
val: Value,
|
||||
base: Payload = Payload{ .tag = base_tag },
|
||||
data: struct {
|
||||
bits: u16,
|
||||
signed: bool,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Float_16 = struct {
|
||||
base: Payload = .{ .tag = .float_16 },
|
||||
val: f16,
|
||||
pub const base_tag = Tag.float_16;
|
||||
|
||||
base: Payload = .{ .tag = base_tag },
|
||||
data: f16,
|
||||
};
|
||||
|
||||
pub const Float_32 = struct {
|
||||
base: Payload = .{ .tag = .float_32 },
|
||||
val: f32,
|
||||
pub const base_tag = Tag.float_32;
|
||||
|
||||
base: Payload = .{ .tag = base_tag },
|
||||
data: f32,
|
||||
};
|
||||
|
||||
pub const Float_64 = struct {
|
||||
base: Payload = .{ .tag = .float_64 },
|
||||
val: f64,
|
||||
pub const base_tag = Tag.float_64;
|
||||
|
||||
base: Payload = .{ .tag = base_tag },
|
||||
data: f64,
|
||||
};
|
||||
|
||||
pub const Float_128 = struct {
|
||||
base: Payload = .{ .tag = .float_128 },
|
||||
val: f128,
|
||||
pub const base_tag = Tag.float_128;
|
||||
|
||||
base: Payload = .{ .tag = base_tag },
|
||||
data: f128,
|
||||
};
|
||||
|
||||
pub const ErrorSet = struct {
|
||||
base: Payload = .{ .tag = .error_set },
|
||||
pub const base_tag = Tag.error_set;
|
||||
|
||||
// TODO revisit this when we have the concept of the error tag type
|
||||
fields: std.StringHashMapUnmanaged(u16),
|
||||
decl: *Module.Decl,
|
||||
base: Payload = .{ .tag = base_tag },
|
||||
data: struct {
|
||||
// TODO revisit this when we have the concept of the error tag type
|
||||
fields: std.StringHashMapUnmanaged(u16),
|
||||
decl: *Module.Decl,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Error = struct {
|
||||
base: Payload = .{ .tag = .@"error" },
|
||||
|
||||
// TODO revisit this when we have the concept of the error tag type
|
||||
/// `name` is owned by `Module` and will be valid for the entire
|
||||
/// duration of the compilation.
|
||||
name: []const u8,
|
||||
value: u16,
|
||||
data: struct {
|
||||
// TODO revisit this when we have the concept of the error tag type
|
||||
/// `name` is owned by `Module` and will be valid for the entire
|
||||
/// duration of the compilation.
|
||||
name: []const u8,
|
||||
value: u16,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@ -1914,15 +2032,24 @@ pub const Value = extern union {
|
||||
|
||||
test "hash same value different representation" {
|
||||
const zero_1 = Value.initTag(.zero);
|
||||
var payload_1 = Value.Payload.Int_u64{ .int = 0 };
|
||||
var payload_1 = Value.Payload.U64{
|
||||
.base = .{ .tag = .int_u64 },
|
||||
.data = 0,
|
||||
};
|
||||
const zero_2 = Value.initPayload(&payload_1.base);
|
||||
std.testing.expectEqual(zero_1.hash(), zero_2.hash());
|
||||
|
||||
var payload_2 = Value.Payload.Int_i64{ .int = 0 };
|
||||
var payload_2 = Value.Payload.I64{
|
||||
.base = .{ .tag = .int_i64 },
|
||||
.data = 0,
|
||||
};
|
||||
const zero_3 = Value.initPayload(&payload_2.base);
|
||||
std.testing.expectEqual(zero_2.hash(), zero_3.hash());
|
||||
|
||||
var payload_3 = Value.Payload.IntBigNegative{ .limbs = &[_]std.math.big.Limb{0} };
|
||||
var payload_3 = Value.Payload.BigInt{
|
||||
.base = .{ .tag = .int_big_negative },
|
||||
.data = &[_]std.math.big.Limb{0},
|
||||
};
|
||||
const zero_4 = Value.initPayload(&payload_3.base);
|
||||
std.testing.expectEqual(zero_3.hash(), zero_4.hash());
|
||||
}
|
||||
|
||||
34
src/zir.zig
34
src/zir.zig
@ -1990,15 +1990,15 @@ const EmitZIR = struct {
|
||||
|
||||
fn resolveInst(self: *EmitZIR, new_body: ZirBody, inst: *ir.Inst) !*Inst {
|
||||
if (inst.cast(ir.Inst.Constant)) |const_inst| {
|
||||
const new_inst = if (const_inst.val.cast(Value.Payload.Function)) |func_pl| blk: {
|
||||
const owner_decl = func_pl.func.owner_decl;
|
||||
const new_inst = if (const_inst.val.castTag(.function)) |func_pl| blk: {
|
||||
const owner_decl = func_pl.data.owner_decl;
|
||||
break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
|
||||
} else if (const_inst.val.cast(Value.Payload.DeclRef)) |declref| blk: {
|
||||
const decl_ref = try self.emitDeclRef(inst.src, declref.decl);
|
||||
} else if (const_inst.val.castTag(.decl_ref)) |declref| blk: {
|
||||
const decl_ref = try self.emitDeclRef(inst.src, declref.data);
|
||||
try new_body.instructions.append(decl_ref);
|
||||
break :blk decl_ref;
|
||||
} else if (const_inst.val.cast(Value.Payload.Variable)) |var_pl| blk: {
|
||||
const owner_decl = var_pl.variable.owner_decl;
|
||||
} else if (const_inst.val.castTag(.variable)) |var_pl| blk: {
|
||||
const owner_decl = var_pl.data.owner_decl;
|
||||
break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
|
||||
} else blk: {
|
||||
break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;
|
||||
@ -2150,13 +2150,13 @@ const EmitZIR = struct {
|
||||
|
||||
fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Decl {
|
||||
const allocator = &self.arena.allocator;
|
||||
if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| {
|
||||
const decl = decl_ref.decl;
|
||||
if (typed_value.val.castTag(.decl_ref)) |decl_ref| {
|
||||
const decl = decl_ref.data;
|
||||
return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl));
|
||||
} else if (typed_value.val.cast(Value.Payload.Variable)) |variable| {
|
||||
} else if (typed_value.val.castTag(.variable)) |variable| {
|
||||
return self.emitTypedValue(src, .{
|
||||
.ty = typed_value.ty,
|
||||
.val = variable.variable.init,
|
||||
.val = variable.data.init,
|
||||
});
|
||||
}
|
||||
if (typed_value.val.isUndef()) {
|
||||
@ -2215,7 +2215,7 @@ const EmitZIR = struct {
|
||||
return self.emitType(src, ty);
|
||||
},
|
||||
.Fn => {
|
||||
const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
|
||||
const module_fn = typed_value.val.castTag(.function).?.data;
|
||||
return self.emitFn(module_fn, src, typed_value.ty);
|
||||
},
|
||||
.Array => {
|
||||
@ -2248,7 +2248,7 @@ const EmitZIR = struct {
|
||||
else
|
||||
return self.emitPrimitive(src, .@"false"),
|
||||
.EnumLiteral => {
|
||||
const enum_literal = @fieldParentPtr(Value.Payload.Bytes, "base", typed_value.val.ptr_otherwise);
|
||||
const enum_literal = typed_value.val.castTag(.enum_literal).?;
|
||||
const inst = try self.arena.allocator.create(Inst.Str);
|
||||
inst.* = .{
|
||||
.base = .{
|
||||
@ -2748,9 +2748,8 @@ const EmitZIR = struct {
|
||||
.signed => .@"true",
|
||||
.unsigned => .@"false",
|
||||
});
|
||||
const bits_payload = try self.arena.allocator.create(Value.Payload.Int_u64);
|
||||
bits_payload.* = .{ .int = info.bits };
|
||||
const bits = try self.emitComptimeIntVal(src, Value.initPayload(&bits_payload.base));
|
||||
const bits_val = try Value.Tag.int_u64.create(&self.arena.allocator, info.bits);
|
||||
const bits = try self.emitComptimeIntVal(src, bits_val);
|
||||
const inttype_inst = try self.arena.allocator.create(Inst.IntType);
|
||||
inttype_inst.* = .{
|
||||
.base = .{
|
||||
@ -2800,7 +2799,10 @@ const EmitZIR = struct {
|
||||
return self.emitUnnamedDecl(&inst.base);
|
||||
},
|
||||
.Array => {
|
||||
var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() };
|
||||
var len_pl = Value.Payload.U64{
|
||||
.base = .{ .tag = .int_u64 },
|
||||
.data = ty.arrayLen(),
|
||||
};
|
||||
const len = Value.initPayload(&len_pl.base);
|
||||
|
||||
const inst = if (ty.sentinel()) |sentinel| blk: {
|
||||
|
||||
@ -364,12 +364,9 @@ fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!
|
||||
const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One);
|
||||
|
||||
if (operand.value()) |val| {
|
||||
const ref_payload = try scope.arena().create(Value.Payload.RefVal);
|
||||
ref_payload.* = .{ .val = val };
|
||||
|
||||
return mod.constInst(scope, inst.base.src, .{
|
||||
.ty = ptr_type,
|
||||
.val = Value.initPayload(&ref_payload.base),
|
||||
.val = try Value.Tag.ref_val.create(scope.arena(), val),
|
||||
});
|
||||
}
|
||||
|
||||
@ -480,12 +477,9 @@ fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerErr
|
||||
errdefer new_decl_arena.deinit();
|
||||
const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes);
|
||||
|
||||
const bytes_payload = try scope.arena().create(Value.Payload.Bytes);
|
||||
bytes_payload.* = .{ .data = arena_bytes };
|
||||
|
||||
const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
|
||||
.ty = try Type.Tag.array_u8_sentinel_0.create(scope.arena(), arena_bytes.len),
|
||||
.val = Value.initPayload(&bytes_payload.base),
|
||||
.val = try Value.Tag.bytes.create(scope.arena(), arena_bytes),
|
||||
});
|
||||
return mod.analyzeDeclRef(scope, str_inst.base.src, new_decl);
|
||||
}
|
||||
@ -779,11 +773,9 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!
|
||||
.analysis = .{ .queued = fn_zir },
|
||||
.owner_decl = scope.decl().?,
|
||||
};
|
||||
const fn_payload = try scope.arena().create(Value.Payload.Function);
|
||||
fn_payload.* = .{ .func = new_func };
|
||||
return mod.constInst(scope, fn_inst.base.src, .{
|
||||
.ty = fn_type,
|
||||
.val = Value.initPayload(&fn_payload.base),
|
||||
.val = try Value.Tag.function.create(scope.arena(), new_func),
|
||||
});
|
||||
}
|
||||
|
||||
@ -838,14 +830,17 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In
|
||||
|
||||
const payload = try scope.arena().create(Value.Payload.ErrorSet);
|
||||
payload.* = .{
|
||||
.fields = .{},
|
||||
.decl = undefined, // populated below
|
||||
.base = .{ .tag = .error_set },
|
||||
.data = .{
|
||||
.fields = .{},
|
||||
.decl = undefined, // populated below
|
||||
},
|
||||
};
|
||||
try payload.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, inst.positionals.fields.len));
|
||||
try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, inst.positionals.fields.len));
|
||||
|
||||
for (inst.positionals.fields) |field_name| {
|
||||
const entry = try mod.getErrorValue(field_name);
|
||||
if (payload.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| {
|
||||
if (payload.data.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| {
|
||||
return mod.fail(scope, inst.base.src, "duplicate error: '{}'", .{field_name});
|
||||
}
|
||||
}
|
||||
@ -854,7 +849,7 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initPayload(&payload.base),
|
||||
});
|
||||
payload.decl = new_decl;
|
||||
payload.data.decl = new_decl;
|
||||
return mod.analyzeDeclRef(scope, inst.base.src, new_decl);
|
||||
}
|
||||
|
||||
@ -863,14 +858,10 @@ fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp)
|
||||
}
|
||||
|
||||
fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
|
||||
const payload = try scope.arena().create(Value.Payload.Bytes);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .enum_literal },
|
||||
.data = try scope.arena().dupe(u8, inst.positionals.name),
|
||||
};
|
||||
const duped_name = try scope.arena().dupe(u8, inst.positionals.name);
|
||||
return mod.constInst(scope, inst.base.src, .{
|
||||
.ty = Type.initTag(.enum_literal),
|
||||
.val = Value.initPayload(&payload.base),
|
||||
.val = try Value.Tag.enum_literal.create(scope.arena(), duped_name),
|
||||
});
|
||||
}
|
||||
|
||||
@ -989,15 +980,12 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
|
||||
switch (elem_ty.zigTypeTag()) {
|
||||
.Array => {
|
||||
if (mem.eql(u8, field_name, "len")) {
|
||||
const len_payload = try scope.arena().create(Value.Payload.Int_u64);
|
||||
len_payload.* = .{ .int = elem_ty.arrayLen() };
|
||||
|
||||
const ref_payload = try scope.arena().create(Value.Payload.RefVal);
|
||||
ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) };
|
||||
|
||||
return mod.constInst(scope, fieldptr.base.src, .{
|
||||
.ty = Type.initTag(.single_const_pointer_to_comptime_int),
|
||||
.val = Value.initPayload(&ref_payload.base),
|
||||
.val = try Value.Tag.ref_val.create(
|
||||
scope.arena(),
|
||||
try Value.Tag.int_u64.create(scope.arena(), elem_ty.arrayLen()),
|
||||
),
|
||||
});
|
||||
} else {
|
||||
return mod.fail(
|
||||
@ -1013,15 +1001,12 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
|
||||
switch (ptr_child.zigTypeTag()) {
|
||||
.Array => {
|
||||
if (mem.eql(u8, field_name, "len")) {
|
||||
const len_payload = try scope.arena().create(Value.Payload.Int_u64);
|
||||
len_payload.* = .{ .int = ptr_child.arrayLen() };
|
||||
|
||||
const ref_payload = try scope.arena().create(Value.Payload.RefVal);
|
||||
ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) };
|
||||
|
||||
return mod.constInst(scope, fieldptr.base.src, .{
|
||||
.ty = Type.initTag(.single_const_pointer_to_comptime_int),
|
||||
.val = Value.initPayload(&ref_payload.base),
|
||||
.val = try Value.Tag.ref_val.create(
|
||||
scope.arena(),
|
||||
try Value.Tag.int_u64.create(scope.arena(), ptr_child.arrayLen()),
|
||||
),
|
||||
});
|
||||
} else {
|
||||
return mod.fail(
|
||||
@ -1043,21 +1028,12 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
|
||||
switch (child_type.zigTypeTag()) {
|
||||
.ErrorSet => {
|
||||
// TODO resolve inferred error sets
|
||||
const entry = if (val.cast(Value.Payload.ErrorSet)) |payload|
|
||||
(payload.fields.getEntry(field_name) orelse
|
||||
const entry = if (val.castTag(.error_set)) |payload|
|
||||
(payload.data.fields.getEntry(field_name) orelse
|
||||
return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).*
|
||||
else
|
||||
try mod.getErrorValue(field_name);
|
||||
|
||||
const error_payload = try scope.arena().create(Value.Payload.Error);
|
||||
error_payload.* = .{
|
||||
.name = entry.key,
|
||||
.value = entry.value,
|
||||
};
|
||||
|
||||
const ref_payload = try scope.arena().create(Value.Payload.RefVal);
|
||||
ref_payload.* = .{ .val = Value.initPayload(&error_payload.base) };
|
||||
|
||||
const result_type = if (child_type.tag() == .anyerror)
|
||||
try Type.Tag.error_set_single.create(scope.arena(), entry.key)
|
||||
else
|
||||
@ -1065,7 +1041,13 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
|
||||
|
||||
return mod.constInst(scope, fieldptr.base.src, .{
|
||||
.ty = try mod.simplePtrType(scope, fieldptr.base.src, result_type, false, .One),
|
||||
.val = Value.initPayload(&ref_payload.base),
|
||||
.val = try Value.Tag.ref_val.create(
|
||||
scope.arena(),
|
||||
try Value.Tag.@"error".create(scope.arena(), .{
|
||||
.name = entry.key,
|
||||
.value = entry.value,
|
||||
}),
|
||||
),
|
||||
});
|
||||
},
|
||||
.Struct => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user