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 {...@@ -49,6 +49,12 @@ pub const Inst = struct {
49 };49 };
50 }50 }
5151
52 pub const Unreach = struct {
53 pub const base_tag = Tag.unreach;
54 base: Inst,
55 args: void,
56 };
57
52 pub const Constant = struct {58 pub const Constant = struct {
53 pub const base_tag = Tag.constant;59 pub const base_tag = Tag.constant;
54 base: Inst,60 base: Inst,
...@@ -63,7 +69,7 @@ pub const Inst = struct {...@@ -63,7 +69,7 @@ pub const Inst = struct {
63 args: struct {69 args: struct {
64 asm_source: []const u8,70 asm_source: []const u8,
65 is_volatile: bool,71 is_volatile: bool,
66 output: []const u8,72 output: ?[]const u8,
67 inputs: []const []const u8,73 inputs: []const []const u8,
68 clobbers: []const []const u8,74 clobbers: []const []const u8,
69 args: []const *Inst,75 args: []const *Inst,
...@@ -260,6 +266,7 @@ const Analyze = struct {...@@ -260,6 +266,7 @@ const Analyze = struct {
260 });266 });
261 }267 }
262268
269 /// TODO should not need the cast on the last parameter at the callsites
263 fn addNewInstArgs(270 fn addNewInstArgs(
264 self: *Analyze,271 self: *Analyze,
265 func: *Fn,272 func: *Fn,
...@@ -318,11 +325,18 @@ const Analyze = struct {...@@ -318,11 +325,18 @@ const Analyze = struct {
318325
319 fn constType(self: *Analyze, src: usize, ty: Type) !*Inst {326 fn constType(self: *Analyze, src: usize, ty: Type) !*Inst {
320 return self.constInst(src, .{327 return self.constInst(src, .{
321 .ty = Type.initTag(.@"type"),328 .ty = Type.initTag(.type),
322 .val = try ty.toValue(&self.arena.allocator),329 .val = try ty.toValue(&self.arena.allocator),
323 });330 });
324 }331 }
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
326 fn constIntUnsigned(self: *Analyze, src: usize, ty: Type, int: u64) !*Inst {340 fn constIntUnsigned(self: *Analyze, src: usize, ty: Type, int: u64) !*Inst {
327 const int_payload = try self.arena.allocator.create(Value.Payload.Int_u64);341 const int_payload = try self.arena.allocator.create(Value.Payload.Int_u64);
328 int_payload.* = .{ .int = int };342 int_payload.* = .{ .int = int };
...@@ -385,10 +399,13 @@ const Analyze = struct {...@@ -385,10 +399,13 @@ const Analyze = struct {
385 .fieldptr => return self.analyzeInstFieldPtr(func, old_inst.cast(text.Inst.FieldPtr).?),399 .fieldptr => return self.analyzeInstFieldPtr(func, old_inst.cast(text.Inst.FieldPtr).?),
386 .deref => return self.analyzeInstDeref(func, old_inst.cast(text.Inst.Deref).?),400 .deref => return self.analyzeInstDeref(func, old_inst.cast(text.Inst.Deref).?),
387 .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?),401 .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)}),402 .@"asm" => return self.analyzeInstAsm(func, old_inst.cast(text.Inst.Asm).?),
389 .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),403 .@"unreachable" => return self.analyzeInstUnreachable(func, old_inst.cast(text.Inst.Unreachable).?),
390 .@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?),404 .@"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 },
392 .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?),409 .primitive => return self.analyzeInstPrimitive(func, old_inst.cast(text.Inst.Primitive).?),
393 .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),410 .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),
394 .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?),411 .intcast => return self.analyzeInstIntCast(func, old_inst.cast(text.Inst.IntCast).?),
...@@ -466,7 +483,6 @@ const Analyze = struct {...@@ -466,7 +483,6 @@ const Analyze = struct {
466 // TODO handle known-pointer-address483 // TODO handle known-pointer-address
467 const f = try self.requireFunctionBody(func, ptrtoint.base.src);484 const f = try self.requireFunctionBody(func, ptrtoint.base.src);
468 const ty = Type.initTag(.usize);485 const ty = Type.initTag(.usize);
469 // TODO should not need the cast on the last parameter
470 return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr });486 return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr });
471 }487 }
472488
...@@ -551,6 +567,41 @@ const Analyze = struct {...@@ -551,6 +567,41 @@ const Analyze = struct {
551 return self.fail(deref.base.src, "TODO implement runtime deref", .{});567 return self.fail(deref.base.src, "TODO implement runtime deref", .{});
552 }568 }
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
554 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {605 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
555 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);606 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
556 if (in_memory_result == .ok) {607 if (in_memory_result == .ok) {
src-self-hosted/ir/text.zig+2-2
...@@ -39,7 +39,7 @@ pub const Inst = struct {...@@ -39,7 +39,7 @@ pub const Inst = struct {
39 .fieldptr => FieldPtr,39 .fieldptr => FieldPtr,
40 .deref => Deref,40 .deref => Deref,
41 .as => As,41 .as => As,
42 .@"asm" => Assembly,42 .@"asm" => Asm,
43 .@"unreachable" => Unreachable,43 .@"unreachable" => Unreachable,
44 .@"fn" => Fn,44 .@"fn" => Fn,
45 .@"export" => Export,45 .@"export" => Export,
...@@ -118,7 +118,7 @@ pub const Inst = struct {...@@ -118,7 +118,7 @@ pub const Inst = struct {
118 kw_args: struct {},118 kw_args: struct {},
119 };119 };
120120
121 pub const Assembly = struct {121 pub const Asm = struct {
122 pub const base_tag = Tag.@"asm";122 pub const base_tag = Tag.@"asm";
123 base: Inst,123 base: Inst,
124124
src-self-hosted/value.zig+2
...@@ -255,6 +255,7 @@ pub const Value = extern union {...@@ -255,6 +255,7 @@ pub const Value = extern union {
255 .int_u64 => switch (ty.zigTypeTag()) {255 .int_u64 => switch (ty.zigTypeTag()) {
256 .Int => {256 .Int => {
257 const x = self.cast(Payload.Int_u64).?.int;257 const x = self.cast(Payload.Int_u64).?.int;
258 if (x == 0) return true;
258 const info = ty.intInfo(target);259 const info = ty.intInfo(target);
259 const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signed);260 const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signed);
260 return info.bits >= needed_bits;261 return info.bits >= needed_bits;
...@@ -265,6 +266,7 @@ pub const Value = extern union {...@@ -265,6 +266,7 @@ pub const Value = extern union {
265 .int_i64 => switch (ty.zigTypeTag()) {266 .int_i64 => switch (ty.zigTypeTag()) {
266 .Int => {267 .Int => {
267 const x = self.cast(Payload.Int_i64).?.int;268 const x = self.cast(Payload.Int_i64).?.int;
269 if (x == 0) return true;
268 const info = ty.intInfo(target);270 const info = ty.intInfo(target);
269 if (!info.signed and x < 0)271 if (!info.signed and x < 0)
270 return false;272 return false;