authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-26 01:20:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-26 01:20:58-04:00
logd44c9bdbd9c6add603997a834506ddd165a70cd4
tree181f146aa0bf546db5f3cd27260a72dfbf513e9c
parent6481b02fdce735614e87c0b48ec169a2f3496610

ir: elemptr and add instructions


3 files changed, 167 insertions(+), 1 deletions(-)

src-self-hosted/ir.zig+79-1
...@@ -421,6 +421,8 @@ const Analyze = struct {...@@ -421,6 +421,8 @@ const Analyze = struct {
421 .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),421 .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),
422 .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?),422 .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?),
423 .bitcast => return self.analyzeInstBitCast(func, old_inst.cast(text.Inst.BitCast).?),423 .bitcast => return self.analyzeInstBitCast(func, old_inst.cast(text.Inst.BitCast).?),
424 .elemptr => return self.analyzeInstElemPtr(func, old_inst.cast(text.Inst.ElemPtr).?),
425 .add => return self.analyzeInstAdd(func, old_inst.cast(text.Inst.Add).?),
424 }426 }
425 }427 }
426428
...@@ -569,6 +571,67 @@ const Analyze = struct {...@@ -569,6 +571,67 @@ const Analyze = struct {
569 return self.bitcast(func, dest_type, operand);571 return self.bitcast(func, dest_type, operand);
570 }572 }
571573
574 fn analyzeInstElemPtr(self: *Analyze, func: ?*Fn, inst: *text.Inst.ElemPtr) InnerError!*Inst {
575 const array_ptr = try self.resolveInst(func, inst.positionals.array_ptr);
576 const uncasted_index = try self.resolveInst(func, inst.positionals.index);
577 const elem_index = try self.coerce(func, Type.initTag(.usize), uncasted_index);
578
579 if (array_ptr.ty.isSinglePointer() and array_ptr.ty.elemType().zigTypeTag() == .Array) {
580 if (array_ptr.value()) |array_ptr_val| {
581 if (elem_index.value()) |index_val| {
582 // Both array pointer and index are compile-time known.
583 const index_u64 = index_val.toUnsignedInt();
584 // @intCast here because it would have been impossible to construct a value that
585 // required a larger index.
586 const elem_val = try array_ptr_val.elemValueAt(&self.arena.allocator, @intCast(usize, index_u64));
587
588 const ref_payload = try self.arena.allocator.create(Value.Payload.RefVal);
589 ref_payload.* = .{ .val = elem_val };
590
591 const type_payload = try self.arena.allocator.create(Type.Payload.SingleConstPointer);
592 type_payload.* = .{ .pointee_type = array_ptr.ty.elemType().elemType() };
593
594 return self.constInst(inst.base.src, .{
595 .ty = Type.initPayload(&type_payload.base),
596 .val = Value.initPayload(&ref_payload.base),
597 });
598 }
599 }
600 }
601
602 return self.fail(inst.base.src, "TODO implement more analyze elemptr", .{});
603 }
604
605 fn analyzeInstAdd(self: *Analyze, func: ?*Fn, inst: *text.Inst.Add) InnerError!*Inst {
606 const lhs = try self.resolveInst(func, inst.positionals.lhs);
607 const rhs = try self.resolveInst(func, inst.positionals.rhs);
608
609 if (lhs.ty.zigTypeTag() == .Int and rhs.ty.zigTypeTag() == .Int) {
610 if (lhs.value()) |lhs_val| {
611 if (rhs.value()) |rhs_val| {
612 const lhs_bigint = try lhs_val.toBigInt(&self.arena.allocator);
613 const rhs_bigint = try rhs_val.toBigInt(&self.arena.allocator);
614 var result_bigint = try BigInt.init(&self.arena.allocator);
615 try BigInt.add(&result_bigint, lhs_bigint, rhs_bigint);
616
617 if (!lhs.ty.eql(rhs.ty)) {
618 return self.fail(inst.base.src, "TODO implement peer type resolution", .{});
619 }
620
621 const val_payload = try self.arena.allocator.create(Value.Payload.IntBig);
622 val_payload.* = .{ .big_int = result_bigint };
623
624 return self.constInst(inst.base.src, .{
625 .ty = lhs.ty,
626 .val = Value.initPayload(&val_payload.base),
627 });
628 }
629 }
630 }
631
632 return self.fail(inst.base.src, "TODO implement more analyze add", .{});
633 }
634
572 fn analyzeInstDeref(self: *Analyze, func: ?*Fn, deref: *text.Inst.Deref) InnerError!*Inst {635 fn analyzeInstDeref(self: *Analyze, func: ?*Fn, deref: *text.Inst.Deref) InnerError!*Inst {
573 const ptr = try self.resolveInst(func, deref.positionals.ptr);636 const ptr = try self.resolveInst(func, deref.positionals.ptr);
574 const elem_ty = switch (ptr.ty.zigTypeTag()) {637 const elem_ty = switch (ptr.ty.zigTypeTag()) {
...@@ -654,7 +717,22 @@ const Analyze = struct {...@@ -654,7 +717,22 @@ const Analyze = struct {
654 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });717 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
655 }718 }
656719
657 return self.fail(inst.src, "TODO implement type coercion", .{});720 // integer widening
721 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
722 const src_info = inst.ty.intInfo(self.target);
723 const dst_info = dest_type.intInfo(self.target);
724 if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) {
725 if (inst.value()) |val| {
726 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
727 } else {
728 return self.fail(inst.src, "TODO implement runtime integer widening", .{});
729 }
730 } else {
731 return self.fail(inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });
732 }
733 }
734
735 return self.fail(inst.src, "TODO implement type coercion from {} to {}", .{ inst.ty, dest_type });
658 }736 }
659737
660 fn bitcast(self: *Analyze, func: ?*Fn, dest_type: Type, inst: *Inst) !*Inst {738 fn bitcast(self: *Analyze, func: ?*Fn, dest_type: Type, inst: *Inst) !*Inst {
src-self-hosted/ir/text.zig+33
...@@ -32,6 +32,8 @@ pub const Inst = struct {...@@ -32,6 +32,8 @@ pub const Inst = struct {
32 fntype,32 fntype,
33 intcast,33 intcast,
34 bitcast,34 bitcast,
35 elemptr,
36 add,
35 };37 };
3638
37 pub fn TagToType(tag: Tag) type {39 pub fn TagToType(tag: Tag) type {
...@@ -50,6 +52,8 @@ pub const Inst = struct {...@@ -50,6 +52,8 @@ pub const Inst = struct {
50 .fntype => FnType,52 .fntype => FnType,
51 .intcast => IntCast,53 .intcast => IntCast,
52 .bitcast => BitCast,54 .bitcast => BitCast,
55 .elemptr => ElemPtr,
56 .add => Add,
53 };57 };
54 }58 }
5559
...@@ -157,6 +161,11 @@ pub const Inst = struct {...@@ -157,6 +161,11 @@ pub const Inst = struct {
157 },161 },
158 kw_args: struct {},162 kw_args: struct {},
159163
164 const Point = struct {
165 x: i32,
166 y: i32,
167 };
168
160 pub const Body = struct {169 pub const Body = struct {
161 instructions: []*Inst,170 instructions: []*Inst,
162 };171 };
...@@ -271,6 +280,28 @@ pub const Inst = struct {...@@ -271,6 +280,28 @@ pub const Inst = struct {
271 },280 },
272 kw_args: struct {},281 kw_args: struct {},
273 };282 };
283
284 pub const ElemPtr = struct {
285 pub const base_tag = Tag.elemptr;
286 base: Inst,
287
288 positionals: struct {
289 array_ptr: *Inst,
290 index: *Inst,
291 },
292 kw_args: struct {},
293 };
294
295 pub const Add = struct {
296 pub const base_tag = Tag.add;
297 base: Inst,
298
299 positionals: struct {
300 lhs: *Inst,
301 rhs: *Inst,
302 },
303 kw_args: struct {},
304 };
274};305};
275306
276pub const ErrorMsg = struct {307pub const ErrorMsg = struct {
...@@ -345,6 +376,8 @@ pub const Module = struct {...@@ -345,6 +376,8 @@ pub const Module = struct {
345 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),376 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),
346 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),377 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),
347 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, decl, inst_table),378 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, decl, inst_table),
379 .elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, decl, inst_table),
380 .add => return self.writeInstToStreamGeneric(stream, .add, decl, inst_table),
348 }381 }
349 }382 }
350383
src-self-hosted/value.zig+55
...@@ -441,6 +441,61 @@ pub const Value = extern union {...@@ -441,6 +441,61 @@ pub const Value = extern union {
441 }441 }
442 }442 }
443443
444 /// Asserts the value is a single-item pointer to an array, or an array,
445 /// or an unknown-length pointer, and returns the element value at the index.
446 pub fn elemValueAt(self: Value, allocator: *Allocator, index: usize) Allocator.Error!Value {
447 switch (self.tag()) {
448 .ty,
449 .u8_type,
450 .i8_type,
451 .isize_type,
452 .usize_type,
453 .c_short_type,
454 .c_ushort_type,
455 .c_int_type,
456 .c_uint_type,
457 .c_long_type,
458 .c_ulong_type,
459 .c_longlong_type,
460 .c_ulonglong_type,
461 .c_longdouble_type,
462 .f16_type,
463 .f32_type,
464 .f64_type,
465 .f128_type,
466 .c_void_type,
467 .bool_type,
468 .void_type,
469 .type_type,
470 .anyerror_type,
471 .comptime_int_type,
472 .comptime_float_type,
473 .noreturn_type,
474 .fn_naked_noreturn_no_args_type,
475 .single_const_pointer_to_comptime_int_type,
476 .const_slice_u8_type,
477 .zero,
478 .void_value,
479 .noreturn_value,
480 .bool_true,
481 .bool_false,
482 .function,
483 .int_u64,
484 .int_i64,
485 .int_big,
486 => unreachable,
487
488 .ref => @panic("TODO figure out how MemoryCell works"),
489 .ref_val => @panic("TODO figure out how MemoryCell works"),
490
491 .bytes => {
492 const int_payload = try allocator.create(Value.Payload.Int_u64);
493 int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] };
494 return Value.initPayload(&int_payload.base);
495 },
496 }
497 }
498
444 /// This type is not copyable since it may contain pointers to its inner data.499 /// This type is not copyable since it may contain pointers to its inner data.
445 pub const Payload = struct {500 pub const Payload = struct {
446 tag: Tag,501 tag: Tag,