From d44c9bdbd9c6add603997a834506ddd165a70cd4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 26 Apr 2020 01:20:58 -0400 Subject: [PATCH] ir: elemptr and add instructions --- src-self-hosted/ir.zig | 80 ++++++++++++++++++++++++++++++++++++- src-self-hosted/ir/text.zig | 33 +++++++++++++++ src-self-hosted/value.zig | 55 +++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 1 deletion(-) diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 9a609b63ae..310591e629 100644 --- a/src-self-hosted/ir.zig +++ b/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 { diff --git a/src-self-hosted/ir/text.zig b/src-self-hosted/ir/text.zig index 94b1de03de..6e9d4ae121 100644 --- a/src-self-hosted/ir/text.zig +++ b/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), } } diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index aaa6f0867a..2adbb7807e 100644 --- a/src-self-hosted/value.zig +++ b/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,