| ... | @@ -214,6 +214,10 @@ pub const Object = struct { | ... | @@ -214,6 +214,10 @@ pub const Object = struct { |
| 214 | /// Note that the values are not added until flushModule, when all errors in | 214 | /// Note that the values are not added until flushModule, when all errors in |
| 215 | /// the compilation are known. | 215 | /// the compilation are known. |
| 216 | error_name_table: ?*const llvm.Value, | 216 | error_name_table: ?*const llvm.Value, |
| | 217 | /// This map is usually very close to empty. It tracks only the cases when a |
| | 218 | /// second extern Decl could not be emitted with the correct name due to a |
| | 219 | /// name collision. |
| | 220 | extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void), |
| 217 | | 221 | |
| 218 | pub const TypeMap = std.HashMapUnmanaged( | 222 | pub const TypeMap = std.HashMapUnmanaged( |
| 219 | Type, | 223 | Type, |
| ... | @@ -376,6 +380,7 @@ pub const Object = struct { | ... | @@ -376,6 +380,7 @@ pub const Object = struct { |
| 376 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), | 380 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), |
| 377 | .di_type_map = .{}, | 381 | .di_type_map = .{}, |
| 378 | .error_name_table = null, | 382 | .error_name_table = null, |
| | 383 | .extern_collisions = .{}, |
| 379 | }; | 384 | }; |
| 380 | } | 385 | } |
| 381 | | 386 | |
| ... | @@ -392,6 +397,7 @@ pub const Object = struct { | ... | @@ -392,6 +397,7 @@ pub const Object = struct { |
| 392 | self.decl_map.deinit(gpa); | 397 | self.decl_map.deinit(gpa); |
| 393 | self.type_map.deinit(gpa); | 398 | self.type_map.deinit(gpa); |
| 394 | self.type_map_arena.deinit(); | 399 | self.type_map_arena.deinit(); |
| | 400 | self.extern_collisions.deinit(gpa); |
| 395 | self.* = undefined; | 401 | self.* = undefined; |
| 396 | } | 402 | } |
| 397 | | 403 | |
| ... | @@ -508,6 +514,22 @@ pub const Object = struct { | ... | @@ -508,6 +514,22 @@ pub const Object = struct { |
| 508 | fn resolveExportExternCollisions(object: *Object) !void { | 514 | fn resolveExportExternCollisions(object: *Object) !void { |
| 509 | const mod = object.module; | 515 | const mod = object.module; |
| 510 | | 516 | |
| | 517 | // This map has externs with incorrect symbol names. |
| | 518 | for (object.extern_collisions.keys()) |decl_index| { |
| | 519 | const entry = object.decl_map.getEntry(decl_index) orelse continue; |
| | 520 | const llvm_global = entry.value_ptr.*; |
| | 521 | // Same logic as below but for externs instead of exports. |
| | 522 | const decl = mod.declPtr(decl_index); |
| | 523 | const other_global = object.getLlvmGlobal(decl.name) orelse continue; |
| | 524 | if (other_global == llvm_global) continue; |
| | 525 | |
| | 526 | const new_global_ptr = other_global.constBitCast(llvm_global.typeOf()); |
| | 527 | llvm_global.replaceAllUsesWith(new_global_ptr); |
| | 528 | object.deleteLlvmGlobal(llvm_global); |
| | 529 | entry.value_ptr.* = new_global_ptr; |
| | 530 | } |
| | 531 | object.extern_collisions.clearRetainingCapacity(); |
| | 532 | |
| 511 | const export_keys = mod.decl_exports.keys(); | 533 | const export_keys = mod.decl_exports.keys(); |
| 512 | for (mod.decl_exports.values()) |export_list, i| { | 534 | for (mod.decl_exports.values()) |export_list, i| { |
| 513 | const decl_index = export_keys[i]; | 535 | const decl_index = export_keys[i]; |
| ... | @@ -997,6 +1019,15 @@ pub const Object = struct { | ... | @@ -997,6 +1019,15 @@ pub const Object = struct { |
| 997 | return null; | 1019 | return null; |
| 998 | } | 1020 | } |
| 999 | | 1021 | |
| | 1022 | /// TODO can this be done with simpler logic / different API binding? |
| | 1023 | fn deleteLlvmGlobal(o: Object, llvm_global: *const llvm.Value) void { |
| | 1024 | if (o.llvm_module.getNamedFunction(llvm_global.getValueName()) != null) { |
| | 1025 | llvm_global.deleteFunction(); |
| | 1026 | return; |
| | 1027 | } |
| | 1028 | return llvm_global.deleteGlobal(); |
| | 1029 | } |
| | 1030 | |
| 1000 | pub fn updateDeclExports( | 1031 | pub fn updateDeclExports( |
| 1001 | self: *Object, | 1032 | self: *Object, |
| 1002 | module: *Module, | 1033 | module: *Module, |
| ... | @@ -1009,6 +1040,12 @@ pub const Object = struct { | ... | @@ -1009,6 +1040,12 @@ pub const Object = struct { |
| 1009 | const decl = module.declPtr(decl_index); | 1040 | const decl = module.declPtr(decl_index); |
| 1010 | if (decl.isExtern()) { | 1041 | if (decl.isExtern()) { |
| 1011 | llvm_global.setValueName(decl.name); | 1042 | llvm_global.setValueName(decl.name); |
| | 1043 | if (self.getLlvmGlobal(decl.name)) |other_global| { |
| | 1044 | if (other_global != llvm_global) { |
| | 1045 | log.debug("updateDeclExports isExtern()=true setValueName({s}) conflict", .{decl.name}); |
| | 1046 | try self.extern_collisions.put(module.gpa, decl_index, {}); |
| | 1047 | } |
| | 1048 | } |
| 1012 | llvm_global.setUnnamedAddr(.False); | 1049 | llvm_global.setUnnamedAddr(.False); |
| 1013 | llvm_global.setLinkage(.External); | 1050 | llvm_global.setLinkage(.External); |
| 1014 | if (self.di_map.get(decl)) |di_node| { | 1051 | if (self.di_map.get(decl)) |di_node| { |
| ... | @@ -2143,11 +2180,8 @@ pub const DeclGen = struct { | ... | @@ -2143,11 +2180,8 @@ pub const DeclGen = struct { |
| 2143 | log.debug("gen: {s} type: {}, value: {}", .{ | 2180 | log.debug("gen: {s} type: {}, value: {}", .{ |
| 2144 | decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(), | 2181 | decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(), |
| 2145 | }); | 2182 | }); |
| 2146 | | 2183 | assert(decl.val.tag() != .function); |
| 2147 | if (decl.val.castTag(.function)) |func_payload| { | 2184 | if (decl.val.castTag(.extern_fn)) |extern_fn| { |
| 2148 | _ = func_payload; | | |
| 2149 | @panic("TODO llvm backend genDecl function pointer"); | | |
| 2150 | } else if (decl.val.castTag(.extern_fn)) |extern_fn| { | | |
| 2151 | _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl); | 2185 | _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl); |
| 2152 | } else { | 2186 | } else { |
| 2153 | const target = dg.module.getTarget(); | 2187 | const target = dg.module.getTarget(); |
| ... | @@ -2246,12 +2280,14 @@ pub const DeclGen = struct { | ... | @@ -2246,12 +2280,14 @@ pub const DeclGen = struct { |
| 2246 | if (!is_extern) { | 2280 | if (!is_extern) { |
| 2247 | llvm_fn.setLinkage(.Internal); | 2281 | llvm_fn.setLinkage(.Internal); |
| 2248 | llvm_fn.setUnnamedAddr(.True); | 2282 | llvm_fn.setUnnamedAddr(.True); |
| 2249 | } else if (dg.module.getTarget().isWasm()) { | 2283 | } else { |
| 2250 | dg.addFnAttrString(llvm_fn, "wasm-import-name", std.mem.sliceTo(decl.name, 0)); | 2284 | if (dg.module.getTarget().isWasm()) { |
| 2251 | if (decl.getExternFn().?.lib_name) |lib_name| { | 2285 | dg.addFnAttrString(llvm_fn, "wasm-import-name", std.mem.sliceTo(decl.name, 0)); |
| 2252 | const module_name = std.mem.sliceTo(lib_name, 0); | 2286 | if (decl.getExternFn().?.lib_name) |lib_name| { |
| 2253 | if (!std.mem.eql(u8, module_name, "c")) { | 2287 | const module_name = std.mem.sliceTo(lib_name, 0); |
| 2254 | dg.addFnAttrString(llvm_fn, "wasm-import-module", module_name); | 2288 | if (!std.mem.eql(u8, module_name, "c")) { |
| | 2289 | dg.addFnAttrString(llvm_fn, "wasm-import-module", module_name); |
| | 2290 | } |
| 2255 | } | 2291 | } |
| 2256 | } | 2292 | } |
| 2257 | } | 2293 | } |