| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const mem = std.mem; | 2 | const mem = std.mem; |
| | 3 | const math = std.math; |
| 3 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 4 | const ir = @import("ir.zig"); | 5 | const ir = @import("ir.zig"); |
| 5 | const Type = @import("type.zig").Type; | 6 | const Type = @import("type.zig").Type; |
| ... | @@ -50,57 +51,58 @@ pub fn generateSymbol( | ... | @@ -50,57 +51,58 @@ pub fn generateSymbol( |
| 50 | switch (typed_value.ty.zigTypeTag()) { | 51 | switch (typed_value.ty.zigTypeTag()) { |
| 51 | .Fn => { | 52 | .Fn => { |
| 52 | switch (bin_file.options.target.cpu.arch) { | 53 | switch (bin_file.options.target.cpu.arch) { |
| 53 | .arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code), | 54 | //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code), |
| 54 | .armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code), | 55 | //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code), |
| 55 | .aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code), | 56 | //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code), |
| 56 | .aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code), | 57 | //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code), |
| 57 | .aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code), | 58 | //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code), |
| 58 | .arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code), | 59 | //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code), |
| 59 | .avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code), | 60 | //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code), |
| 60 | .bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code), | 61 | //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code), |
| 61 | .bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code), | 62 | //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code), |
| 62 | .hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code), | 63 | //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code), |
| 63 | .mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code), | 64 | //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code), |
| 64 | .mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code), | 65 | //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code), |
| 65 | .mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code), | 66 | //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code), |
| 66 | .mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code), | 67 | //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code), |
| 67 | .msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code), | 68 | //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code), |
| 68 | .powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code), | 69 | //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code), |
| 69 | .powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code), | 70 | //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code), |
| 70 | .powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code), | 71 | //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code), |
| 71 | .r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code), | 72 | //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code), |
| 72 | .amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code), | 73 | //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code), |
| 73 | .riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code), | 74 | //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code), |
| 74 | .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code), | 75 | //.riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code), |
| 75 | .sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code), | 76 | //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code), |
| 76 | .sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code), | 77 | //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code), |
| 77 | .sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code), | 78 | //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code), |
| 78 | .s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code), | 79 | //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code), |
| 79 | .tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code), | 80 | //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code), |
| 80 | .tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code), | 81 | //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code), |
| 81 | .thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code), | 82 | //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code), |
| 82 | .thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code), | 83 | //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code), |
| 83 | .i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code), | 84 | //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code), |
| 84 | .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code), | 85 | .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code), |
| 85 | .xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code), | 86 | //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code), |
| 86 | .nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code), | 87 | //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code), |
| 87 | .nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code), | 88 | //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code), |
| 88 | .le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code), | 89 | //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code), |
| 89 | .le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code), | 90 | //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code), |
| 90 | .amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code), | 91 | //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code), |
| 91 | .amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code), | 92 | //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code), |
| 92 | .hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code), | 93 | //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code), |
| 93 | .hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code), | 94 | //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code), |
| 94 | .spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code), | 95 | //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code), |
| 95 | .spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code), | 96 | //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code), |
| 96 | .kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code), | 97 | //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code), |
| 97 | .shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code), | 98 | //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code), |
| 98 | .lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code), | 99 | //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code), |
| 99 | .wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code), | 100 | //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code), |
| 100 | .wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code), | 101 | //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code), |
| 101 | .renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code), | 102 | //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code), |
| 102 | .renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code), | 103 | //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code), |
| 103 | .ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code), | 104 | //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code), |
| | 105 | else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."), |
| 104 | } | 106 | } |
| 105 | }, | 107 | }, |
| 106 | .Array => { | 108 | .Array => { |
| ... | @@ -209,6 +211,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -209,6 +211,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 209 | ret_mcv: MCValue, | 211 | ret_mcv: MCValue, |
| 210 | arg_index: usize, | 212 | arg_index: usize, |
| 211 | src: usize, | 213 | src: usize, |
| | 214 | stack_align: u32, |
| 212 | | 215 | |
| 213 | /// Whenever there is a runtime branch, we push a Branch onto this stack, | 216 | /// Whenever there is a runtime branch, we push a Branch onto this stack, |
| 214 | /// and pop it off when the runtime branch joins. This provides an "overlay" | 217 | /// and pop it off when the runtime branch joins. This provides an "overlay" |
| ... | @@ -238,10 +241,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -238,10 +241,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 238 | stack_offset: u64, | 241 | stack_offset: u64, |
| 239 | /// The value is in the compare flags assuming an unsigned operation, | 242 | /// The value is in the compare flags assuming an unsigned operation, |
| 240 | /// with this operator applied on top of it. | 243 | /// with this operator applied on top of it. |
| 241 | compare_flags_unsigned: std.math.CompareOperator, | 244 | compare_flags_unsigned: math.CompareOperator, |
| 242 | /// The value is in the compare flags assuming a signed operation, | 245 | /// The value is in the compare flags assuming a signed operation, |
| 243 | /// with this operator applied on top of it. | 246 | /// with this operator applied on top of it. |
| 244 | compare_flags_signed: std.math.CompareOperator, | 247 | compare_flags_signed: math.CompareOperator, |
| 245 | | 248 | |
| 246 | fn isMemory(mcv: MCValue) bool { | 249 | fn isMemory(mcv: MCValue) bool { |
| 247 | return switch (mcv) { | 250 | return switch (mcv) { |
| ... | @@ -280,10 +283,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -280,10 +283,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 280 | const Branch = struct { | 283 | const Branch = struct { |
| 281 | inst_table: std.AutoHashMapUnmanaged(*ir.Inst, MCValue) = .{}, | 284 | inst_table: std.AutoHashMapUnmanaged(*ir.Inst, MCValue) = .{}, |
| 282 | registers: std.AutoHashMapUnmanaged(Register, RegisterAllocation) = .{}, | 285 | registers: std.AutoHashMapUnmanaged(Register, RegisterAllocation) = .{}, |
| 283 | free_registers: FreeRegInt = std.math.maxInt(FreeRegInt), | 286 | free_registers: FreeRegInt = math.maxInt(FreeRegInt), |
| 284 | | 287 | |
| 285 | /// Maps offset to what is stored there. | 288 | /// Maps offset to what is stored there. |
| 286 | stack: std.AutoHashMapUnmanaged(usize, StackAllocation) = .{}, | 289 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, |
| 287 | /// Offset from the stack base, representing the end of the stack frame. | 290 | /// Offset from the stack base, representing the end of the stack frame. |
| 288 | max_end_stack: u32 = 0, | 291 | max_end_stack: u32 = 0, |
| 289 | /// Represents the current end stack offset. If there is no existing slot | 292 | /// Represents the current end stack offset. If there is no existing slot |
| ... | @@ -293,7 +296,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -293,7 +296,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 293 | fn markRegUsed(self: *Branch, reg: Register) void { | 296 | fn markRegUsed(self: *Branch, reg: Register) void { |
| 294 | if (FreeRegInt == u0) return; | 297 | if (FreeRegInt == u0) return; |
| 295 | const index = reg.allocIndex() orelse return; | 298 | const index = reg.allocIndex() orelse return; |
| 296 | const ShiftInt = std.math.Log2Int(FreeRegInt); | 299 | const ShiftInt = math.Log2Int(FreeRegInt); |
| 297 | const shift = @intCast(ShiftInt, index); | 300 | const shift = @intCast(ShiftInt, index); |
| 298 | self.free_registers &= ~(@as(FreeRegInt, 1) << shift); | 301 | self.free_registers &= ~(@as(FreeRegInt, 1) << shift); |
| 299 | } | 302 | } |
| ... | @@ -301,7 +304,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -301,7 +304,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 301 | fn markRegFree(self: *Branch, reg: Register) void { | 304 | fn markRegFree(self: *Branch, reg: Register) void { |
| 302 | if (FreeRegInt == u0) return; | 305 | if (FreeRegInt == u0) return; |
| 303 | const index = reg.allocIndex() orelse return; | 306 | const index = reg.allocIndex() orelse return; |
| 304 | const ShiftInt = std.math.Log2Int(FreeRegInt); | 307 | const ShiftInt = math.Log2Int(FreeRegInt); |
| 305 | const shift = @intCast(ShiftInt, index); | 308 | const shift = @intCast(ShiftInt, index); |
| 306 | self.free_registers |= @as(FreeRegInt, 1) << shift; | 309 | self.free_registers |= @as(FreeRegInt, 1) << shift; |
| 307 | } | 310 | } |
| ... | @@ -356,6 +359,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -356,6 +359,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 356 | .arg_index = 0, | 359 | .arg_index = 0, |
| 357 | .branch_stack = &branch_stack, | 360 | .branch_stack = &branch_stack, |
| 358 | .src = src, | 361 | .src = src, |
| | 362 | .stack_align = undefined, |
| 359 | }; | 363 | }; |
| 360 | | 364 | |
| 361 | var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) { | 365 | var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) { |
| ... | @@ -366,6 +370,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -366,6 +370,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 366 | | 370 | |
| 367 | function.args = call_info.args; | 371 | function.args = call_info.args; |
| 368 | function.ret_mcv = call_info.return_value; | 372 | function.ret_mcv = call_info.return_value; |
| | 373 | function.stack_align = call_info.stack_align; |
| 369 | branch.max_end_stack = call_info.stack_byte_count; | 374 | branch.max_end_stack = call_info.stack_byte_count; |
| 370 | | 375 | |
| 371 | function.gen() catch |err| switch (err) { | 376 | function.gen() catch |err| switch (err) { |
| ... | @@ -383,15 +388,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -383,15 +388,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 383 | fn gen(self: *Self) !void { | 388 | fn gen(self: *Self) !void { |
| 384 | try self.code.ensureCapacity(self.code.items.len + 11); | 389 | try self.code.ensureCapacity(self.code.items.len + 11); |
| 385 | | 390 | |
| | 391 | // TODO omit this for naked functions |
| 386 | // push rbp | 392 | // push rbp |
| 387 | // mov rbp, rsp | 393 | // mov rbp, rsp |
| 388 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0x55, 0x48, 0x89, 0xe5 }); | 394 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0x55, 0x48, 0x89, 0xe5 }); |
| 389 | | 395 | |
| 390 | // sub rsp, x | 396 | // sub rsp, x |
| 391 | const stack_end = self.branch_stack.items[0].max_end_stack; | 397 | const stack_end = self.branch_stack.items[0].max_end_stack; |
| 392 | if (stack_end > std.math.maxInt(i32)) { | 398 | if (stack_end > math.maxInt(i32)) { |
| 393 | return self.fail(self.src, "too much stack used in call parameters", .{}); | 399 | return self.fail(self.src, "too much stack used in call parameters", .{}); |
| 394 | } else if (stack_end > std.math.maxInt(i8)) { | 400 | } else if (stack_end > math.maxInt(i8)) { |
| 395 | // 48 83 ec xx sub rsp,0x10 | 401 | // 48 83 ec xx sub rsp,0x10 |
| 396 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0x48, 0x81, 0xec }); | 402 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0x48, 0x81, 0xec }); |
| 397 | const x = @intCast(u32, stack_end); | 403 | const x = @intCast(u32, stack_end); |
| ... | @@ -436,6 +442,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -436,6 +442,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 436 | fn genFuncInst(self: *Self, inst: *ir.Inst) !MCValue { | 442 | fn genFuncInst(self: *Self, inst: *ir.Inst) !MCValue { |
| 437 | switch (inst.tag) { | 443 | switch (inst.tag) { |
| 438 | .add => return self.genAdd(inst.castTag(.add).?), | 444 | .add => return self.genAdd(inst.castTag(.add).?), |
| | 445 | .alloc => return self.genAlloc(inst.castTag(.alloc).?), |
| 439 | .arg => return self.genArg(inst.castTag(.arg).?), | 446 | .arg => return self.genArg(inst.castTag(.arg).?), |
| 440 | .assembly => return self.genAsm(inst.castTag(.assembly).?), | 447 | .assembly => return self.genAsm(inst.castTag(.assembly).?), |
| 441 | .bitcast => return self.genBitCast(inst.castTag(.bitcast).?), | 448 | .bitcast => return self.genBitCast(inst.castTag(.bitcast).?), |
| ... | @@ -465,6 +472,28 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -465,6 +472,28 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 465 | } | 472 | } |
| 466 | } | 473 | } |
| 467 | | 474 | |
| | 475 | fn genAlloc(self: *Self, inst: *ir.Inst.NoOp) !MCValue { |
| | 476 | const elem_ty = inst.base.ty.elemType(); |
| | 477 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch { |
| | 478 | return self.fail(inst.base.src, "type '{}' too big to fit into stack frame", .{elem_ty}); |
| | 479 | }; |
| | 480 | // TODO swap this for inst.base.ty.ptrAlign |
| | 481 | const abi_align = elem_ty.abiAlignment(self.target.*); |
| | 482 | if (abi_align > self.stack_align) |
| | 483 | self.stack_align = abi_align; |
| | 484 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| | 485 | // TODO find a free slot instead of always appending |
| | 486 | const offset = mem.alignForwardGeneric(u32, branch.next_stack_offset, abi_align); |
| | 487 | branch.next_stack_offset = offset + abi_size; |
| | 488 | if (branch.next_stack_offset > branch.max_end_stack) |
| | 489 | branch.max_end_stack = branch.next_stack_offset; |
| | 490 | try branch.stack.putNoClobber(self.gpa, offset, .{ |
| | 491 | .inst = &inst.base, |
| | 492 | .size = abi_size, |
| | 493 | }); |
| | 494 | return MCValue{ .stack_offset = offset }; |
| | 495 | } |
| | 496 | |
| 468 | fn genFloatCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue { | 497 | fn genFloatCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 469 | // No side effects, so if it's unreferenced, do nothing. | 498 | // No side effects, so if it's unreferenced, do nothing. |
| 470 | if (inst.base.isUnused()) | 499 | if (inst.base.isUnused()) |
| ... | @@ -610,7 +639,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -610,7 +639,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 610 | // and as a register. | 639 | // and as a register. |
| 611 | switch (src_mcv) { | 640 | switch (src_mcv) { |
| 612 | .immediate => |imm| { | 641 | .immediate => |imm| { |
| 613 | if (imm > std.math.maxInt(u31)) { | 642 | if (imm > math.maxInt(u31)) { |
| 614 | src_mcv = try self.copyToNewRegister(src_inst); | 643 | src_mcv = try self.copyToNewRegister(src_inst); |
| 615 | } | 644 | } |
| 616 | }, | 645 | }, |
| ... | @@ -639,7 +668,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -639,7 +668,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 639 | .immediate => |imm| { | 668 | .immediate => |imm| { |
| 640 | const imm32 = @intCast(u31, imm); // This case must be handled before calling genX8664BinMathCode. | 669 | const imm32 = @intCast(u31, imm); // This case must be handled before calling genX8664BinMathCode. |
| 641 | // 81 /opx id | 670 | // 81 /opx id |
| 642 | if (imm32 <= std.math.maxInt(u7)) { | 671 | if (imm32 <= math.maxInt(u7)) { |
| 643 | self.rex(.{ .b = dst_reg.isExtended(), .w = dst_reg.size() == 64 }); | 672 | self.rex(.{ .b = dst_reg.isExtended(), .w = dst_reg.size() == 64 }); |
| 644 | self.code.appendSliceAssumeCapacity(&[_]u8{ | 673 | self.code.appendSliceAssumeCapacity(&[_]u8{ |
| 645 | 0x83, | 674 | 0x83, |
| ... | @@ -785,7 +814,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -785,7 +814,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 785 | return self.ret(inst.base.src, .none); | 814 | return self.ret(inst.base.src, .none); |
| 786 | } | 815 | } |
| 787 | | 816 | |
| 788 | fn genCmp(self: *Self, inst: *ir.Inst.BinOp, op: std.math.CompareOperator) !MCValue { | 817 | fn genCmp(self: *Self, inst: *ir.Inst.BinOp, op: math.CompareOperator) !MCValue { |
| 789 | // No side effects, so if it's unreferenced, do nothing. | 818 | // No side effects, so if it's unreferenced, do nothing. |
| 790 | if (inst.base.isUnused()) | 819 | if (inst.base.isUnused()) |
| 791 | return MCValue.dead; | 820 | return MCValue.dead; |
| ... | @@ -909,7 +938,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -909,7 +938,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 909 | switch (reloc) { | 938 | switch (reloc) { |
| 910 | .rel32 => |pos| { | 939 | .rel32 => |pos| { |
| 911 | const amt = self.code.items.len - (pos + 4); | 940 | const amt = self.code.items.len - (pos + 4); |
| 912 | const s32_amt = std.math.cast(i32, amt) catch | 941 | const s32_amt = math.cast(i32, amt) catch |
| 913 | return self.fail(src, "unable to perform relocation: jump too far", .{}); | 942 | return self.fail(src, "unable to perform relocation: jump too far", .{}); |
| 914 | mem.writeIntLittle(i32, self.code.items[pos..][0..4], s32_amt); | 943 | mem.writeIntLittle(i32, self.code.items[pos..][0..4], s32_amt); |
| 915 | }, | 944 | }, |
| ... | @@ -1070,7 +1099,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1070,7 +1099,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1070 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0x31, 0xC0 | id << 3 | id }); | 1099 | self.code.appendSliceAssumeCapacity(&[_]u8{ 0x31, 0xC0 | id << 3 | id }); |
| 1071 | return; | 1100 | return; |
| 1072 | } | 1101 | } |
| 1073 | if (x <= std.math.maxInt(u32)) { | 1102 | if (x <= math.maxInt(u32)) { |
| 1074 | // Next best case: if we set the lower four bytes, the upper four will be zeroed. | 1103 | // Next best case: if we set the lower four bytes, the upper four will be zeroed. |
| 1075 | // | 1104 | // |
| 1076 | // The encoding for `mov IMM32 -> REG` is (0xB8 + R) IMM. | 1105 | // The encoding for `mov IMM32 -> REG` is (0xB8 + R) IMM. |
| ... | @@ -1152,7 +1181,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1152,7 +1181,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1152 | if (reg.size() != 64) { | 1181 | if (reg.size() != 64) { |
| 1153 | return self.fail(src, "TODO decide whether to implement non-64-bit loads", .{}); | 1182 | return self.fail(src, "TODO decide whether to implement non-64-bit loads", .{}); |
| 1154 | } | 1183 | } |
| 1155 | if (x <= std.math.maxInt(u32)) { | 1184 | if (x <= math.maxInt(u32)) { |
| 1156 | // Moving from memory to a register is a variant of `8B /r`. | 1185 | // Moving from memory to a register is a variant of `8B /r`. |
| 1157 | // Since we're using 64-bit moves, we require a REX. | 1186 | // Since we're using 64-bit moves, we require a REX. |
| 1158 | // This variant also requires a SIB, as it would otherwise be RIP-relative. | 1187 | // This variant also requires a SIB, as it would otherwise be RIP-relative. |
| ... | @@ -1285,7 +1314,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1285,7 +1314,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1285 | .is_signed = false, | 1314 | .is_signed = false, |
| 1286 | }, | 1315 | }, |
| 1287 | }); | 1316 | }); |
| 1288 | if (imm >= std.math.maxInt(U)) { | 1317 | if (imm >= math.maxInt(U)) { |
| 1289 | return self.copyToNewRegister(inst); | 1318 | return self.copyToNewRegister(inst); |
| 1290 | } | 1319 | } |
| 1291 | }, | 1320 | }, |
| ... | @@ -1327,6 +1356,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1327,6 +1356,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1327 | args: []MCValue, | 1356 | args: []MCValue, |
| 1328 | return_value: MCValue, | 1357 | return_value: MCValue, |
| 1329 | stack_byte_count: u32, | 1358 | stack_byte_count: u32, |
| | 1359 | stack_align: u32, |
| 1330 | | 1360 | |
| 1331 | fn deinit(self: *CallMCValues, func: *Self) void { | 1361 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 1332 | func.gpa.free(self.args); | 1362 | func.gpa.free(self.args); |
| ... | @@ -1342,8 +1372,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1342,8 +1372,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1342 | fn_ty.fnParamTypes(param_types); | 1372 | fn_ty.fnParamTypes(param_types); |
| 1343 | var result: CallMCValues = .{ | 1373 | var result: CallMCValues = .{ |
| 1344 | .args = try self.gpa.alloc(MCValue, param_types.len), | 1374 | .args = try self.gpa.alloc(MCValue, param_types.len), |
| | 1375 | // These undefined values must be populated before returning from this function. |
| 1345 | .return_value = undefined, | 1376 | .return_value = undefined, |
| 1346 | .stack_byte_count = undefined, | 1377 | .stack_byte_count = undefined, |
| | 1378 | .stack_align = undefined, |
| 1347 | }; | 1379 | }; |
| 1348 | errdefer self.gpa.free(result.args); | 1380 | errdefer self.gpa.free(result.args); |
| 1349 | | 1381 | |
| ... | @@ -1356,6 +1388,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1356,6 +1388,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1356 | assert(result.args.len == 0); | 1388 | assert(result.args.len == 0); |
| 1357 | result.return_value = .{ .unreach = {} }; | 1389 | result.return_value = .{ .unreach = {} }; |
| 1358 | result.stack_byte_count = 0; | 1390 | result.stack_byte_count = 0; |
| | 1391 | result.stack_align = 1; |
| 1359 | return result; | 1392 | return result; |
| 1360 | }, | 1393 | }, |
| 1361 | .Unspecified, .C => { | 1394 | .Unspecified, .C => { |
| ... | @@ -1377,6 +1410,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1377,6 +1410,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1377 | } | 1410 | } |
| 1378 | } | 1411 | } |
| 1379 | result.stack_byte_count = next_stack_offset; | 1412 | result.stack_byte_count = next_stack_offset; |
| | 1413 | result.stack_align = 16; |
| 1380 | }, | 1414 | }, |
| 1381 | else => return self.fail(src, "TODO implement function parameters for {}", .{cc}), | 1415 | else => return self.fail(src, "TODO implement function parameters for {}", .{cc}), |
| 1382 | } | 1416 | } |