| ... | @@ -146,6 +146,10 @@ pub const LLVMIRModule = struct { | ... | @@ -146,6 +146,10 @@ pub const LLVMIRModule = struct { |
| 146 | gpa: *Allocator, | 146 | gpa: *Allocator, |
| 147 | err_msg: ?*Compilation.ErrorMsg = null, | 147 | err_msg: ?*Compilation.ErrorMsg = null, |
| 148 | | 148 | |
| | 149 | /// This stores the LLVM values used in a function, such that they can be |
| | 150 | /// referred to in other instructions. This table is cleared before every function is generated. |
| | 151 | func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.ValueRef) = .{}, |
| | 152 | |
| 149 | pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule { | 153 | pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule { |
| 150 | const self = try allocator.create(LLVMIRModule); | 154 | const self = try allocator.create(LLVMIRModule); |
| 151 | errdefer allocator.destroy(self); | 155 | errdefer allocator.destroy(self); |
| ... | @@ -283,7 +287,10 @@ pub const LLVMIRModule = struct { | ... | @@ -283,7 +287,10 @@ pub const LLVMIRModule = struct { |
| 283 | .Fn => { | 287 | .Fn => { |
| 284 | const func = typed_value.val.castTag(.function).?.data; | 288 | const func = typed_value.val.castTag(.function).?.data; |
| 285 | | 289 | |
| 286 | const llvm_func = try self.resolveLLVMFunction(func); | 290 | const llvm_func = try self.resolveLLVMFunction(func, src); |
| | 291 | |
| | 292 | // Make sure no other LLVM values from other functions can be referenced |
| | 293 | self.func_inst_table.clearRetainingCapacity(); |
| 287 | | 294 | |
| 288 | // We remove all the basic blocks of a function to support incremental | 295 | // We remove all the basic blocks of a function to support incremental |
| 289 | // compilation! | 296 | // compilation! |
| ... | @@ -297,29 +304,33 @@ pub const LLVMIRModule = struct { | ... | @@ -297,29 +304,33 @@ pub const LLVMIRModule = struct { |
| 297 | | 304 | |
| 298 | const instructions = func.body.instructions; | 305 | const instructions = func.body.instructions; |
| 299 | for (instructions) |inst| { | 306 | for (instructions) |inst| { |
| 300 | switch (inst.tag) { | 307 | const opt_llvm_val: ?*const llvm.ValueRef = switch (inst.tag) { |
| 301 | .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?), | 308 | .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?), |
| 302 | .call => try self.genCall(inst.castTag(.call).?), | 309 | .call => try self.genCall(inst.castTag(.call).?), |
| 303 | .unreach => self.genUnreach(inst.castTag(.unreach).?), | 310 | .unreach => self.genUnreach(inst.castTag(.unreach).?), |
| 304 | .retvoid => self.genRetVoid(inst.castTag(.retvoid).?), | 311 | .retvoid => self.genRetVoid(inst.castTag(.retvoid).?), |
| 305 | .arg => self.genArg(inst.castTag(.arg).?), | 312 | .arg => try self.genArg(inst.castTag(.arg).?), |
| 306 | .dbg_stmt => { | 313 | .alloc => try self.genAlloc(inst.castTag(.alloc).?), |
| | 314 | .store => try self.genStore(inst.castTag(.store).?), |
| | 315 | .dbg_stmt => blk: { |
| 307 | // TODO: implement debug info | 316 | // TODO: implement debug info |
| | 317 | break :blk null; |
| 308 | }, | 318 | }, |
| 309 | else => |tag| return self.fail(src, "TODO implement LLVM codegen for Zir instruction: {}", .{tag}), | 319 | else => |tag| return self.fail(src, "TODO implement LLVM codegen for Zir instruction: {}", .{tag}), |
| 310 | } | 320 | }; |
| | 321 | if (opt_llvm_val) |llvm_val| try self.func_inst_table.put(self.gpa, inst, llvm_val); |
| 311 | } | 322 | } |
| 312 | }, | 323 | }, |
| 313 | else => |ty| return self.fail(src, "TODO implement LLVM codegen for top-level decl type: {}", .{ty}), | 324 | else => |ty| return self.fail(src, "TODO implement LLVM codegen for top-level decl type: {}", .{ty}), |
| 314 | } | 325 | } |
| 315 | } | 326 | } |
| 316 | | 327 | |
| 317 | fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !void { | 328 | fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !?*const llvm.ValueRef { |
| 318 | if (inst.func.value()) |func_value| { | 329 | if (inst.func.value()) |func_value| { |
| 319 | if (func_value.castTag(.function)) |func_payload| { | 330 | if (func_value.castTag(.function)) |func_payload| { |
| 320 | const func = func_payload.data; | 331 | const func = func_payload.data; |
| 321 | const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty; | 332 | const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty; |
| 322 | const llvm_fn = try self.resolveLLVMFunction(func); | 333 | const llvm_fn = try self.resolveLLVMFunction(func, inst.base.src); |
| 323 | | 334 | |
| 324 | const num_args = inst.args.len; | 335 | const num_args = inst.args.len; |
| 325 | | 336 | |
| ... | @@ -339,42 +350,73 @@ pub const LLVMIRModule = struct { | ... | @@ -339,42 +350,73 @@ pub const LLVMIRModule = struct { |
| 339 | "", | 350 | "", |
| 340 | ); | 351 | ); |
| 341 | | 352 | |
| 342 | if (zig_fn_type.fnReturnType().zigTypeTag() == .NoReturn) { | 353 | const return_type = zig_fn_type.fnReturnType().zigTypeTag(); |
| | 354 | if (return_type == .NoReturn) { |
| 343 | _ = self.builder.buildUnreachable(); | 355 | _ = self.builder.buildUnreachable(); |
| 344 | } | 356 | } |
| | 357 | |
| | 358 | // No need to store the LLVM value if the return type is void or noreturn |
| | 359 | if (return_type == .NoReturn or return_type == .Void) return null; |
| | 360 | |
| | 361 | return call; |
| 345 | } | 362 | } |
| 346 | } | 363 | } |
| | 364 | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer LLVM backend", .{}); |
| 347 | } | 365 | } |
| 348 | | 366 | |
| 349 | fn genRetVoid(self: *LLVMIRModule, inst: *Inst.NoOp) void { | 367 | fn genRetVoid(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.ValueRef { |
| 350 | _ = self.builder.buildRetVoid(); | 368 | _ = self.builder.buildRetVoid(); |
| | 369 | return null; |
| 351 | } | 370 | } |
| 352 | | 371 | |
| 353 | fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) void { | 372 | fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.ValueRef { |
| 354 | _ = self.builder.buildUnreachable(); | 373 | _ = self.builder.buildUnreachable(); |
| | 374 | return null; |
| 355 | } | 375 | } |
| 356 | | 376 | |
| 357 | fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) void { | 377 | fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) !?*const llvm.ValueRef { |
| 358 | // TODO: implement this | 378 | // TODO: implement this |
| | 379 | return null; |
| 359 | } | 380 | } |
| 360 | | 381 | |
| 361 | fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !void { | 382 | fn genAlloc(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.ValueRef { |
| | 383 | // buildAlloca expects the pointee type, not the pointer type, so assert that |
| | 384 | // a Payload.PointerSimple is passed to the alloc instruction. |
| | 385 | const pointee_type = inst.base.ty.castPointer().?.data; |
| | 386 | |
| | 387 | // TODO: figure out a way to get the name of the var decl. |
| | 388 | // TODO: set alignment and volatile |
| | 389 | return self.builder.buildAlloca(try self.getLLVMType(pointee_type, inst.base.src), ""); |
| | 390 | } |
| | 391 | |
| | 392 | fn genStore(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.ValueRef { |
| | 393 | const val = try self.resolveInst(inst.rhs); |
| | 394 | const ptr = try self.resolveInst(inst.lhs); |
| | 395 | _ = self.builder.buildStore(val, ptr); |
| | 396 | return null; |
| | 397 | } |
| | 398 | |
| | 399 | fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.ValueRef { |
| 362 | // TODO: Store this function somewhere such that we dont have to add it again | 400 | // TODO: Store this function somewhere such that we dont have to add it again |
| 363 | const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false); | 401 | const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false); |
| 364 | const func = self.llvm_module.addFunction("llvm.debugtrap", fn_type); | 402 | const func = self.llvm_module.addFunction("llvm.debugtrap", fn_type); |
| | 403 | |
| 365 | // TODO: add assertion: LLVMGetIntrinsicID | 404 | // TODO: add assertion: LLVMGetIntrinsicID |
| 366 | _ = self.builder.buildCall(func, null, 0, ""); | 405 | _ = self.builder.buildCall(func, null, 0, ""); |
| | 406 | return null; |
| 367 | } | 407 | } |
| 368 | | 408 | |
| 369 | fn resolveInst(self: *LLVMIRModule, inst: *ir.Inst) !*const llvm.ValueRef { | 409 | fn resolveInst(self: *LLVMIRModule, inst: *ir.Inst) !*const llvm.ValueRef { |
| 370 | if (inst.castTag(.constant)) |const_inst| { | 410 | if (inst.castTag(.constant)) |const_inst| { |
| 371 | return self.genTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val }); | 411 | return self.genTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val }); |
| 372 | } | 412 | } |
| 373 | return self.fail(inst.src, "TODO implement resolveInst", .{}); | 413 | if (self.func_inst_table.get(inst)) |value| return value; |
| | 414 | |
| | 415 | return self.fail(inst.src, "TODO implement global llvm values (or the value is not in the func_inst_table table)", .{}); |
| 374 | } | 416 | } |
| 375 | | 417 | |
| 376 | fn genTypedValue(self: *LLVMIRModule, src: usize, typed_value: TypedValue) !*const llvm.ValueRef { | 418 | fn genTypedValue(self: *LLVMIRModule, src: usize, typed_value: TypedValue) !*const llvm.ValueRef { |
| 377 | const llvm_type = self.getLLVMType(typed_value.ty); | 419 | const llvm_type = try self.getLLVMType(typed_value.ty, src); |
| 378 | | 420 | |
| 379 | if (typed_value.val.isUndef()) | 421 | if (typed_value.val.isUndef()) |
| 380 | return llvm_type.getUndef(); | 422 | return llvm_type.getUndef(); |
| ... | @@ -386,7 +428,7 @@ pub const LLVMIRModule = struct { | ... | @@ -386,7 +428,7 @@ pub const LLVMIRModule = struct { |
| 386 | } | 428 | } |
| 387 | | 429 | |
| 388 | /// If the llvm function does not exist, create it | 430 | /// If the llvm function does not exist, create it |
| 389 | fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Fn) !*const llvm.ValueRef { | 431 | fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Fn, src: usize) !*const llvm.ValueRef { |
| 390 | // TODO: do we want to store this in our own datastructure? | 432 | // TODO: do we want to store this in our own datastructure? |
| 391 | if (self.llvm_module.getNamedFunction(func.owner_decl.name)) |llvm_fn| return llvm_fn; | 433 | if (self.llvm_module.getNamedFunction(func.owner_decl.name)) |llvm_fn| return llvm_fn; |
| 392 | | 434 | |
| ... | @@ -403,11 +445,11 @@ pub const LLVMIRModule = struct { | ... | @@ -403,11 +445,11 @@ pub const LLVMIRModule = struct { |
| 403 | defer self.gpa.free(llvm_param); | 445 | defer self.gpa.free(llvm_param); |
| 404 | | 446 | |
| 405 | for (fn_param_types) |fn_param, i| { | 447 | for (fn_param_types) |fn_param, i| { |
| 406 | llvm_param[i] = self.getLLVMType(fn_param); | 448 | llvm_param[i] = try self.getLLVMType(fn_param, src); |
| 407 | } | 449 | } |
| 408 | | 450 | |
| 409 | const fn_type = llvm.TypeRef.functionType( | 451 | const fn_type = llvm.TypeRef.functionType( |
| 410 | self.getLLVMType(return_type), | 452 | try self.getLLVMType(return_type, src), |
| 411 | if (fn_param_len == 0) null else llvm_param.ptr, | 453 | if (fn_param_len == 0) null else llvm_param.ptr, |
| 412 | @intCast(c_uint, fn_param_len), | 454 | @intCast(c_uint, fn_param_len), |
| 413 | false, | 455 | false, |
| ... | @@ -421,7 +463,7 @@ pub const LLVMIRModule = struct { | ... | @@ -421,7 +463,7 @@ pub const LLVMIRModule = struct { |
| 421 | return llvm_fn; | 463 | return llvm_fn; |
| 422 | } | 464 | } |
| 423 | | 465 | |
| 424 | fn getLLVMType(self: *LLVMIRModule, t: Type) *const llvm.TypeRef { | 466 | fn getLLVMType(self: *LLVMIRModule, t: Type, src: usize) !*const llvm.TypeRef { |
| 425 | switch (t.zigTypeTag()) { | 467 | switch (t.zigTypeTag()) { |
| 426 | .Void => return llvm.voidType(), | 468 | .Void => return llvm.voidType(), |
| 427 | .NoReturn => return llvm.voidType(), | 469 | .NoReturn => return llvm.voidType(), |
| ... | @@ -430,7 +472,7 @@ pub const LLVMIRModule = struct { | ... | @@ -430,7 +472,7 @@ pub const LLVMIRModule = struct { |
| 430 | return llvm.intType(info.bits); | 472 | return llvm.intType(info.bits); |
| 431 | }, | 473 | }, |
| 432 | .Bool => return llvm.intType(1), | 474 | .Bool => return llvm.intType(1), |
| 433 | else => unreachable, | 475 | else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}), |
| 434 | } | 476 | } |
| 435 | } | 477 | } |
| 436 | | 478 | |