| ... | ... | @@ -37,6 +37,69 @@ pub fn generateSymbol( |
| 37 | 37 | .Fn => { |
| 38 | 38 | const module_fn = typed_value.val.cast(Value.Payload.Function).?.func; |
| 39 | 39 | |
| 40 | const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty; |
| 41 | const param_types = try bin_file.allocator.alloc(Type, fn_type.fnParamLen()); |
| 42 | defer bin_file.allocator.free(param_types); |
| 43 | fn_type.fnParamTypes(param_types); |
| 44 | // A parameter may be broken into multiple machine code parameters, so we don't |
| 45 | // know the size up front. |
| 46 | var mc_args = try std.ArrayList(Function.MCValue).initCapacity(bin_file.allocator, param_types.len); |
| 47 | defer mc_args.deinit(); |
| 48 | |
| 49 | var next_stack_offset: u64 = 0; |
| 50 | |
| 51 | switch (fn_type.fnCallingConvention()) { |
| 52 | .Naked => assert(mc_args.items.len == 0), |
| 53 | .Unspecified, .C => { |
| 54 | // Prepare the function parameters |
| 55 | switch (bin_file.options.target.cpu.arch) { |
| 56 | .x86_64 => { |
| 57 | const integer_registers = [_]Reg(.x86_64){.rdi, .rsi, .rdx, .rcx, .r8, .r9}; |
| 58 | var next_int_reg: usize = 0; |
| 59 | |
| 60 | for (param_types) |param_type, src_i| { |
| 61 | switch (param_type.zigTypeTag()) { |
| 62 | .Bool, .Int => { |
| 63 | if (next_int_reg >= integer_registers.len) { |
| 64 | try mc_args.append(.{ .stack_offset = next_stack_offset }); |
| 65 | next_stack_offset += param_type.abiSize(bin_file.options.target); |
| 66 | } else { |
| 67 | try mc_args.append(.{ .register = @enumToInt(integer_registers[next_int_reg])}); |
| 68 | next_int_reg += 1; |
| 69 | } |
| 70 | }, |
| 71 | else => return Result{ |
| 72 | .fail = try ErrorMsg.create( |
| 73 | bin_file.allocator, |
| 74 | src, |
| 75 | "TODO implement function parameters of type {}", |
| 76 | .{@tagName(param_type.zigTypeTag())}, |
| 77 | ), |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | }, |
| 83 | else => return Result{ |
| 84 | .fail = try ErrorMsg.create( |
| 85 | bin_file.allocator, |
| 86 | src, |
| 87 | "TODO implement function parameters for {}", |
| 88 | .{bin_file.options.target.cpu.arch}, |
| 89 | ), |
| 90 | }, |
| 91 | } |
| 92 | }, |
| 93 | else => return Result{ |
| 94 | .fail = try ErrorMsg.create( |
| 95 | bin_file.allocator, |
| 96 | src, |
| 97 | "TODO implement {} calling convention", |
| 98 | .{fn_type.fnCallingConvention()}, |
| 99 | ), |
| 100 | }, |
| 101 | } |
| 102 | |
| 40 | 103 | var function = Function{ |
| 41 | 104 | .target = &bin_file.options.target, |
| 42 | 105 | .bin_file = bin_file, |
| ... | ... | @@ -44,16 +107,14 @@ pub fn generateSymbol( |
| 44 | 107 | .code = code, |
| 45 | 108 | .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(bin_file.allocator), |
| 46 | 109 | .err_msg = null, |
| 110 | .args = mc_args.items, |
| 47 | 111 | }; |
| 48 | 112 | defer function.inst_table.deinit(); |
| 49 | 113 | |
| 50 | | for (module_fn.analysis.success.instructions) |inst| { |
| 51 | | const new_inst = function.genFuncInst(inst) catch |err| switch (err) { |
| 52 | | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| 53 | | else => |e| return e, |
| 54 | | }; |
| 55 | | try function.inst_table.putNoClobber(inst, new_inst); |
| 56 | | } |
| 114 | function.gen() catch |err| switch (err) { |
| 115 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| 116 | else => |e| return e, |
| 117 | }; |
| 57 | 118 | |
| 58 | 119 | if (function.err_msg) |em| { |
| 59 | 120 | return Result{ .fail = em }; |
| ... | ... | @@ -157,6 +218,7 @@ const Function = struct { |
| 157 | 218 | code: *std.ArrayList(u8), |
| 158 | 219 | inst_table: std.AutoHashMap(*ir.Inst, MCValue), |
| 159 | 220 | err_msg: ?*ErrorMsg, |
| 221 | args: []MCValue, |
| 160 | 222 | |
| 161 | 223 | const MCValue = union(enum) { |
| 162 | 224 | none, |
| ... | ... | @@ -170,44 +232,119 @@ const Function = struct { |
| 170 | 232 | register: usize, |
| 171 | 233 | /// The value is in memory at a hard-coded address. |
| 172 | 234 | memory: u64, |
| 235 | /// The value is one of the stack variables. |
| 236 | stack_offset: u64, |
| 173 | 237 | }; |
| 174 | 238 | |
| 175 | | fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue { |
| 239 | fn gen(self: *Function) !void { |
| 240 | switch (self.target.cpu.arch) { |
| 241 | .arm => return self.genArch(.arm), |
| 242 | .armeb => return self.genArch(.armeb), |
| 243 | .aarch64 => return self.genArch(.aarch64), |
| 244 | .aarch64_be => return self.genArch(.aarch64_be), |
| 245 | .aarch64_32 => return self.genArch(.aarch64_32), |
| 246 | .arc => return self.genArch(.arc), |
| 247 | .avr => return self.genArch(.avr), |
| 248 | .bpfel => return self.genArch(.bpfel), |
| 249 | .bpfeb => return self.genArch(.bpfeb), |
| 250 | .hexagon => return self.genArch(.hexagon), |
| 251 | .mips => return self.genArch(.mips), |
| 252 | .mipsel => return self.genArch(.mipsel), |
| 253 | .mips64 => return self.genArch(.mips64), |
| 254 | .mips64el => return self.genArch(.mips64el), |
| 255 | .msp430 => return self.genArch(.msp430), |
| 256 | .powerpc => return self.genArch(.powerpc), |
| 257 | .powerpc64 => return self.genArch(.powerpc64), |
| 258 | .powerpc64le => return self.genArch(.powerpc64le), |
| 259 | .r600 => return self.genArch(.r600), |
| 260 | .amdgcn => return self.genArch(.amdgcn), |
| 261 | .riscv32 => return self.genArch(.riscv32), |
| 262 | .riscv64 => return self.genArch(.riscv64), |
| 263 | .sparc => return self.genArch(.sparc), |
| 264 | .sparcv9 => return self.genArch(.sparcv9), |
| 265 | .sparcel => return self.genArch(.sparcel), |
| 266 | .s390x => return self.genArch(.s390x), |
| 267 | .tce => return self.genArch(.tce), |
| 268 | .tcele => return self.genArch(.tcele), |
| 269 | .thumb => return self.genArch(.thumb), |
| 270 | .thumbeb => return self.genArch(.thumbeb), |
| 271 | .i386 => return self.genArch(.i386), |
| 272 | .x86_64 => return self.genArch(.x86_64), |
| 273 | .xcore => return self.genArch(.xcore), |
| 274 | .nvptx => return self.genArch(.nvptx), |
| 275 | .nvptx64 => return self.genArch(.nvptx64), |
| 276 | .le32 => return self.genArch(.le32), |
| 277 | .le64 => return self.genArch(.le64), |
| 278 | .amdil => return self.genArch(.amdil), |
| 279 | .amdil64 => return self.genArch(.amdil64), |
| 280 | .hsail => return self.genArch(.hsail), |
| 281 | .hsail64 => return self.genArch(.hsail64), |
| 282 | .spir => return self.genArch(.spir), |
| 283 | .spir64 => return self.genArch(.spir64), |
| 284 | .kalimba => return self.genArch(.kalimba), |
| 285 | .shave => return self.genArch(.shave), |
| 286 | .lanai => return self.genArch(.lanai), |
| 287 | .wasm32 => return self.genArch(.wasm32), |
| 288 | .wasm64 => return self.genArch(.wasm64), |
| 289 | .renderscript32 => return self.genArch(.renderscript32), |
| 290 | .renderscript64 => return self.genArch(.renderscript64), |
| 291 | .ve => return self.genArch(.ve), |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | fn genArch(self: *Function, comptime arch: std.Target.Cpu.Arch) !void { |
| 296 | for (self.mod_fn.analysis.success.instructions) |inst| { |
| 297 | const new_inst = try self.genFuncInst(inst, arch); |
| 298 | try self.inst_table.putNoClobber(inst, new_inst); |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | fn genFuncInst(self: *Function, inst: *ir.Inst, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 176 | 303 | switch (inst.tag) { |
| 177 | | .add => return self.genAdd(inst.cast(ir.Inst.Add).?), |
| 178 | | .arg => return self.genArg(inst.src), |
| 179 | | .block => return self.genBlock(inst.cast(ir.Inst.Block).?), |
| 180 | | .breakpoint => return self.genBreakpoint(inst.src), |
| 181 | | .call => return self.genCall(inst.cast(ir.Inst.Call).?), |
| 304 | .add => return self.genAdd(inst.cast(ir.Inst.Add).?, arch), |
| 305 | .arg => return self.genArg(inst.cast(ir.Inst.Arg).?), |
| 306 | .block => return self.genBlock(inst.cast(ir.Inst.Block).?, arch), |
| 307 | .breakpoint => return self.genBreakpoint(inst.src, arch), |
| 308 | .call => return self.genCall(inst.cast(ir.Inst.Call).?, arch), |
| 182 | 309 | .unreach => return MCValue{ .unreach = {} }, |
| 183 | 310 | .constant => unreachable, // excluded from function bodies |
| 184 | | .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?), |
| 311 | .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?, arch), |
| 185 | 312 | .ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?), |
| 186 | 313 | .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?), |
| 187 | | .ret => return self.genRet(inst.cast(ir.Inst.Ret).?), |
| 188 | | .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?), |
| 189 | | .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?), |
| 190 | | .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?), |
| 191 | | .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?), |
| 192 | | .isnonnull => return self.genIsNonNull(inst.cast(ir.Inst.IsNonNull).?), |
| 314 | .ret => return self.genRet(inst.cast(ir.Inst.Ret).?, arch), |
| 315 | .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?, arch), |
| 316 | .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?, arch), |
| 317 | .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?, arch), |
| 318 | .isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?, arch), |
| 319 | .isnonnull => return self.genIsNonNull(inst.cast(ir.Inst.IsNonNull).?, arch), |
| 193 | 320 | } |
| 194 | 321 | } |
| 195 | 322 | |
| 196 | | fn genAdd(self: *Function, inst: *ir.Inst.Add) !MCValue { |
| 197 | | switch (self.target.cpu.arch) { |
| 323 | fn genAdd(self: *Function, inst: *ir.Inst.Add, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 324 | const lhs = try self.resolveInst(inst.args.lhs); |
| 325 | const rhs = try self.resolveInst(inst.args.rhs); |
| 326 | switch (arch) { |
| 327 | .i386, .x86_64 => { |
| 328 | // const lhs_reg = try self.instAsReg(lhs); |
| 329 | // const rhs_reg = try self.instAsReg(rhs); |
| 330 | // const result = try self.allocateReg(); |
| 331 | |
| 332 | // try self.code.append(??); |
| 333 | |
| 334 | // lhs_reg.release(); |
| 335 | // rhs_reg.release(); |
| 336 | return self.fail(inst.base.src, "TODO implement register allocation", .{}); |
| 337 | }, |
| 198 | 338 | else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}), |
| 199 | 339 | } |
| 200 | 340 | } |
| 201 | 341 | |
| 202 | | fn genArg(self: *Function, src: usize) !MCValue { |
| 203 | | switch (self.target.cpu.arch) { |
| 204 | | else => return self.fail(src, "TODO implement function parameters for {}", .{self.target.cpu.arch}), |
| 205 | | } |
| 206 | | return .none; |
| 342 | fn genArg(self: *Function, inst: *ir.Inst.Arg) !MCValue { |
| 343 | return self.args[inst.args.index]; |
| 207 | 344 | } |
| 208 | 345 | |
| 209 | | fn genBreakpoint(self: *Function, src: usize) !MCValue { |
| 210 | | switch (self.target.cpu.arch) { |
| 346 | fn genBreakpoint(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 347 | switch (arch) { |
| 211 | 348 | .i386, .x86_64 => { |
| 212 | 349 | try self.code.append(0xcc); // int3 |
| 213 | 350 | }, |
| ... | ... | @@ -216,8 +353,8 @@ const Function = struct { |
| 216 | 353 | return .none; |
| 217 | 354 | } |
| 218 | 355 | |
| 219 | | fn genCall(self: *Function, inst: *ir.Inst.Call) !MCValue { |
| 220 | | switch (self.target.cpu.arch) { |
| 356 | fn genCall(self: *Function, inst: *ir.Inst.Call, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 357 | switch (arch) { |
| 221 | 358 | .x86_64, .i386 => { |
| 222 | 359 | if (inst.args.func.cast(ir.Inst.Constant)) |func_inst| { |
| 223 | 360 | if (inst.args.args.len != 0) { |
| ... | ... | @@ -251,11 +388,11 @@ const Function = struct { |
| 251 | 388 | } |
| 252 | 389 | } |
| 253 | 390 | |
| 254 | | fn ret(self: *Function, src: usize, mcv: MCValue) !MCValue { |
| 391 | fn ret(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch, mcv: MCValue) !MCValue { |
| 255 | 392 | if (mcv != .none) { |
| 256 | 393 | return self.fail(src, "TODO implement return with non-void operand", .{}); |
| 257 | 394 | } |
| 258 | | switch (self.target.cpu.arch) { |
| 395 | switch (arch) { |
| 259 | 396 | .i386, .x86_64 => { |
| 260 | 397 | try self.code.append(0xc3); // ret |
| 261 | 398 | }, |
| ... | ... | @@ -264,43 +401,43 @@ const Function = struct { |
| 264 | 401 | return .unreach; |
| 265 | 402 | } |
| 266 | 403 | |
| 267 | | fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue { |
| 404 | fn genRet(self: *Function, inst: *ir.Inst.Ret, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 268 | 405 | const operand = try self.resolveInst(inst.args.operand); |
| 269 | | return self.ret(inst.base.src, operand); |
| 406 | return self.ret(inst.base.src, arch, operand); |
| 270 | 407 | } |
| 271 | 408 | |
| 272 | | fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid) !MCValue { |
| 273 | | return self.ret(inst.base.src, .none); |
| 409 | fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 410 | return self.ret(inst.base.src, arch, .none); |
| 274 | 411 | } |
| 275 | 412 | |
| 276 | | fn genCmp(self: *Function, inst: *ir.Inst.Cmp) !MCValue { |
| 277 | | switch (self.target.cpu.arch) { |
| 413 | fn genCmp(self: *Function, inst: *ir.Inst.Cmp, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 414 | switch (arch) { |
| 278 | 415 | else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}), |
| 279 | 416 | } |
| 280 | 417 | } |
| 281 | 418 | |
| 282 | | fn genCondBr(self: *Function, inst: *ir.Inst.CondBr) !MCValue { |
| 283 | | switch (self.target.cpu.arch) { |
| 419 | fn genCondBr(self: *Function, inst: *ir.Inst.CondBr, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 420 | switch (arch) { |
| 284 | 421 | else => return self.fail(inst.base.src, "TODO implement condbr for {}", .{self.target.cpu.arch}), |
| 285 | 422 | } |
| 286 | 423 | } |
| 287 | 424 | |
| 288 | | fn genIsNull(self: *Function, inst: *ir.Inst.IsNull) !MCValue { |
| 289 | | switch (self.target.cpu.arch) { |
| 425 | fn genIsNull(self: *Function, inst: *ir.Inst.IsNull, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 426 | switch (arch) { |
| 290 | 427 | else => return self.fail(inst.base.src, "TODO implement isnull for {}", .{self.target.cpu.arch}), |
| 291 | 428 | } |
| 292 | 429 | } |
| 293 | 430 | |
| 294 | | fn genIsNonNull(self: *Function, inst: *ir.Inst.IsNonNull) !MCValue { |
| 431 | fn genIsNonNull(self: *Function, inst: *ir.Inst.IsNonNull, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 295 | 432 | // Here you can specialize this instruction if it makes sense to, otherwise the default |
| 296 | 433 | // will call genIsNull and invert the result. |
| 297 | | switch (self.target.cpu.arch) { |
| 434 | switch (arch) { |
| 298 | 435 | else => return self.fail(inst.base.src, "TODO call genIsNull and invert the result ", .{}), |
| 299 | 436 | } |
| 300 | 437 | } |
| 301 | 438 | |
| 302 | | fn genRelativeFwdJump(self: *Function, src: usize, amount: u32) !void { |
| 303 | | switch (self.target.cpu.arch) { |
| 439 | fn genRelativeFwdJump(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch, amount: u32) !void { |
| 440 | switch (arch) { |
| 304 | 441 | .i386, .x86_64 => { |
| 305 | 442 | // TODO x86 treats the operands as signed |
| 306 | 443 | if (amount <= std.math.maxInt(u8)) { |
| ... | ... | @@ -318,70 +455,13 @@ const Function = struct { |
| 318 | 455 | } |
| 319 | 456 | } |
| 320 | 457 | |
| 321 | | fn genBlock(self: *Function, inst: *ir.Inst.Block) !MCValue { |
| 322 | | switch (self.target.cpu.arch) { |
| 458 | fn genBlock(self: *Function, inst: *ir.Inst.Block, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 459 | switch (arch) { |
| 323 | 460 | else => return self.fail(inst.base.src, "TODO implement codegen Block for {}", .{self.target.cpu.arch}), |
| 324 | 461 | } |
| 325 | 462 | } |
| 326 | 463 | |
| 327 | | fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue { |
| 328 | | // TODO convert to inline function |
| 329 | | switch (self.target.cpu.arch) { |
| 330 | | .arm => return self.genAsmArch(.arm, inst), |
| 331 | | .armeb => return self.genAsmArch(.armeb, inst), |
| 332 | | .aarch64 => return self.genAsmArch(.aarch64, inst), |
| 333 | | .aarch64_be => return self.genAsmArch(.aarch64_be, inst), |
| 334 | | .aarch64_32 => return self.genAsmArch(.aarch64_32, inst), |
| 335 | | .arc => return self.genAsmArch(.arc, inst), |
| 336 | | .avr => return self.genAsmArch(.avr, inst), |
| 337 | | .bpfel => return self.genAsmArch(.bpfel, inst), |
| 338 | | .bpfeb => return self.genAsmArch(.bpfeb, inst), |
| 339 | | .hexagon => return self.genAsmArch(.hexagon, inst), |
| 340 | | .mips => return self.genAsmArch(.mips, inst), |
| 341 | | .mipsel => return self.genAsmArch(.mipsel, inst), |
| 342 | | .mips64 => return self.genAsmArch(.mips64, inst), |
| 343 | | .mips64el => return self.genAsmArch(.mips64el, inst), |
| 344 | | .msp430 => return self.genAsmArch(.msp430, inst), |
| 345 | | .powerpc => return self.genAsmArch(.powerpc, inst), |
| 346 | | .powerpc64 => return self.genAsmArch(.powerpc64, inst), |
| 347 | | .powerpc64le => return self.genAsmArch(.powerpc64le, inst), |
| 348 | | .r600 => return self.genAsmArch(.r600, inst), |
| 349 | | .amdgcn => return self.genAsmArch(.amdgcn, inst), |
| 350 | | .riscv32 => return self.genAsmArch(.riscv32, inst), |
| 351 | | .riscv64 => return self.genAsmArch(.riscv64, inst), |
| 352 | | .sparc => return self.genAsmArch(.sparc, inst), |
| 353 | | .sparcv9 => return self.genAsmArch(.sparcv9, inst), |
| 354 | | .sparcel => return self.genAsmArch(.sparcel, inst), |
| 355 | | .s390x => return self.genAsmArch(.s390x, inst), |
| 356 | | .tce => return self.genAsmArch(.tce, inst), |
| 357 | | .tcele => return self.genAsmArch(.tcele, inst), |
| 358 | | .thumb => return self.genAsmArch(.thumb, inst), |
| 359 | | .thumbeb => return self.genAsmArch(.thumbeb, inst), |
| 360 | | .i386 => return self.genAsmArch(.i386, inst), |
| 361 | | .x86_64 => return self.genAsmArch(.x86_64, inst), |
| 362 | | .xcore => return self.genAsmArch(.xcore, inst), |
| 363 | | .nvptx => return self.genAsmArch(.nvptx, inst), |
| 364 | | .nvptx64 => return self.genAsmArch(.nvptx64, inst), |
| 365 | | .le32 => return self.genAsmArch(.le32, inst), |
| 366 | | .le64 => return self.genAsmArch(.le64, inst), |
| 367 | | .amdil => return self.genAsmArch(.amdil, inst), |
| 368 | | .amdil64 => return self.genAsmArch(.amdil64, inst), |
| 369 | | .hsail => return self.genAsmArch(.hsail, inst), |
| 370 | | .hsail64 => return self.genAsmArch(.hsail64, inst), |
| 371 | | .spir => return self.genAsmArch(.spir, inst), |
| 372 | | .spir64 => return self.genAsmArch(.spir64, inst), |
| 373 | | .kalimba => return self.genAsmArch(.kalimba, inst), |
| 374 | | .shave => return self.genAsmArch(.shave, inst), |
| 375 | | .lanai => return self.genAsmArch(.lanai, inst), |
| 376 | | .wasm32 => return self.genAsmArch(.wasm32, inst), |
| 377 | | .wasm64 => return self.genAsmArch(.wasm64, inst), |
| 378 | | .renderscript32 => return self.genAsmArch(.renderscript32, inst), |
| 379 | | .renderscript64 => return self.genAsmArch(.renderscript64, inst), |
| 380 | | .ve => return self.genAsmArch(.ve, inst), |
| 381 | | } |
| 382 | | } |
| 383 | | |
| 384 | | fn genAsmArch(self: *Function, comptime arch: Target.Cpu.Arch, inst: *ir.Inst.Assembly) !MCValue { |
| 464 | fn genAsm(self: *Function, inst: *ir.Inst.Assembly, comptime arch: Target.Cpu.Arch) !MCValue { |
| 385 | 465 | if (arch != .x86_64 and arch != .i386) { |
| 386 | 466 | return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{}); |
| 387 | 467 | } |
| ... | ... | @@ -607,6 +687,9 @@ const Function = struct { |
| 607 | 687 | } |
| 608 | 688 | } |
| 609 | 689 | }, |
| 690 | .stack_offset => |off| { |
| 691 | return self.fail(src, "TODO implement genSetReg for stack variables", .{}); |
| 692 | } |
| 610 | 693 | }, |
| 611 | 694 | else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}), |
| 612 | 695 | } |