authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 22:19:32-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 22:19:32-04:00
log2e6ccec1007199d651bf89216c4af53f80c5c15a
tree6ed2d2f29ef26b07f974c944b3b0665b20368d60
parent8d3e4147d591342d6ec4ce54c5e14da98c1a692a

ir: analyze asm instruction


3 files changed, 61 insertions(+), 8 deletions(-)

src-self-hosted/ir.zig+57-6
......@@ -49,6 +49,12 @@ pub const Inst = struct {
4949 };
5050 }
5151
52 pub const Unreach = struct {
53 pub const base_tag = Tag.unreach;
54 base: Inst,
55 args: void,
56 };
57
5258 pub const Constant = struct {
5359 pub const base_tag = Tag.constant;
5460 base: Inst,
......@@ -63,7 +69,7 @@ pub const Inst = struct {
6369 args: struct {
6470 asm_source: []const u8,
6571 is_volatile: bool,
66 output: []const u8,
72 output: ?[]const u8,
6773 inputs: []const []const u8,
6874 clobbers: []const []const u8,
6975 args: []const *Inst,
......@@ -260,6 +266,7 @@ const Analyze = struct {
260266 });
261267 }
262268
269 /// TODO should not need the cast on the last parameter at the callsites
263270 fn addNewInstArgs(
264271 self: *Analyze,
265272 func: *Fn,
......@@ -318,11 +325,18 @@ const Analyze = struct {
318325
319326 fn constType(self: *Analyze, src: usize, ty: Type) !*Inst {
320327 return self.constInst(src, .{
321 .ty = Type.initTag(.@"type"),
328 .ty = Type.initTag(.type),
322329 .val = try ty.toValue(&self.arena.allocator),
323330 });
324331 }
325332
333 fn constVoid(self: *Analyze, src: usize) !*Inst {
334 return self.constInst(src, .{
335 .ty = Type.initTag(.void),
336 .val = Value.initTag(.void_value),
337 });
338 }
339
326340 fn constIntUnsigned(self: *Analyze, src: usize, ty: Type, int: u64) !*Inst {
327341 const int_payload = try self.arena.allocator.create(Value.Payload.Int_u64);
328342 int_payload.* = .{ .int = int };
......@@ -385,10 +399,13 @@ const Analyze = struct {
385399 .fieldptr => return self.analyzeInstFieldPtr(func, old_inst.cast(text.Inst.FieldPtr).?),
386400 .deref => return self.analyzeInstDeref(func, old_inst.cast(text.Inst.Deref).?),
387401 .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?),
388 .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
389 .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
402 .@"asm" => return self.analyzeInstAsm(func, old_inst.cast(text.Inst.Asm).?),
403 .@"unreachable" => return self.analyzeInstUnreachable(func, old_inst.cast(text.Inst.Unreachable).?),
390404 .@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?),
391 .@"export" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
405 .@"export" => {
406 try self.analyzeExport(func, old_inst.cast(text.Inst.Export).?);
407 return self.constVoid(old_inst.src);
408 },
392409 .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?),
393410 .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),
394411 .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?),
......@@ -466,7 +483,6 @@ const Analyze = struct {
466483 // TODO handle known-pointer-address
467484 const f = try self.requireFunctionBody(func, ptrtoint.base.src);
468485 const ty = Type.initTag(.usize);
469 // TODO should not need the cast on the last parameter
470486 return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr });
471487 }
472488
......@@ -551,6 +567,41 @@ const Analyze = struct {
551567 return self.fail(deref.base.src, "TODO implement runtime deref", .{});
552568 }
553569
570 fn analyzeInstAsm(self: *Analyze, func: ?*Fn, assembly: *text.Inst.Asm) InnerError!*Inst {
571 const return_type = try self.resolveType(func, assembly.positionals.return_type);
572 const asm_source = try self.resolveConstString(func, assembly.positionals.asm_source);
573 const output = if (assembly.kw_args.output) |o| try self.resolveConstString(func, o) else null;
574
575 const inputs = try self.arena.allocator.alloc([]const u8, assembly.kw_args.inputs.len);
576 const clobbers = try self.arena.allocator.alloc([]const u8, assembly.kw_args.clobbers.len);
577 const args = try self.arena.allocator.alloc(*Inst, assembly.kw_args.args.len);
578
579 for (inputs) |*elem, i| {
580 elem.* = try self.resolveConstString(func, assembly.kw_args.inputs[i]);
581 }
582 for (clobbers) |*elem, i| {
583 elem.* = try self.resolveConstString(func, assembly.kw_args.clobbers[i]);
584 }
585 for (args) |*elem, i| {
586 elem.* = try self.resolveInst(func, assembly.kw_args.args[i]);
587 }
588
589 const f = try self.requireFunctionBody(func, assembly.base.src);
590 return self.addNewInstArgs(f, assembly.base.src, return_type, Inst.Assembly, Inst.Args(Inst.Assembly){
591 .asm_source = asm_source,
592 .is_volatile = assembly.kw_args.@"volatile",
593 .output = output,
594 .inputs = inputs,
595 .clobbers = clobbers,
596 .args = args,
597 });
598 }
599
600 fn analyzeInstUnreachable(self: *Analyze, func: ?*Fn, unreach: *text.Inst.Unreachable) InnerError!*Inst {
601 const f = try self.requireFunctionBody(func, unreach.base.src);
602 return self.addNewInstArgs(f, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {});
603 }
604
554605 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
555606 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
556607 if (in_memory_result == .ok) {
src-self-hosted/ir/text.zig+2-2
......@@ -39,7 +39,7 @@ pub const Inst = struct {
3939 .fieldptr => FieldPtr,
4040 .deref => Deref,
4141 .as => As,
42 .@"asm" => Assembly,
42 .@"asm" => Asm,
4343 .@"unreachable" => Unreachable,
4444 .@"fn" => Fn,
4545 .@"export" => Export,
......@@ -118,7 +118,7 @@ pub const Inst = struct {
118118 kw_args: struct {},
119119 };
120120
121 pub const Assembly = struct {
121 pub const Asm = struct {
122122 pub const base_tag = Tag.@"asm";
123123 base: Inst,
124124
src-self-hosted/value.zig+2
......@@ -255,6 +255,7 @@ pub const Value = extern union {
255255 .int_u64 => switch (ty.zigTypeTag()) {
256256 .Int => {
257257 const x = self.cast(Payload.Int_u64).?.int;
258 if (x == 0) return true;
258259 const info = ty.intInfo(target);
259260 const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signed);
260261 return info.bits >= needed_bits;
......@@ -265,6 +266,7 @@ pub const Value = extern union {
265266 .int_i64 => switch (ty.zigTypeTag()) {
266267 .Int => {
267268 const x = self.cast(Payload.Int_i64).?.int;
269 if (x == 0) return true;
268270 const info = ty.intInfo(target);
269271 if (!info.signed and x < 0)
270272 return false;