| ... | @@ -136,8 +136,11 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 { | ... | @@ -136,8 +136,11 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 { |
| 136 | } | 136 | } |
| 137 | | 137 | |
| 138 | pub const LLVMIRModule = struct { | 138 | pub const LLVMIRModule = struct { |
| | 139 | module: *Module, |
| 139 | llvm_module: *const llvm.ModuleRef, | 140 | llvm_module: *const llvm.ModuleRef, |
| 140 | target_machine: *const llvm.TargetMachineRef, | 141 | target_machine: *const llvm.TargetMachineRef, |
| | 142 | builder: *const llvm.BuilderRef, |
| | 143 | |
| 141 | output_path: []const u8, | 144 | output_path: []const u8, |
| 142 | | 145 | |
| 143 | gpa: *Allocator, | 146 | gpa: *Allocator, |
| ... | @@ -192,9 +195,14 @@ pub const LLVMIRModule = struct { | ... | @@ -192,9 +195,14 @@ pub const LLVMIRModule = struct { |
| 192 | ); | 195 | ); |
| 193 | errdefer target_machine.disposeTargetMachine(); | 196 | errdefer target_machine.disposeTargetMachine(); |
| 194 | | 197 | |
| | 198 | const builder = llvm.BuilderRef.createBuilder(); |
| | 199 | errdefer builder.disposeBuilder(); |
| | 200 | |
| 195 | self.* = .{ | 201 | self.* = .{ |
| | 202 | .module = options.module.?, |
| 196 | .llvm_module = llvm_module, | 203 | .llvm_module = llvm_module, |
| 197 | .target_machine = target_machine, | 204 | .target_machine = target_machine, |
| | 205 | .builder = builder, |
| 198 | .output_path = sub_path, | 206 | .output_path = sub_path, |
| 199 | .gpa = gpa, | 207 | .gpa = gpa, |
| 200 | }; | 208 | }; |
| ... | @@ -202,8 +210,9 @@ pub const LLVMIRModule = struct { | ... | @@ -202,8 +210,9 @@ pub const LLVMIRModule = struct { |
| 202 | } | 210 | } |
| 203 | | 211 | |
| 204 | pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void { | 212 | pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void { |
| 205 | self.llvm_module.disposeModule(); | 213 | self.builder.disposeBuilder(); |
| 206 | self.target_machine.disposeTargetMachine(); | 214 | self.target_machine.disposeTargetMachine(); |
| | 215 | self.llvm_module.disposeModule(); |
| 207 | allocator.destroy(self); | 216 | allocator.destroy(self); |
| 208 | } | 217 | } |
| 209 | | 218 | |
| ... | @@ -216,6 +225,14 @@ pub const LLVMIRModule = struct { | ... | @@ -216,6 +225,14 @@ pub const LLVMIRModule = struct { |
| 216 | } | 225 | } |
| 217 | | 226 | |
| 218 | pub fn flushModule(self: *LLVMIRModule, comp: *Compilation) !void { | 227 | pub fn flushModule(self: *LLVMIRModule, comp: *Compilation) !void { |
| | 228 | if (comp.verbose_llvm_ir) { |
| | 229 | const dump = self.llvm_module.printToString(); |
| | 230 | defer llvm.disposeMessage(dump); |
| | 231 | |
| | 232 | const stderr = std.io.getStdErr().outStream(); |
| | 233 | try stderr.writeAll(std.mem.spanZ(dump)); |
| | 234 | } |
| | 235 | |
| 219 | { | 236 | { |
| 220 | var error_message: [*:0]const u8 = undefined; | 237 | var error_message: [*:0]const u8 = undefined; |
| 221 | // verifyModule always allocs the error_message even if there is no error | 238 | // verifyModule always allocs the error_message even if there is no error |
| ... | @@ -228,14 +245,6 @@ pub const LLVMIRModule = struct { | ... | @@ -228,14 +245,6 @@ pub const LLVMIRModule = struct { |
| 228 | } | 245 | } |
| 229 | } | 246 | } |
| 230 | | 247 | |
| 231 | if (comp.verbose_llvm_ir) { | | |
| 232 | const dump = self.llvm_module.printToString(); | | |
| 233 | defer llvm.disposeMessage(dump); | | |
| 234 | | | |
| 235 | const stderr = std.io.getStdErr().outStream(); | | |
| 236 | try stderr.writeAll(std.mem.spanZ(dump)); | | |
| 237 | } | | |
| 238 | | | |
| 239 | const output_pathZ = try self.gpa.dupeZ(u8, self.output_path); | 248 | const output_pathZ = try self.gpa.dupeZ(u8, self.output_path); |
| 240 | defer self.gpa.free(output_pathZ); | 249 | defer self.gpa.free(output_pathZ); |
| 241 | | 250 | |
| ... | @@ -258,7 +267,7 @@ pub const LLVMIRModule = struct { | ... | @@ -258,7 +267,7 @@ pub const LLVMIRModule = struct { |
| 258 | | 267 | |
| 259 | pub fn updateDecl(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void { | 268 | pub fn updateDecl(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void { |
| 260 | const typed_value = decl.typed_value.most_recent.typed_value; | 269 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 261 | self.generate(module, typed_value, decl.src()) catch |err| switch (err) { | 270 | self.gen(module, typed_value, decl.src()) catch |err| switch (err) { |
| 262 | error.CodegenFail => { | 271 | error.CodegenFail => { |
| 263 | decl.analysis = .codegen_failure; | 272 | decl.analysis = .codegen_failure; |
| 264 | try module.failed_decls.put(module.gpa, decl, self.err_msg.?); | 273 | try module.failed_decls.put(module.gpa, decl, self.err_msg.?); |
| ... | @@ -268,19 +277,12 @@ pub const LLVMIRModule = struct { | ... | @@ -268,19 +277,12 @@ pub const LLVMIRModule = struct { |
| 268 | }; | 277 | }; |
| 269 | } | 278 | } |
| 270 | | 279 | |
| 271 | fn generate(self: *LLVMIRModule, module: *Module, typed_value: TypedValue, src: usize) !void { | 280 | fn gen(self: *LLVMIRModule, module: *Module, typed_value: TypedValue, src: usize) !void { |
| 272 | switch (typed_value.ty.zigTypeTag()) { | 281 | switch (typed_value.ty.zigTypeTag()) { |
| 273 | .Fn => { | 282 | .Fn => { |
| 274 | const func = typed_value.val.cast(Value.Payload.Function).?.func; | 283 | const func = typed_value.val.cast(Value.Payload.Function).?.func; |
| 275 | | 284 | |
| 276 | var codegen = CodeGen{ | 285 | const llvm_func = try self.resolveLLVMFunction(func); |
| 277 | .module = module, | | |
| 278 | .llvm_module = self.llvm_module, | | |
| 279 | .builder = llvm.BuilderRef.createBuilder(), | | |
| 280 | }; | | |
| 281 | defer codegen.builder.disposeBuilder(); | | |
| 282 | | | |
| 283 | const llvm_func = try codegen.resolveLLVMFunction(func); | | |
| 284 | | 286 | |
| 285 | // We remove all the basic blocks of a function to support incremental | 287 | // We remove all the basic blocks of a function to support incremental |
| 286 | // compilation! | 288 | // compilation! |
| ... | @@ -290,15 +292,15 @@ pub const LLVMIRModule = struct { | ... | @@ -290,15 +292,15 @@ pub const LLVMIRModule = struct { |
| 290 | } | 292 | } |
| 291 | | 293 | |
| 292 | const entry_block = llvm_func.appendBasicBlock("Entry"); | 294 | const entry_block = llvm_func.appendBasicBlock("Entry"); |
| 293 | codegen.builder.positionBuilderAtEnd(entry_block); | 295 | self.builder.positionBuilderAtEnd(entry_block); |
| 294 | | 296 | |
| 295 | const instructions = func.analysis.success.instructions; | 297 | const instructions = func.analysis.success.instructions; |
| 296 | for (instructions) |inst| { | 298 | for (instructions) |inst| { |
| 297 | switch (inst.tag) { | 299 | switch (inst.tag) { |
| 298 | .breakpoint => try codegen.generateBreakpoint(inst.castTag(.breakpoint).?), | 300 | .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?), |
| 299 | .call => try codegen.generateCall(inst.castTag(.call).?), | 301 | .call => try self.genCall(inst.castTag(.call).?), |
| 300 | .unreach => codegen.generateUnreach(inst.castTag(.unreach).?), | 302 | .unreach => self.genUnreach(inst.castTag(.unreach).?), |
| 301 | .retvoid => codegen.generateRetVoid(inst.castTag(.retvoid).?), | 303 | .retvoid => self.genRetVoid(inst.castTag(.retvoid).?), |
| 302 | .dbg_stmt => { | 304 | .dbg_stmt => { |
| 303 | // TODO: implement debug info | 305 | // TODO: implement debug info |
| 304 | }, | 306 | }, |
| ... | @@ -310,83 +312,70 @@ pub const LLVMIRModule = struct { | ... | @@ -310,83 +312,70 @@ pub const LLVMIRModule = struct { |
| 310 | } | 312 | } |
| 311 | } | 313 | } |
| 312 | | 314 | |
| 313 | pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { | 315 | fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !void { |
| 314 | @setCold(true); | | |
| 315 | std.debug.assert(self.err_msg == null); | | |
| 316 | self.err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args); | | |
| 317 | return error.CodegenFail; | | |
| 318 | } | | |
| 319 | }; | | |
| 320 | | | |
| 321 | const CodeGen = struct { | | |
| 322 | module: *Module, | | |
| 323 | llvm_module: *const llvm.ModuleRef, | | |
| 324 | builder: *const llvm.BuilderRef, | | |
| 325 | | | |
| 326 | fn generateCall(codegen: *CodeGen, inst: *Inst.Call) !void { | | |
| 327 | if (inst.func.cast(Inst.Constant)) |func_inst| { | 316 | if (inst.func.cast(Inst.Constant)) |func_inst| { |
| 328 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | 317 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { |
| 329 | const func = func_val.func; | 318 | const func = func_val.func; |
| 330 | const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty; | 319 | const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty; |
| 331 | const llvm_fn = try codegen.resolveLLVMFunction(func); | 320 | const llvm_fn = try self.resolveLLVMFunction(func); |
| 332 | | 321 | |
| 333 | // TODO: handle more arguments, inst.args | 322 | // TODO: handle more arguments, inst.args |
| 334 | | 323 | |
| 335 | // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs | 324 | // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs |
| 336 | // Do we need that? | 325 | // Do we need that? |
| 337 | const call = codegen.builder.buildCall(llvm_fn, null, 0, ""); | 326 | const call = self.builder.buildCall(llvm_fn, null, 0, ""); |
| 338 | | 327 | |
| 339 | if (zig_fn_type.fnReturnType().zigTypeTag() == .NoReturn) { | 328 | if (zig_fn_type.fnReturnType().zigTypeTag() == .NoReturn) { |
| 340 | _ = codegen.builder.buildUnreachable(); | 329 | _ = self.builder.buildUnreachable(); |
| 341 | } | 330 | } |
| 342 | } | 331 | } |
| 343 | } | 332 | } |
| 344 | } | 333 | } |
| 345 | | 334 | |
| 346 | fn generateRetVoid(codegen: *CodeGen, inst: *Inst.NoOp) void { | 335 | fn genRetVoid(self: *LLVMIRModule, inst: *Inst.NoOp) void { |
| 347 | _ = codegen.builder.buildRetVoid(); | 336 | _ = self.builder.buildRetVoid(); |
| 348 | } | 337 | } |
| 349 | | 338 | |
| 350 | fn generateUnreach(codegen: *CodeGen, inst: *Inst.NoOp) void { | 339 | fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) void { |
| 351 | _ = codegen.builder.buildUnreachable(); | 340 | _ = self.builder.buildUnreachable(); |
| 352 | } | 341 | } |
| 353 | | 342 | |
| 354 | fn generateBreakpoint(codegen: *CodeGen, inst: *Inst.NoOp) !void { | 343 | fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !void { |
| 355 | // TODO: Store this function somewhere such that we dont have to add it again | 344 | // TODO: Store this function somewhere such that we dont have to add it again |
| 356 | const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false); | 345 | const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false); |
| 357 | const func = codegen.llvm_module.addFunction("llvm.debugtrap", fn_type); | 346 | const func = self.llvm_module.addFunction("llvm.debugtrap", fn_type); |
| 358 | // TODO: add assertion: LLVMGetIntrinsicID | 347 | // TODO: add assertion: LLVMGetIntrinsicID |
| 359 | _ = codegen.builder.buildCall(func, null, 0, ""); | 348 | _ = self.builder.buildCall(func, null, 0, ""); |
| 360 | } | 349 | } |
| 361 | | 350 | |
| 362 | /// If the llvm function does not exist, create it | 351 | /// If the llvm function does not exist, create it |
| 363 | fn resolveLLVMFunction(codegen: *CodeGen, func: *Module.Fn) !*const llvm.ValueRef { | 352 | fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Fn) !*const llvm.ValueRef { |
| 364 | // TODO: do we want to store this in our own datastructure? | 353 | // TODO: do we want to store this in our own datastructure? |
| 365 | if (codegen.llvm_module.getNamedFunction(func.owner_decl.name)) |llvm_fn| return llvm_fn; | 354 | if (self.llvm_module.getNamedFunction(func.owner_decl.name)) |llvm_fn| return llvm_fn; |
| 366 | | 355 | |
| 367 | const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty; | 356 | const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty; |
| 368 | const return_type = zig_fn_type.fnReturnType(); | 357 | const return_type = zig_fn_type.fnReturnType(); |
| 369 | | 358 | |
| 370 | const fn_param_len = zig_fn_type.fnParamLen(); | 359 | const fn_param_len = zig_fn_type.fnParamLen(); |
| 371 | | 360 | |
| 372 | const fn_param_types = try codegen.module.gpa.alloc(Type, fn_param_len); | 361 | const fn_param_types = try self.gpa.alloc(Type, fn_param_len); |
| 373 | defer codegen.module.gpa.free(fn_param_types); | 362 | defer self.gpa.free(fn_param_types); |
| 374 | zig_fn_type.fnParamTypes(fn_param_types); | 363 | zig_fn_type.fnParamTypes(fn_param_types); |
| 375 | | 364 | |
| 376 | const llvm_param = try codegen.module.gpa.alloc(*const llvm.TypeRef, fn_param_len); | 365 | const llvm_param = try self.gpa.alloc(*const llvm.TypeRef, fn_param_len); |
| 377 | defer codegen.module.gpa.free(llvm_param); | 366 | defer self.gpa.free(llvm_param); |
| 378 | | 367 | |
| 379 | for (fn_param_types) |fn_param, i| { | 368 | for (fn_param_types) |fn_param, i| { |
| 380 | llvm_param[i] = codegen.getLLVMType(fn_param); | 369 | llvm_param[i] = self.getLLVMType(fn_param); |
| 381 | } | 370 | } |
| 382 | | 371 | |
| 383 | const fn_type = llvm.TypeRef.functionType( | 372 | const fn_type = llvm.TypeRef.functionType( |
| 384 | codegen.getLLVMType(return_type), | 373 | self.getLLVMType(return_type), |
| 385 | if (fn_param_len == 0) null else llvm_param.ptr, | 374 | if (fn_param_len == 0) null else llvm_param.ptr, |
| 386 | @intCast(c_uint, fn_param_len), | 375 | @intCast(c_uint, fn_param_len), |
| 387 | false, | 376 | false, |
| 388 | ); | 377 | ); |
| 389 | const llvm_fn = codegen.llvm_module.addFunction(func.owner_decl.name, fn_type); | 378 | const llvm_fn = self.llvm_module.addFunction(func.owner_decl.name, fn_type); |
| 390 | | 379 | |
| 391 | if (return_type.zigTypeTag() == .NoReturn) { | 380 | if (return_type.zigTypeTag() == .NoReturn) { |
| 392 | llvm_fn.addFnAttr("noreturn"); | 381 | llvm_fn.addFnAttr("noreturn"); |
| ... | @@ -395,16 +384,23 @@ const CodeGen = struct { | ... | @@ -395,16 +384,23 @@ const CodeGen = struct { |
| 395 | return llvm_fn; | 384 | return llvm_fn; |
| 396 | } | 385 | } |
| 397 | | 386 | |
| 398 | fn getLLVMType(codegen: *CodeGen, t: Type) *const llvm.TypeRef { | 387 | fn getLLVMType(self: *LLVMIRModule, t: Type) *const llvm.TypeRef { |
| 399 | switch (t.zigTypeTag()) { | 388 | switch (t.zigTypeTag()) { |
| 400 | .Void => return llvm.voidType(), | 389 | .Void => return llvm.voidType(), |
| 401 | .NoReturn => return llvm.voidType(), | 390 | .NoReturn => return llvm.voidType(), |
| 402 | .Int => { | 391 | .Int => { |
| 403 | const info = t.intInfo(codegen.module.getTarget()); | 392 | const info = t.intInfo(self.module.getTarget()); |
| 404 | return llvm.intType(info.bits); | 393 | return llvm.intType(info.bits); |
| 405 | }, | 394 | }, |
| 406 | .Bool => return llvm.intType(1), | 395 | .Bool => return llvm.intType(1), |
| 407 | else => unreachable, | 396 | else => unreachable, |
| 408 | } | 397 | } |
| 409 | } | 398 | } |
| | 399 | |
| | 400 | pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| | 401 | @setCold(true); |
| | 402 | std.debug.assert(self.err_msg == null); |
| | 403 | self.err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args); |
| | 404 | return error.CodegenFail; |
| | 405 | } |
| 410 | }; | 406 | }; |