| ... | @@ -78,7 +78,7 @@ pub fn generateSymbol( | ... | @@ -78,7 +78,7 @@ pub fn generateSymbol( |
| 78 | //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line), | 78 | //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line), |
| 79 | //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line), | 79 | //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line), |
| 80 | //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line), | 80 | //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line), |
| 81 | //.riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line), | 81 | .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line), |
| 82 | //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line), | 82 | //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line), |
| 83 | //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line), | 83 | //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line), |
| 84 | //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line), | 84 | //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line), |
| ... | @@ -1023,6 +1023,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1023,6 +1023,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1023 | .i386, .x86_64 => { | 1023 | .i386, .x86_64 => { |
| 1024 | try self.code.append(0xcc); // int3 | 1024 | try self.code.append(0xcc); // int3 |
| 1025 | }, | 1025 | }, |
| | 1026 | .riscv64 => { |
| | 1027 | const full = @bitCast(u32, Instructions.CallBreak{ |
| | 1028 | .mode = @enumToInt(Instructions.CallBreak.Mode.ebreak), |
| | 1029 | }); |
| | 1030 | |
| | 1031 | try self.code.resize(self.code.items.len + 4); |
| | 1032 | mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], full); |
| | 1033 | }, |
| 1026 | else => return self.fail(src, "TODO implement @breakpoint() for {}", .{self.target.cpu.arch}), | 1034 | else => return self.fail(src, "TODO implement @breakpoint() for {}", .{self.target.cpu.arch}), |
| 1027 | } | 1035 | } |
| 1028 | return .none; | 1036 | return .none; |
| ... | @@ -1325,36 +1333,73 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1325,36 +1333,73 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1325 | fn genAsm(self: *Self, inst: *ir.Inst.Assembly) !MCValue { | 1333 | fn genAsm(self: *Self, inst: *ir.Inst.Assembly) !MCValue { |
| 1326 | if (!inst.is_volatile and inst.base.isUnused()) | 1334 | if (!inst.is_volatile and inst.base.isUnused()) |
| 1327 | return MCValue.dead; | 1335 | return MCValue.dead; |
| 1328 | if (arch != .x86_64 and arch != .i386) { | 1336 | switch (arch) { |
| 1329 | return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{}); | 1337 | .riscv64 => { |
| 1330 | } | 1338 | for (inst.inputs) |input, i| { |
| 1331 | for (inst.inputs) |input, i| { | 1339 | if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') { |
| 1332 | if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') { | 1340 | return self.fail(inst.base.src, "unrecognized asm input constraint: '{}'", .{input}); |
| 1333 | return self.fail(inst.base.src, "unrecognized asm input constraint: '{}'", .{input}); | 1341 | } |
| 1334 | } | 1342 | const reg_name = input[1 .. input.len - 1]; |
| 1335 | const reg_name = input[1 .. input.len - 1]; | 1343 | const reg = parseRegName(reg_name) orelse |
| 1336 | const reg = parseRegName(reg_name) orelse | 1344 | return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name}); |
| 1337 | return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name}); | 1345 | const arg = try self.resolveInst(inst.args[i]); |
| 1338 | const arg = try self.resolveInst(inst.args[i]); | 1346 | try self.genSetReg(inst.base.src, reg, arg); |
| 1339 | try self.genSetReg(inst.base.src, reg, arg); | 1347 | } |
| 1340 | } | | |
| 1341 | | 1348 | |
| 1342 | if (mem.eql(u8, inst.asm_source, "syscall")) { | 1349 | if (mem.eql(u8, inst.asm_source, "ecall")) { |
| 1343 | try self.code.appendSlice(&[_]u8{ 0x0f, 0x05 }); | 1350 | const full = @bitCast(u32, Instructions.CallBreak{ |
| 1344 | } else { | 1351 | .mode = @enumToInt(Instructions.CallBreak.Mode.ecall), |
| 1345 | return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{}); | 1352 | }); |
| 1346 | } | | |
| 1347 | | 1353 | |
| 1348 | if (inst.output) |output| { | 1354 | try self.code.resize(self.code.items.len + 4); |
| 1349 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { | 1355 | mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], full); |
| 1350 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{}'", .{output}); | 1356 | } else { |
| 1351 | } | 1357 | return self.fail(inst.base.src, "TODO implement support for more riscv64 assembly instructions", .{}); |
| 1352 | const reg_name = output[2 .. output.len - 1]; | 1358 | } |
| 1353 | const reg = parseRegName(reg_name) orelse | 1359 | |
| 1354 | return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name}); | 1360 | if (inst.output) |output| { |
| 1355 | return MCValue{ .register = reg }; | 1361 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { |
| 1356 | } else { | 1362 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{}'", .{output}); |
| 1357 | return MCValue.none; | 1363 | } |
| | 1364 | const reg_name = output[2 .. output.len - 1]; |
| | 1365 | const reg = parseRegName(reg_name) orelse |
| | 1366 | return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name}); |
| | 1367 | return MCValue{ .register = reg }; |
| | 1368 | } else { |
| | 1369 | return MCValue.none; |
| | 1370 | } |
| | 1371 | }, |
| | 1372 | .x86_64, .i386 => { |
| | 1373 | for (inst.inputs) |input, i| { |
| | 1374 | if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') { |
| | 1375 | return self.fail(inst.base.src, "unrecognized asm input constraint: '{}'", .{input}); |
| | 1376 | } |
| | 1377 | const reg_name = input[1 .. input.len - 1]; |
| | 1378 | const reg = parseRegName(reg_name) orelse |
| | 1379 | return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name}); |
| | 1380 | const arg = try self.resolveInst(inst.args[i]); |
| | 1381 | try self.genSetReg(inst.base.src, reg, arg); |
| | 1382 | } |
| | 1383 | |
| | 1384 | if (mem.eql(u8, inst.asm_source, "syscall")) { |
| | 1385 | try self.code.appendSlice(&[_]u8{ 0x0f, 0x05 }); |
| | 1386 | } else { |
| | 1387 | return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{}); |
| | 1388 | } |
| | 1389 | |
| | 1390 | if (inst.output) |output| { |
| | 1391 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { |
| | 1392 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{}'", .{output}); |
| | 1393 | } |
| | 1394 | const reg_name = output[2 .. output.len - 1]; |
| | 1395 | const reg = parseRegName(reg_name) orelse |
| | 1396 | return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name}); |
| | 1397 | return MCValue{ .register = reg }; |
| | 1398 | } else { |
| | 1399 | return MCValue.none; |
| | 1400 | } |
| | 1401 | }, |
| | 1402 | else => return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{}), |
| 1358 | } | 1403 | } |
| 1359 | } | 1404 | } |
| 1360 | | 1405 | |
| ... | @@ -1500,6 +1545,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1500,6 +1545,31 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1500 | | 1545 | |
| 1501 | fn genSetReg(self: *Self, src: usize, reg: Register, mcv: MCValue) InnerError!void { | 1546 | fn genSetReg(self: *Self, src: usize, reg: Register, mcv: MCValue) InnerError!void { |
| 1502 | switch (arch) { | 1547 | switch (arch) { |
| | 1548 | .riscv64 => switch (mcv) { |
| | 1549 | .immediate => |x| { |
| | 1550 | if (x > math.maxInt(u11)) { |
| | 1551 | return self.fail(src, "TODO genSetReg 12+ bit immediates for riscv64", .{}); |
| | 1552 | } |
| | 1553 | const Instruction = packed struct { |
| | 1554 | opcode: u7, |
| | 1555 | rd: u5, |
| | 1556 | mode: u3, |
| | 1557 | rsi1: u5, |
| | 1558 | imm: u11, |
| | 1559 | signextend: u1 = 0, |
| | 1560 | }; |
| | 1561 | const full = @bitCast(u32, Instructions.Addi{ |
| | 1562 | .imm = @intCast(u11, x), |
| | 1563 | .rsi1 = Register.zero.id(), |
| | 1564 | .mode = @enumToInt(Instructions.Addi.Mode.addi), |
| | 1565 | .rd = reg.id(), |
| | 1566 | }); |
| | 1567 | |
| | 1568 | try self.code.resize(self.code.items.len + 4); |
| | 1569 | mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], full); |
| | 1570 | }, |
| | 1571 | else => return self.fail(src, "TODO implement getSetReg for riscv64 MCValue {}", .{mcv}), |
| | 1572 | }, |
| 1503 | .x86_64 => switch (mcv) { | 1573 | .x86_64 => switch (mcv) { |
| 1504 | .dead => unreachable, | 1574 | .dead => unreachable, |
| 1505 | .ptr_stack_offset => unreachable, | 1575 | .ptr_stack_offset => unreachable, |
| ... | @@ -1873,7 +1943,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1873,7 +1943,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1873 | else => return self.fail(src, "TODO implement function parameters for {}", .{cc}), | 1943 | else => return self.fail(src, "TODO implement function parameters for {}", .{cc}), |
| 1874 | } | 1944 | } |
| 1875 | }, | 1945 | }, |
| 1876 | else => return self.fail(src, "TODO implement codegen parameters for {}", .{self.target.cpu.arch}), | 1946 | else => if (param_types.len != 0) |
| | 1947 | return self.fail(src, "TODO implement codegen parameters for {}", .{self.target.cpu.arch}), |
| 1877 | } | 1948 | } |
| 1878 | | 1949 | |
| 1879 | if (ret_ty.zigTypeTag() == .NoReturn) { | 1950 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| ... | @@ -1915,6 +1986,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1915,6 +1986,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1915 | usingnamespace switch (arch) { | 1986 | usingnamespace switch (arch) { |
| 1916 | .i386 => @import("codegen/x86.zig"), | 1987 | .i386 => @import("codegen/x86.zig"), |
| 1917 | .x86_64 => @import("codegen/x86_64.zig"), | 1988 | .x86_64 => @import("codegen/x86_64.zig"), |
| | 1989 | .riscv64 => @import("codegen/riscv64.zig"), |
| 1918 | else => struct { | 1990 | else => struct { |
| 1919 | pub const Register = enum { | 1991 | pub const Register = enum { |
| 1920 | dummy, | 1992 | dummy, |