Commit d44c9bdbd9
src-self-hosted/ir/text.zig
@@ -32,6 +32,8 @@ pub const Inst = struct {
fntype,
intcast,
bitcast,
+ elemptr,
+ add,
};
pub fn TagToType(tag: Tag) type {
@@ -50,6 +52,8 @@ pub const Inst = struct {
.fntype => FnType,
.intcast => IntCast,
.bitcast => BitCast,
+ .elemptr => ElemPtr,
+ .add => Add,
};
}
@@ -157,6 +161,11 @@ pub const Inst = struct {
},
kw_args: struct {},
+ const Point = struct {
+ x: i32,
+ y: i32,
+ };
+
pub const Body = struct {
instructions: []*Inst,
};
@@ -271,6 +280,28 @@ pub const Inst = struct {
},
kw_args: struct {},
};
+
+ pub const ElemPtr = struct {
+ pub const base_tag = Tag.elemptr;
+ base: Inst,
+
+ positionals: struct {
+ array_ptr: *Inst,
+ index: *Inst,
+ },
+ kw_args: struct {},
+ };
+
+ pub const Add = struct {
+ pub const base_tag = Tag.add;
+ base: Inst,
+
+ positionals: struct {
+ lhs: *Inst,
+ rhs: *Inst,
+ },
+ kw_args: struct {},
+ };
};
pub const ErrorMsg = struct {
@@ -345,6 +376,8 @@ pub const Module = struct {
.fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),
.intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),
.bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, decl, inst_table),
+ .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, decl, inst_table),
+ .add => return self.writeInstToStreamGeneric(stream, .add, decl, inst_table),
}
}
src-self-hosted/ir.zig
@@ -421,6 +421,8 @@ const Analyze = struct {
.fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),
.intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?),
.bitcast => return self.analyzeInstBitCast(func, old_inst.cast(text.Inst.BitCast).?),
+ .elemptr => return self.analyzeInstElemPtr(func, old_inst.cast(text.Inst.ElemPtr).?),
+ .add => return self.analyzeInstAdd(func, old_inst.cast(text.Inst.Add).?),
}
}
@@ -569,6 +571,67 @@ const Analyze = struct {
return self.bitcast(func, dest_type, operand);
}
+ fn analyzeInstElemPtr(self: *Analyze, func: ?*Fn, inst: *text.Inst.ElemPtr) InnerError!*Inst {
+ const array_ptr = try self.resolveInst(func, inst.positionals.array_ptr);
+ const uncasted_index = try self.resolveInst(func, inst.positionals.index);
+ const elem_index = try self.coerce(func, Type.initTag(.usize), uncasted_index);
+
+ if (array_ptr.ty.isSinglePointer() and array_ptr.ty.elemType().zigTypeTag() == .Array) {
+ if (array_ptr.value()) |array_ptr_val| {
+ if (elem_index.value()) |index_val| {
+ // Both array pointer and index are compile-time known.
+ const index_u64 = index_val.toUnsignedInt();
+ // @intCast here because it would have been impossible to construct a value that
+ // required a larger index.
+ const elem_val = try array_ptr_val.elemValueAt(&self.arena.allocator, @intCast(usize, index_u64));
+
+ const ref_payload = try self.arena.allocator.create(Value.Payload.RefVal);
+ ref_payload.* = .{ .val = elem_val };
+
+ const type_payload = try self.arena.allocator.create(Type.Payload.SingleConstPointer);
+ type_payload.* = .{ .pointee_type = array_ptr.ty.elemType().elemType() };
+
+ return self.constInst(inst.base.src, .{
+ .ty = Type.initPayload(&type_payload.base),
+ .val = Value.initPayload(&ref_payload.base),
+ });
+ }
+ }
+ }
+
+ return self.fail(inst.base.src, "TODO implement more analyze elemptr", .{});
+ }
+
+ fn analyzeInstAdd(self: *Analyze, func: ?*Fn, inst: *text.Inst.Add) InnerError!*Inst {
+ const lhs = try self.resolveInst(func, inst.positionals.lhs);
+ const rhs = try self.resolveInst(func, inst.positionals.rhs);
+
+ if (lhs.ty.zigTypeTag() == .Int and rhs.ty.zigTypeTag() == .Int) {
+ if (lhs.value()) |lhs_val| {
+ if (rhs.value()) |rhs_val| {
+ const lhs_bigint = try lhs_val.toBigInt(&self.arena.allocator);
+ const rhs_bigint = try rhs_val.toBigInt(&self.arena.allocator);
+ var result_bigint = try BigInt.init(&self.arena.allocator);
+ try BigInt.add(&result_bigint, lhs_bigint, rhs_bigint);
+
+ if (!lhs.ty.eql(rhs.ty)) {
+ return self.fail(inst.base.src, "TODO implement peer type resolution", .{});
+ }
+
+ const val_payload = try self.arena.allocator.create(Value.Payload.IntBig);
+ val_payload.* = .{ .big_int = result_bigint };
+
+ return self.constInst(inst.base.src, .{
+ .ty = lhs.ty,
+ .val = Value.initPayload(&val_payload.base),
+ });
+ }
+ }
+ }
+
+ return self.fail(inst.base.src, "TODO implement more analyze add", .{});
+ }
+
fn analyzeInstDeref(self: *Analyze, func: ?*Fn, deref: *text.Inst.Deref) InnerError!*Inst {
const ptr = try self.resolveInst(func, deref.positionals.ptr);
const elem_ty = switch (ptr.ty.zigTypeTag()) {
@@ -654,7 +717,22 @@ const Analyze = struct {
return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
}
- return self.fail(inst.src, "TODO implement type coercion", .{});
+ // integer widening
+ if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
+ const src_info = inst.ty.intInfo(self.target);
+ const dst_info = dest_type.intInfo(self.target);
+ if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) {
+ if (inst.value()) |val| {
+ return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
+ } else {
+ return self.fail(inst.src, "TODO implement runtime integer widening", .{});
+ }
+ } else {
+ return self.fail(inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });
+ }
+ }
+
+ return self.fail(inst.src, "TODO implement type coercion from {} to {}", .{ inst.ty, dest_type });
}
fn bitcast(self: *Analyze, func: ?*Fn, dest_type: Type, inst: *Inst) !*Inst {
src-self-hosted/value.zig
@@ -441,6 +441,61 @@ pub const Value = extern union {
}
}
+ /// Asserts the value is a single-item pointer to an array, or an array,
+ /// or an unknown-length pointer, and returns the element value at the index.
+ pub fn elemValueAt(self: Value, allocator: *Allocator, index: usize) Allocator.Error!Value {
+ switch (self.tag()) {
+ .ty,
+ .u8_type,
+ .i8_type,
+ .isize_type,
+ .usize_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,
+ .fn_naked_noreturn_no_args_type,
+ .single_const_pointer_to_comptime_int_type,
+ .const_slice_u8_type,
+ .zero,
+ .void_value,
+ .noreturn_value,
+ .bool_true,
+ .bool_false,
+ .function,
+ .int_u64,
+ .int_i64,
+ .int_big,
+ => unreachable,
+
+ .ref => @panic("TODO figure out how MemoryCell works"),
+ .ref_val => @panic("TODO figure out how MemoryCell works"),
+
+ .bytes => {
+ const int_payload = try allocator.create(Value.Payload.Int_u64);
+ int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] };
+ return Value.initPayload(&int_payload.base);
+ },
+ }
+ }
+
/// This type is not copyable since it may contain pointers to its inner data.
pub const Payload = struct {
tag: Tag,