authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-23 20:23:16-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-23 20:23:16-04:00
log757d13d7843879de618247733f22f4fc515cc467
treefd901a6065b3dc6d23e261e63e9567fccf52ec77
parent0ac502f37257c607fc835840d02f0401c5e59442

codegen supports embedded-in-code constants

also coerce no longer requires a bitcast

3 files changed, 90 insertions(+), 11 deletions(-)

src-self-hosted/codegen.zig+28-1
...@@ -81,6 +81,7 @@ const Function = struct {...@@ -81,6 +81,7 @@ const Function = struct {
81 .constant => unreachable, // excluded from function bodies81 .constant => unreachable, // excluded from function bodies
82 .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?),82 .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?),
83 .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),83 .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),
84 .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
84 }85 }
85 }86 }
8687
...@@ -282,7 +283,26 @@ const Function = struct {...@@ -282,7 +283,26 @@ const Function = struct {
282 .rsi => switch (mcv) {283 .rsi => switch (mcv) {
283 .none, .unreach => unreachable,284 .none, .unreach => unreachable,
284 .immediate => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = immediate", .{}),285 .immediate => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = immediate", .{}),
285 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = embedded_in_code", .{}),286 .embedded_in_code => |code_offset| {
287 // Examples:
288 // lea rsi, [rip + 0x01020304]
289 // lea rsi, [rip - 7]
290 // f: 48 8d 35 04 03 02 01 lea rsi,[rip+0x1020304] # 102031a <_start+0x102031a>
291 // 16: 48 8d 35 f9 ff ff ff lea rsi,[rip+0xfffffffffffffff9] # 16 <_start+0x16>
292 //
293 // We need the offset from RIP in a signed i32 twos complement.
294 // The instruction is 7 bytes long and RIP points to the next instruction.
295 try self.code.resize(self.code.items.len + 7);
296 const rip = self.code.items.len;
297 const big_offset = @intCast(i64, code_offset) - @intCast(i64, rip);
298 const offset = @intCast(i32, big_offset);
299 self.code.items[self.code.items.len - 7] = 0x48;
300 self.code.items[self.code.items.len - 6] = 0x8d;
301 self.code.items[self.code.items.len - 5] = 0x35;
302 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
303 mem.writeIntLittle(i32, imm_ptr, offset);
304 return;
305 },
286 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = register", .{}),306 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = register", .{}),
287 },307 },
288 .rdx => switch (mcv) {308 .rdx => switch (mcv) {
...@@ -302,6 +322,11 @@ const Function = struct {...@@ -302,6 +322,11 @@ const Function = struct {
302 return self.resolveInst(inst.args.ptr);322 return self.resolveInst(inst.args.ptr);
303 }323 }
304324
325 fn genBitCast(self: *Function, inst: *ir.Inst.BitCast) !MCValue {
326 const operand = try self.resolveInst(inst.args.operand);
327 return operand;
328 }
329
305 fn resolveInst(self: *Function, inst: *ir.Inst) !MCValue {330 fn resolveInst(self: *Function, inst: *ir.Inst) !MCValue {
306 if (self.inst_table.getValue(inst)) |mcv| {331 if (self.inst_table.getValue(inst)) |mcv| {
307 return mcv;332 return mcv;
...@@ -344,6 +369,8 @@ const Function = struct {...@@ -344,6 +369,8 @@ const Function = struct {
344 }369 }
345 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };370 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
346 },371 },
372 .ComptimeInt => unreachable, // semantic analysis prevents this
373 .ComptimeFloat => unreachable, // semantic analysis prevents this
347 else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),374 else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),
348 }375 }
349 }376 }
src-self-hosted/ir.zig+35-10
...@@ -24,6 +24,7 @@ pub const Inst = struct {...@@ -24,6 +24,7 @@ pub const Inst = struct {
24 constant,24 constant,
25 assembly,25 assembly,
26 ptrtoint,26 ptrtoint,
27 bitcast,
27 };28 };
2829
29 pub fn cast(base: *Inst, comptime T: type) ?*T {30 pub fn cast(base: *Inst, comptime T: type) ?*T {
...@@ -45,6 +46,7 @@ pub const Inst = struct {...@@ -45,6 +46,7 @@ pub const Inst = struct {
4546
46 .assembly,47 .assembly,
47 .ptrtoint,48 .ptrtoint,
49 .bitcast,
48 => null,50 => null,
49 };51 };
50 }52 }
...@@ -84,6 +86,15 @@ pub const Inst = struct {...@@ -84,6 +86,15 @@ pub const Inst = struct {
84 ptr: *Inst,86 ptr: *Inst,
85 },87 },
86 };88 };
89
90 pub const BitCast = struct {
91 pub const base_tag = Tag.bitcast;
92
93 base: Inst,
94 args: struct {
95 operand: *Inst,
96 },
97 };
87};98};
8899
89pub const TypedValue = struct {100pub const TypedValue = struct {
...@@ -234,7 +245,7 @@ const Analyze = struct {...@@ -234,7 +245,7 @@ const Analyze = struct {
234 fn resolveConstString(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) ![]u8 {245 fn resolveConstString(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) ![]u8 {
235 const new_inst = try self.resolveInst(func, old_inst);246 const new_inst = try self.resolveInst(func, old_inst);
236 const wanted_type = Type.initTag(.const_slice_u8);247 const wanted_type = Type.initTag(.const_slice_u8);
237 const coerced_inst = try self.coerce(wanted_type, new_inst);248 const coerced_inst = try self.coerce(func, wanted_type, new_inst);
238 const val = try self.resolveConstValue(coerced_inst);249 const val = try self.resolveConstValue(coerced_inst);
239 return val.toAllocatedBytes(&self.arena.allocator);250 return val.toAllocatedBytes(&self.arena.allocator);
240 }251 }
...@@ -242,7 +253,7 @@ const Analyze = struct {...@@ -242,7 +253,7 @@ const Analyze = struct {
242 fn resolveType(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) !Type {253 fn resolveType(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) !Type {
243 const new_inst = try self.resolveInst(func, old_inst);254 const new_inst = try self.resolveInst(func, old_inst);
244 const wanted_type = Type.initTag(.@"type");255 const wanted_type = Type.initTag(.@"type");
245 const coerced_inst = try self.coerce(wanted_type, new_inst);256 const coerced_inst = try self.coerce(func, wanted_type, new_inst);
246 const val = try self.resolveConstValue(coerced_inst);257 const val = try self.resolveConstValue(coerced_inst);
247 return val.toType();258 return val.toType();
248 }259 }
...@@ -409,6 +420,7 @@ const Analyze = struct {...@@ -409,6 +420,7 @@ const Analyze = struct {
409 .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?),420 .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?),
410 .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),421 .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),
411 .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).?),
412 }424 }
413 }425 }
414426
...@@ -472,7 +484,7 @@ const Analyze = struct {...@@ -472,7 +484,7 @@ const Analyze = struct {
472 fn analyzeInstAs(self: *Analyze, func: ?*Fn, as: *text.Inst.As) InnerError!*Inst {484 fn analyzeInstAs(self: *Analyze, func: ?*Fn, as: *text.Inst.As) InnerError!*Inst {
473 const dest_type = try self.resolveType(func, as.positionals.dest_type);485 const dest_type = try self.resolveType(func, as.positionals.dest_type);
474 const new_inst = try self.resolveInst(func, as.positionals.value);486 const new_inst = try self.resolveInst(func, as.positionals.value);
475 return self.coerce(dest_type, new_inst);487 return self.coerce(func, dest_type, new_inst);
476 }488 }
477489
478 fn analyzeInstPtrToInt(self: *Analyze, func: ?*Fn, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst {490 fn analyzeInstPtrToInt(self: *Analyze, func: ?*Fn, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst {
...@@ -545,12 +557,18 @@ const Analyze = struct {...@@ -545,12 +557,18 @@ const Analyze = struct {
545 }557 }
546558
547 if (dest_is_comptime_int or new_inst.value() != null) {559 if (dest_is_comptime_int or new_inst.value() != null) {
548 return self.coerce(dest_type, new_inst);560 return self.coerce(func, dest_type, new_inst);
549 }561 }
550562
551 return self.fail(intcast.base.src, "TODO implement analyze widen or shorten int", .{});563 return self.fail(intcast.base.src, "TODO implement analyze widen or shorten int", .{});
552 }564 }
553565
566 fn analyzeInstBitCast(self: *Analyze, func: ?*Fn, inst: *text.Inst.BitCast) InnerError!*Inst {
567 const dest_type = try self.resolveType(func, inst.positionals.dest_type);
568 const operand = try self.resolveInst(func, inst.positionals.operand);
569 return self.bitcast(func, dest_type, operand);
570 }
571
554 fn analyzeInstDeref(self: *Analyze, func: ?*Fn, deref: *text.Inst.Deref) InnerError!*Inst {572 fn analyzeInstDeref(self: *Analyze, func: ?*Fn, deref: *text.Inst.Deref) InnerError!*Inst {
555 const ptr = try self.resolveInst(func, deref.positionals.ptr);573 const ptr = try self.resolveInst(func, deref.positionals.ptr);
556 const elem_ty = switch (ptr.ty.zigTypeTag()) {574 const elem_ty = switch (ptr.ty.zigTypeTag()) {
...@@ -583,7 +601,8 @@ const Analyze = struct {...@@ -583,7 +601,8 @@ const Analyze = struct {
583 elem.* = try self.resolveConstString(func, assembly.kw_args.clobbers[i]);601 elem.* = try self.resolveConstString(func, assembly.kw_args.clobbers[i]);
584 }602 }
585 for (args) |*elem, i| {603 for (args) |*elem, i| {
586 elem.* = try self.resolveInst(func, assembly.kw_args.args[i]);604 const arg = try self.resolveInst(func, assembly.kw_args.args[i]);
605 elem.* = try self.coerce(func, Type.initTag(.usize), arg);
587 }606 }
588607
589 const f = try self.requireFunctionBody(func, assembly.base.src);608 const f = try self.requireFunctionBody(func, assembly.base.src);
...@@ -602,10 +621,14 @@ const Analyze = struct {...@@ -602,10 +621,14 @@ const Analyze = struct {
602 return self.addNewInstArgs(f, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {});621 return self.addNewInstArgs(f, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {});
603 }622 }
604623
605 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {624 fn coerce(self: *Analyze, func: ?*Fn, dest_type: Type, inst: *Inst) !*Inst {
625 // If the types are the same, we can return the operand.
626 if (dest_type.eql(inst.ty))
627 return inst;
628
606 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);629 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
607 if (in_memory_result == .ok) {630 if (in_memory_result == .ok) {
608 return self.bitcast(dest_type, inst);631 return self.bitcast(func, dest_type, inst);
609 }632 }
610633
611 // *[N]T to []T634 // *[N]T to []T
...@@ -634,12 +657,14 @@ const Analyze = struct {...@@ -634,12 +657,14 @@ const Analyze = struct {
634 return self.fail(inst.src, "TODO implement type coercion", .{});657 return self.fail(inst.src, "TODO implement type coercion", .{});
635 }658 }
636659
637 fn bitcast(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {660 fn bitcast(self: *Analyze, func: ?*Fn, dest_type: Type, inst: *Inst) !*Inst {
638 if (inst.value()) |val| {661 if (inst.value()) |val| {
639 // Keep the comptime Value representation; take the new type.662 // Keep the comptime Value representation; take the new type.
640 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });663 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
641 }664 }
642 return self.fail(inst.src, "TODO implement runtime bitcast", .{});665 // TODO validate the type size and other compile errors
666 const f = try self.requireFunctionBody(func, inst.src);
667 return self.addNewInstArgs(f, inst.src, dest_type, Inst.BitCast, Inst.Args(Inst.BitCast){ .operand = inst });
643 }668 }
644669
645 fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {670 fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
...@@ -713,7 +738,7 @@ pub fn main() anyerror!void {...@@ -713,7 +738,7 @@ pub fn main() anyerror!void {
713 std.process.exit(1);738 std.process.exit(1);
714 }739 }
715740
716 const output_zir = false;741 const output_zir = true;
717 if (output_zir) {742 if (output_zir) {
718 var new_zir_module = try text.emit_zir(allocator, analyzed_module);743 var new_zir_module = try text.emit_zir(allocator, analyzed_module);
719 defer new_zir_module.deinit(allocator);744 defer new_zir_module.deinit(allocator);
src-self-hosted/ir/text.zig+27
...@@ -31,6 +31,7 @@ pub const Inst = struct {...@@ -31,6 +31,7 @@ pub const Inst = struct {
31 primitive,31 primitive,
32 fntype,32 fntype,
33 intcast,33 intcast,
34 bitcast,
34 };35 };
3536
36 pub fn TagToType(tag: Tag) type {37 pub fn TagToType(tag: Tag) type {
...@@ -48,6 +49,7 @@ pub const Inst = struct {...@@ -48,6 +49,7 @@ pub const Inst = struct {
48 .primitive => Primitive,49 .primitive => Primitive,
49 .fntype => FnType,50 .fntype => FnType,
50 .intcast => IntCast,51 .intcast => IntCast,
52 .bitcast => BitCast,
51 };53 };
52 }54 }
5355
...@@ -258,6 +260,17 @@ pub const Inst = struct {...@@ -258,6 +260,17 @@ pub const Inst = struct {
258 },260 },
259 kw_args: struct {},261 kw_args: struct {},
260 };262 };
263
264 pub const BitCast = struct {
265 pub const base_tag = Tag.bitcast;
266 base: Inst,
267
268 positionals: struct {
269 dest_type: *Inst,
270 operand: *Inst,
271 },
272 kw_args: struct {},
273 };
261};274};
262275
263pub const ErrorMsg = struct {276pub const ErrorMsg = struct {
...@@ -331,6 +344,7 @@ pub const Module = struct {...@@ -331,6 +344,7 @@ pub const Module = struct {
331 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table),344 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table),
332 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),345 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),
333 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),346 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),
347 .bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, decl, inst_table),
334 }348 }
335 }349 }
336350
...@@ -957,6 +971,19 @@ const EmitZIR = struct {...@@ -957,6 +971,19 @@ const EmitZIR = struct {
957 };971 };
958 break :blk &new_inst.base;972 break :blk &new_inst.base;
959 },973 },
974 .bitcast => blk: {
975 const old_inst = inst.cast(ir.Inst.BitCast).?;
976 const new_inst = try self.arena.allocator.create(Inst.BitCast);
977 new_inst.* = .{
978 .base = .{ .src = inst.src, .tag = Inst.BitCast.base_tag },
979 .positionals = .{
980 .dest_type = try self.emitType(inst.src, inst.ty),
981 .operand = try self.resolveInst(&inst_table, old_inst.args.operand),
982 },
983 .kw_args = .{},
984 };
985 break :blk &new_inst.base;
986 },
960 };987 };
961 try instructions.append(new_inst);988 try instructions.append(new_inst);
962 try inst_table.putNoClobber(inst, new_inst);989 try inst_table.putNoClobber(inst, new_inst);