authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-25 16:04:30-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-25 16:23:55-04:00
logd29c674d0dfab215e230a3d31eddf7ca164491a0
tree08e4aecccfafaf4c3e11d86df58a164a09d3e24a
parent1e080e505617b8a7961971630c059592f7366223

x86_64: implement teb inline assembly for windows


1 files changed, 92 insertions(+), 48 deletions(-)

src/arch/x86_64/CodeGen.zig+92-48
...@@ -6265,13 +6265,23 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -6265,13 +6265,23 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
6265 const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);6265 const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
6266 extra_i += inputs.len;6266 extra_i += inputs.len;
62676267
6268 const dead = !is_volatile and self.liveness.isUnused(inst);6268 var result: MCValue = .none;
6269 const result: MCValue = if (dead) .dead else result: {6269 if (!is_volatile and self.liveness.isUnused(inst)) result = .dead else {
6270 var args = std.StringArrayHashMap(MCValue).init(self.gpa);
6271 try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len);
6272 defer {
6273 for (args.values()) |arg| switch (arg) {
6274 .register => |reg| self.register_manager.unlockReg(.{ .register = reg }),
6275 else => {},
6276 };
6277 args.deinit();
6278 }
6279
6270 if (outputs.len > 1) {6280 if (outputs.len > 1) {
6271 return self.fail("TODO implement codegen for asm with more than 1 output", .{});6281 return self.fail("TODO implement codegen for asm with more than 1 output", .{});
6272 }6282 }
62736283
6274 const output_constraint: ?[]const u8 = for (outputs) |output| {6284 for (outputs) |output| {
6275 if (output != .none) {6285 if (output != .none) {
6276 return self.fail("TODO implement codegen for non-expr asm", .{});6286 return self.fail("TODO implement codegen for non-expr asm", .{});
6277 }6287 }
...@@ -6282,8 +6292,21 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -6282,8 +6292,21 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
6282 // for the string, we still use the next u32 for the null terminator.6292 // for the string, we still use the next u32 for the null terminator.
6283 extra_i += (constraint.len + name.len + (2 + 3)) / 4;6293 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
62846294
6285 break constraint;6295 const mcv: MCValue = if (mem.eql(u8, constraint, "=r"))
6286 } else null;6296 .{ .register = self.register_manager.tryAllocReg(inst, gp) orelse
6297 return self.fail("ran out of registers lowering inline asm", .{}) }
6298 else if (mem.startsWith(u8, constraint, "={") and mem.endsWith(u8, constraint, "}"))
6299 .{ .register = parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse
6300 return self.fail("unrecognized register constraint: '{s}'", .{constraint}) }
6301 else
6302 return self.fail("unrecognized constraint: '{s}'", .{constraint});
6303 args.putAssumeCapacity(name, mcv);
6304 switch (mcv) {
6305 .register => |reg| _ = self.register_manager.lockRegAssumeUnused(reg),
6306 else => {},
6307 }
6308 if (output == .none) result = mcv;
6309 }
62876310
6288 for (inputs) |input| {6311 for (inputs) |input| {
6289 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);6312 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
...@@ -6317,52 +6340,73 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -6317,52 +6340,73 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
6317 }6340 }
6318 }6341 }
63196342
6320 const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];6343 const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
63216344 var line_it = mem.tokenize(u8, asm_source, "\n\r");
6322 {6345 while (line_it.next()) |line| {
6323 var iter = std.mem.tokenize(u8, asm_source, "\n\r");6346 var mnem_it = mem.tokenize(u8, line, " \t");
6324 while (iter.next()) |ins| {6347 const mnem = mnem_it.next() orelse continue;
6325 if (mem.eql(u8, ins, "syscall")) {6348 if (mem.startsWith(u8, mnem, "#")) continue;
6326 try self.asmOpOnly(.syscall);6349 var arg_it = mem.tokenize(u8, mnem_it.rest(), ", ");
6327 } else if (mem.indexOf(u8, ins, "push")) |_| {6350 if (std.ascii.eqlIgnoreCase(mnem, "syscall")) {
6328 const arg = ins[4..];6351 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6329 if (mem.indexOf(u8, arg, "$")) |l| {6352 return self.fail("Too many operands: '{s}'", .{line});
6330 const n = std.fmt.parseInt(u8, ins[4 + l + 1 ..], 10) catch {6353 try self.asmOpOnly(.syscall);
6331 return self.fail("TODO implement more inline asm int parsing", .{});6354 } else if (std.ascii.eqlIgnoreCase(mnem, "push")) {
6332 };6355 const src = arg_it.next() orelse
6333 try self.asmImmediate(.push, Immediate.u(n));6356 return self.fail("Not enough operands: '{s}'", .{line});
6334 } else if (mem.indexOf(u8, arg, "%%")) |l| {6357 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6335 const reg_name = ins[4 + l + 2 ..];6358 return self.fail("Too many operands: '{s}'", .{line});
6336 const reg = parseRegName(reg_name) orelse6359 if (mem.startsWith(u8, src, "$")) {
6337 return self.fail("unrecognized register: '{s}'", .{reg_name});6360 const imm = std.fmt.parseInt(u32, src["$".len..], 0) catch
6338 try self.asmRegister(.push, reg);6361 return self.fail("Invalid immediate: '{s}'", .{src});
6339 } else return self.fail("TODO more push operands", .{});6362 try self.asmImmediate(.push, Immediate.u(imm));
6340 } else if (mem.indexOf(u8, ins, "pop")) |_| {6363 } else if (mem.startsWith(u8, src, "%%")) {
6341 const arg = ins[3..];6364 const reg = parseRegName(src["%%".len..]) orelse
6342 if (mem.indexOf(u8, arg, "%%")) |l| {6365 return self.fail("Invalid register: '{s}'", .{src});
6343 const reg_name = ins[3 + l + 2 ..];6366 try self.asmRegister(.push, reg);
6344 const reg = parseRegName(reg_name) orelse6367 } else return self.fail("Unsupported operand: '{s}'", .{src});
6345 return self.fail("unrecognized register: '{s}'", .{reg_name});6368 } else if (std.ascii.eqlIgnoreCase(mnem, "pop")) {
6346 try self.asmRegister(.pop, reg);6369 const dst = arg_it.next() orelse
6347 } else return self.fail("TODO more pop operands", .{});6370 return self.fail("Not enough operands: '{s}'", .{line});
6348 } else {6371 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6349 return self.fail("TODO implement support for more x86 assembly instructions", .{});6372 return self.fail("Too many operands: '{s}'", .{line});
6373 if (mem.startsWith(u8, dst, "%%")) {
6374 const reg = parseRegName(dst["%%".len..]) orelse
6375 return self.fail("Invalid register: '{s}'", .{dst});
6376 try self.asmRegister(.pop, reg);
6377 } else return self.fail("Unsupported operand: '{s}'", .{dst});
6378 } else if (std.ascii.eqlIgnoreCase(mnem, "movq")) {
6379 const src = arg_it.next() orelse
6380 return self.fail("Not enough operands: '{s}'", .{line});
6381 const dst = arg_it.next() orelse
6382 return self.fail("Not enough operands: '{s}'", .{line});
6383 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6384 return self.fail("Too many operands: '{s}'", .{line});
6385 if (mem.startsWith(u8, src, "%%")) {
6386 const colon = mem.indexOfScalarPos(u8, src, "%%".len + 2, ':');
6387 const src_reg = parseRegName(src["%%".len .. colon orelse src.len]) orelse
6388 return self.fail("Invalid register: '{s}'", .{src});
6389 if (colon) |colon_pos| {
6390 const src_disp = std.fmt.parseInt(i32, src[colon_pos + 1 ..], 0) catch
6391 return self.fail("Invalid immediate: '{s}'", .{src});
6392 if (mem.startsWith(u8, dst, "%[") and mem.endsWith(u8, dst, "]")) {
6393 switch (args.get(dst["%[".len .. dst.len - "]".len]) orelse
6394 return self.fail("no matching constraint for: '{s}'", .{dst})) {
6395 .register => |dst_reg| try self.asmRegisterMemory(
6396 .mov,
6397 dst_reg,
6398 Memory.sib(.qword, .{ .base = src_reg, .disp = src_disp }),
6399 ),
6400 else => return self.fail("Invalid constraint: '{s}'", .{dst}),
6401 }
6402 } else return self.fail("Unsupported operand: '{s}'", .{dst});
6403 } else return self.fail("Unsupported operand: '{s}'", .{src});
6350 }6404 }
6405 } else {
6406 return self.fail("Unsupported instruction: '{s}'", .{mnem});
6351 }6407 }
6352 }6408 }
63536409 }
6354 if (output_constraint) |output| {
6355 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
6356 return self.fail("unrecognized asm output constraint: '{s}'", .{output});
6357 }
6358 const reg_name = output[2 .. output.len - 1];
6359 const reg = parseRegName(reg_name) orelse
6360 return self.fail("unrecognized register: '{s}'", .{reg_name});
6361 break :result .{ .register = reg };
6362 } else {
6363 break :result .none;
6364 }
6365 };
63666410
6367 simple: {6411 simple: {
6368 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);6412 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);