| ... | @@ -550,17 +550,13 @@ pub const Object = struct { | ... | @@ -550,17 +550,13 @@ pub const Object = struct { |
| 550 | debug_anyerror_fwd_ref: Builder.Metadata.Optional, | 550 | debug_anyerror_fwd_ref: Builder.Metadata.Optional, |
| 551 | | 551 | |
| 552 | zcu: *Zcu, | 552 | zcu: *Zcu, |
| 553 | /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function, | 553 | /// Maps a `Nav` to the corresponding LLVM global. |
| 554 | /// but that has some downsides: | | |
| 555 | /// * we have to compute the fully qualified name every time we want to do the lookup | | |
| 556 | /// * for externally linked functions, the name is not fully qualified, but when | | |
| 557 | /// a Decl goes from exported to not exported and vice-versa, we would use the wrong | | |
| 558 | /// version of the name and incorrectly get function not found in the llvm module. | | |
| 559 | /// * it works for functions not all globals. | | |
| 560 | /// Therefore, this table keeps track of the mapping. | | |
| 561 | nav_map: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Builder.Global.Index), | 554 | nav_map: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Builder.Global.Index), |
| 562 | /// Same deal as `decl_map` but for anonymous declarations, which are always global constants. | 555 | /// Same as `nav_map` but for UAVs (which are always global constants). |
| 563 | uav_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Global.Index), | 556 | uav_map: std.AutoHashMapUnmanaged(struct { |
| | 557 | val: InternPool.Index, |
| | 558 | @"addrspace": std.builtin.AddressSpace, |
| | 559 | }, Builder.Variable.Index), |
| 564 | /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction. | 560 | /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction. |
| 565 | enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index), | 561 | enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index), |
| 566 | /// Serves the same purpose as `enum_tag_name_map` but for the `is_named_enum_value` instruction. | 562 | /// Serves the same purpose as `enum_tag_name_map` but for the `is_named_enum_value` instruction. |
| ... | @@ -717,13 +713,13 @@ pub const Object = struct { | ... | @@ -717,13 +713,13 @@ pub const Object = struct { |
| 717 | for (llvm_errors[1..], error_name_list) |*llvm_error, name| { | 713 | for (llvm_errors[1..], error_name_list) |*llvm_error, name| { |
| 718 | const name_string = try o.builder.stringNull(name.toSlice(ip)); | 714 | const name_string = try o.builder.stringNull(name.toSlice(ip)); |
| 719 | const name_init = try o.builder.stringConst(name_string); | 715 | const name_init = try o.builder.stringConst(name_string); |
| 720 | const name_variable_index = | 716 | const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); |
| 721 | try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); | | |
| 722 | try name_variable_index.setInitializer(name_init, &o.builder); | 717 | try name_variable_index.setInitializer(name_init, &o.builder); |
| 723 | name_variable_index.setLinkage(.private, &o.builder); | | |
| 724 | name_variable_index.setMutability(.constant, &o.builder); | 718 | name_variable_index.setMutability(.constant, &o.builder); |
| 725 | name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); | | |
| 726 | name_variable_index.setAlignment(comptime .fromByteUnits(1), &o.builder); | 719 | name_variable_index.setAlignment(comptime .fromByteUnits(1), &o.builder); |
| | 720 | const global_index = name_variable_index.ptrConst(&o.builder).global; |
| | 721 | global_index.setLinkage(.private, &o.builder); |
| | 722 | global_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 727 | | 723 | |
| 728 | llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{ | 724 | llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{ |
| 729 | name_variable_index.toConst(&o.builder), | 725 | name_variable_index.toConst(&o.builder), |
| ... | @@ -790,9 +786,9 @@ pub const Object = struct { | ... | @@ -790,9 +786,9 @@ pub const Object = struct { |
| 790 | array_llvm_ty, | 786 | array_llvm_ty, |
| 791 | .default, | 787 | .default, |
| 792 | ); | 788 | ); |
| 793 | compiler_used_variable.setLinkage(.appending, &o.builder); | | |
| 794 | compiler_used_variable.setSection(try o.builder.string("llvm.metadata"), &o.builder); | | |
| 795 | try compiler_used_variable.setInitializer(init_val, &o.builder); | 789 | try compiler_used_variable.setInitializer(init_val, &o.builder); |
| | 790 | compiler_used_variable.setSection(try o.builder.string("llvm.metadata"), &o.builder); |
| | 791 | compiler_used_variable.ptrConst(&o.builder).global.setLinkage(.appending, &o.builder); |
| 796 | } | 792 | } |
| 797 | | 793 | |
| 798 | if (!o.builder.strip) { | 794 | if (!o.builder.strip) { |
| ... | @@ -1140,6 +1136,7 @@ pub const Object = struct { | ... | @@ -1140,6 +1136,7 @@ pub const Object = struct { |
| 1140 | ) Zcu.CodegenFailError!void { | 1136 | ) Zcu.CodegenFailError!void { |
| 1141 | const zcu = o.zcu; | 1137 | const zcu = o.zcu; |
| 1142 | const comp = zcu.comp; | 1138 | const comp = zcu.comp; |
| | 1139 | const gpa = comp.gpa; |
| 1143 | const ip = &zcu.intern_pool; | 1140 | const ip = &zcu.intern_pool; |
| 1144 | const func = zcu.funcInfo(func_index); | 1141 | const func = zcu.funcInfo(func_index); |
| 1145 | const nav = ip.getNav(func.owner_nav); | 1142 | const nav = ip.getNav(func.owner_nav); |
| ... | @@ -1149,9 +1146,42 @@ pub const Object = struct { | ... | @@ -1149,9 +1146,42 @@ pub const Object = struct { |
| 1149 | const fn_info = zcu.typeToFunc(fn_ty).?; | 1146 | const fn_info = zcu.typeToFunc(fn_ty).?; |
| 1150 | const target = &owner_mod.resolved_target.result; | 1147 | const target = &owner_mod.resolved_target.result; |
| 1151 | | 1148 | |
| 1152 | const function_index = try o.resolveLlvmFunction(func.owner_nav); | 1149 | const gop = try o.nav_map.getOrPut(gpa, func.owner_nav); |
| | 1150 | if (!gop.found_existing) { |
| | 1151 | errdefer assert(o.nav_map.remove(func.owner_nav)); |
| | 1152 | // First time lowering this NAV! Create a fresh global. |
| | 1153 | const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip)); |
| | 1154 | gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{ |
| | 1155 | .type = .void, // placeholder; populated below |
| | 1156 | .kind = .{ .alias = .none }, // placeholder; populated below |
| | 1157 | }); |
| | 1158 | } |
| | 1159 | const llvm_global = gop.value_ptr.*; |
| | 1160 | |
| | 1161 | const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) { |
| | 1162 | .function => |function| function, // re-use existing `Builder.Function` |
| | 1163 | .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder), |
| | 1164 | }; |
| | 1165 | { |
| | 1166 | const global = llvm_function.ptrConst(&o.builder).global.ptr(&o.builder); |
| | 1167 | global.type = try o.lowerType(fn_ty); |
| | 1168 | global.addr_space = toLlvmAddressSpace(nav.resolved.?.@"addrspace", target); |
| | 1169 | global.linkage = if (o.builder.strip) .private else .internal; |
| | 1170 | global.visibility = .default; |
| | 1171 | global.dll_storage_class = .default; |
| | 1172 | global.unnamed_addr = .unnamed_addr; |
| | 1173 | } |
| | 1174 | llvm_function.setAlignment(switch (nav.resolved.?.@"align") { |
| | 1175 | .none => fn_ty.abiAlignment(zcu).toLlvm(), |
| | 1176 | else => |a| a.toLlvm(), |
| | 1177 | }, &o.builder); |
| | 1178 | llvm_function.setSection(s: { |
| | 1179 | const section = nav.resolved.?.@"linksection".toSlice(ip) orelse break :s .none; |
| | 1180 | break :s try o.builder.string(section); |
| | 1181 | }, &o.builder); |
| | 1182 | try o.addLlvmFunctionAttributes(pt, func.owner_nav, llvm_function); |
| 1153 | | 1183 | |
| 1154 | var attributes = try function_index.ptrConst(&o.builder).attributes.toWip(&o.builder); | 1184 | var attributes = try llvm_function.ptrConst(&o.builder).attributes.toWip(&o.builder); |
| 1155 | defer attributes.deinit(&o.builder); | 1185 | defer attributes.deinit(&o.builder); |
| 1156 | | 1186 | |
| 1157 | const func_analysis = func.analysisUnordered(ip); | 1187 | const func_analysis = func.analysisUnordered(ip); |
| ... | @@ -1221,47 +1251,41 @@ pub const Object = struct { | ... | @@ -1221,47 +1251,41 @@ pub const Object = struct { |
| 1221 | } }, &o.builder); | 1251 | } }, &o.builder); |
| 1222 | } | 1252 | } |
| 1223 | | 1253 | |
| 1224 | if (nav.resolved.?.@"linksection".toSlice(ip)) |section| | | |
| 1225 | function_index.setSection(try o.builder.string(section), &o.builder); | | |
| 1226 | | | |
| 1227 | var deinit_wip = true; | 1254 | var deinit_wip = true; |
| 1228 | var wip = try Builder.WipFunction.init(&o.builder, .{ | 1255 | var wip = try Builder.WipFunction.init(&o.builder, .{ |
| 1229 | .function = function_index, | 1256 | .function = llvm_function, |
| 1230 | .strip = owner_mod.strip, | 1257 | .strip = owner_mod.strip, |
| 1231 | }); | 1258 | }); |
| 1232 | defer if (deinit_wip) wip.deinit(); | 1259 | defer if (deinit_wip) wip.deinit(); |
| 1233 | wip.cursor = .{ .block = try wip.block(0, "Entry") }; | 1260 | wip.cursor = .{ .block = try wip.block(0, "Entry") }; |
| 1234 | | 1261 | |
| 1235 | var llvm_arg_i: u32 = 0; | | |
| 1236 | | | |
| 1237 | const ret_ptr: Builder.Value = if (firstParamSRet(fn_info, zcu, target)) param: { | | |
| 1238 | const param = wip.arg(llvm_arg_i); | | |
| 1239 | llvm_arg_i += 1; | | |
| 1240 | break :param param; | | |
| 1241 | } else .none; | | |
| 1242 | | | |
| 1243 | if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { | 1262 | if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { |
| 1244 | .signed => try attributes.addRetAttr(.signext, &o.builder), | 1263 | .signed => try attributes.addRetAttr(.signext, &o.builder), |
| 1245 | .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), | 1264 | .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), |
| 1246 | }; | 1265 | }; |
| 1247 | | 1266 | |
| 1248 | const err_return_tracing = fn_info.cc == .auto and comp.config.any_error_tracing; | | |
| 1249 | | | |
| 1250 | const err_ret_trace: Builder.Value = if (err_return_tracing) param: { | | |
| 1251 | const param = wip.arg(llvm_arg_i); | | |
| 1252 | llvm_arg_i += 1; | | |
| 1253 | break :param param; | | |
| 1254 | } else .none; | | |
| 1255 | | | |
| 1256 | // This is the list of args we will use that correspond directly to the AIR arg | 1267 | // This is the list of args we will use that correspond directly to the AIR arg |
| 1257 | // instructions. Depending on the calling convention, this list is not necessarily | 1268 | // instructions. Depending on the calling convention, this list is not necessarily |
| 1258 | // a bijection with the actual LLVM parameters of the function. | 1269 | // a bijection with the actual LLVM parameters of the function. |
| 1259 | const gpa = o.gpa; | | |
| 1260 | var args: std.ArrayList(Builder.Value) = .empty; | 1270 | var args: std.ArrayList(Builder.Value) = .empty; |
| 1261 | defer args.deinit(gpa); | 1271 | defer args.deinit(gpa); |
| 1262 | | 1272 | |
| 1263 | { | 1273 | const ret_ptr: Builder.Value, const err_ret_trace: Builder.Value = implicit_args: { |
| 1264 | var it = iterateParamTypes(o, fn_info); | 1274 | var it = iterateParamTypes(o, fn_info); |
| | 1275 | |
| | 1276 | const ret_ptr: Builder.Value = if (firstParamSRet(fn_info, zcu, target)) param: { |
| | 1277 | const param = wip.arg(it.llvm_index); |
| | 1278 | it.llvm_index += 1; |
| | 1279 | break :param param; |
| | 1280 | } else .none; |
| | 1281 | |
| | 1282 | const err_return_tracing = fn_info.cc == .auto and comp.config.any_error_tracing; |
| | 1283 | const err_ret_trace: Builder.Value = if (err_return_tracing) param: { |
| | 1284 | const param = wip.arg(it.llvm_index); |
| | 1285 | it.llvm_index += 1; |
| | 1286 | break :param param; |
| | 1287 | } else .none; |
| | 1288 | |
| 1265 | while (try it.next()) |lowering| { | 1289 | while (try it.next()) |lowering| { |
| 1266 | try args.ensureUnusedCapacity(gpa, 1); | 1290 | try args.ensureUnusedCapacity(gpa, 1); |
| 1267 | | 1291 | |
| ... | @@ -1271,7 +1295,7 @@ pub const Object = struct { | ... | @@ -1271,7 +1295,7 @@ pub const Object = struct { |
| 1271 | assert(!it.byval_attr); | 1295 | assert(!it.byval_attr); |
| 1272 | const param_index = it.zig_index - 1; | 1296 | const param_index = it.zig_index - 1; |
| 1273 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]); | 1297 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]); |
| 1274 | const param = wip.arg(llvm_arg_i); | 1298 | const param = wip.arg(it.llvm_index - 1); |
| 1275 | | 1299 | |
| 1276 | if (isByRef(param_ty, zcu)) { | 1300 | if (isByRef(param_ty, zcu)) { |
| 1277 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); | 1301 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| ... | @@ -1281,146 +1305,116 @@ pub const Object = struct { | ... | @@ -1281,146 +1305,116 @@ pub const Object = struct { |
| 1281 | args.appendAssumeCapacity(arg_ptr); | 1305 | args.appendAssumeCapacity(arg_ptr); |
| 1282 | } else { | 1306 | } else { |
| 1283 | args.appendAssumeCapacity(param); | 1307 | args.appendAssumeCapacity(param); |
| 1284 | | | |
| 1285 | try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, llvm_arg_i); | | |
| 1286 | } | 1308 | } |
| 1287 | llvm_arg_i += 1; | | |
| 1288 | }, | 1309 | }, |
| 1289 | .byref => { | 1310 | .byref => { |
| 1290 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); | 1311 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1291 | const param_llvm_ty = try o.lowerType(param_ty); | 1312 | const param = wip.arg(it.llvm_index - 1); |
| 1292 | const param = wip.arg(llvm_arg_i); | | |
| 1293 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); | | |
| 1294 | | | |
| 1295 | try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty); | | |
| 1296 | llvm_arg_i += 1; | | |
| 1297 | | 1313 | |
| 1298 | if (isByRef(param_ty, zcu)) { | 1314 | if (isByRef(param_ty, zcu)) { |
| 1299 | args.appendAssumeCapacity(param); | 1315 | args.appendAssumeCapacity(param); |
| 1300 | } else { | 1316 | } else { |
| | 1317 | const param_llvm_ty = try o.lowerType(param_ty); |
| | 1318 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1301 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); | 1319 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); |
| 1302 | } | 1320 | } |
| 1303 | }, | 1321 | }, |
| 1304 | .byref_mut => { | 1322 | .byref_mut => { |
| 1305 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); | 1323 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1306 | const param_llvm_ty = try o.lowerType(param_ty); | 1324 | const param = wip.arg(it.llvm_index - 1); |
| 1307 | const param = wip.arg(llvm_arg_i); | | |
| 1308 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); | | |
| 1309 | | | |
| 1310 | try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder); | | |
| 1311 | llvm_arg_i += 1; | | |
| 1312 | | 1325 | |
| 1313 | if (isByRef(param_ty, zcu)) { | 1326 | if (isByRef(param_ty, zcu)) { |
| 1314 | args.appendAssumeCapacity(param); | 1327 | args.appendAssumeCapacity(param); |
| 1315 | } else { | 1328 | } else { |
| | 1329 | const param_llvm_ty = try o.lowerType(param_ty); |
| | 1330 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1316 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); | 1331 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); |
| 1317 | } | 1332 | } |
| 1318 | }, | 1333 | }, |
| 1319 | .abi_sized_int => { | 1334 | .abi_sized_int => { |
| 1320 | assert(!it.byval_attr); | 1335 | assert(!it.byval_attr); |
| 1321 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); | 1336 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1322 | const param = wip.arg(llvm_arg_i); | 1337 | const param = wip.arg(it.llvm_index - 1); |
| 1323 | llvm_arg_i += 1; | | |
| 1324 | | 1338 | |
| 1325 | const param_llvm_ty = try o.lowerType(param_ty); | 1339 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1326 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); | 1340 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1327 | const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target); | 1341 | const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target); |
| 1328 | _ = try wip.store(.normal, param, arg_ptr, alignment); | 1342 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1329 | | 1343 | |
| 1330 | args.appendAssumeCapacity(if (isByRef(param_ty, zcu)) | 1344 | if (isByRef(param_ty, zcu)) { |
| 1331 | arg_ptr | 1345 | args.appendAssumeCapacity(arg_ptr); |
| 1332 | else | 1346 | } else { |
| 1333 | try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); | 1347 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); |
| | 1348 | } |
| 1334 | }, | 1349 | }, |
| 1335 | .slice => { | 1350 | .slice => { |
| 1336 | assert(!it.byval_attr); | 1351 | assert(!it.byval_attr); |
| 1337 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); | 1352 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1338 | const ptr_info = param_ty.ptrInfo(zcu); | 1353 | assert(!isByRef(param_ty, zcu)); |
| 1339 | | 1354 | const slice_val = try wip.buildAggregate( |
| 1340 | if (std.math.cast(u5, it.zig_index - 1)) |i| { | 1355 | try o.lowerType(param_ty), |
| 1341 | if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) { | 1356 | &.{ wip.arg(it.llvm_index - 2), wip.arg(it.llvm_index - 1) }, |
| 1342 | try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder); | 1357 | "", |
| 1343 | } | | |
| 1344 | } | | |
| 1345 | if (param_ty.zigTypeTag(zcu) != .optional and | | |
| 1346 | !ptr_info.flags.is_allowzero and | | |
| 1347 | ptr_info.flags.address_space == .generic) | | |
| 1348 | { | | |
| 1349 | try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); | | |
| 1350 | } | | |
| 1351 | if (ptr_info.flags.is_const) { | | |
| 1352 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); | | |
| 1353 | } | | |
| 1354 | const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) { | | |
| 1355 | else => |a| .wrap(a.toLlvm()), | | |
| 1356 | .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)), | | |
| 1357 | }; | | |
| 1358 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); | | |
| 1359 | const ptr_param = wip.arg(llvm_arg_i); | | |
| 1360 | llvm_arg_i += 1; | | |
| 1361 | const len_param = wip.arg(llvm_arg_i); | | |
| 1362 | llvm_arg_i += 1; | | |
| 1363 | | | |
| 1364 | const slice_llvm_ty = try o.lowerType(param_ty); | | |
| 1365 | args.appendAssumeCapacity( | | |
| 1366 | try wip.buildAggregate(slice_llvm_ty, &.{ ptr_param, len_param }, ""), | | |
| 1367 | ); | 1358 | ); |
| | 1359 | args.appendAssumeCapacity(slice_val); |
| 1368 | }, | 1360 | }, |
| 1369 | .multiple_llvm_types => { | 1361 | .multiple_llvm_types => { |
| 1370 | assert(!it.byval_attr); | 1362 | assert(!it.byval_attr); |
| 1371 | const field_types = it.types_buffer[0..it.types_len]; | 1363 | const field_types = it.types_buffer[0..it.types_len]; |
| 1372 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); | 1364 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1373 | const param_llvm_ty = try o.lowerType(param_ty); | 1365 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1374 | const param_alignment = param_ty.abiAlignment(zcu).toLlvm(); | 1366 | const param_alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1375 | const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, param_alignment, target); | 1367 | const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, param_alignment, target); |
| 1376 | const llvm_ty = try o.builder.structType(.normal, field_types); | 1368 | const llvm_ty = try o.builder.structType(.normal, field_types); |
| 1377 | for (0..field_types.len) |field_i| { | 1369 | const llvm_args_start = it.llvm_index - field_types.len; |
| 1378 | const param = wip.arg(llvm_arg_i); | 1370 | for (0..field_types.len, llvm_args_start..) |field_i, llvm_arg_index| { |
| 1379 | llvm_arg_i += 1; | 1371 | const param = wip.arg(@intCast(llvm_arg_index)); |
| 1380 | const field_ptr = try wip.gepStruct(llvm_ty, arg_ptr, field_i, ""); | 1372 | const field_ptr = try wip.gepStruct(llvm_ty, arg_ptr, field_i, ""); |
| 1381 | const alignment = Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); | 1373 | const alignment: Builder.Alignment = .fromByteUnits(@divExact(target.ptrBitWidth(), 8)); |
| 1382 | _ = try wip.store(.normal, param, field_ptr, alignment); | 1374 | _ = try wip.store(.normal, param, field_ptr, alignment); |
| 1383 | } | 1375 | } |
| 1384 | | 1376 | |
| 1385 | const is_by_ref = isByRef(param_ty, zcu); | 1377 | if (isByRef(param_ty, zcu)) { |
| 1386 | args.appendAssumeCapacity(if (is_by_ref) | 1378 | args.appendAssumeCapacity(arg_ptr); |
| 1387 | arg_ptr | 1379 | } else { |
| 1388 | else | 1380 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, "")); |
| 1389 | try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, "")); | 1381 | } |
| 1390 | }, | 1382 | }, |
| 1391 | .float_array => { | 1383 | .float_array => { |
| 1392 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); | 1384 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1393 | const param_llvm_ty = try o.lowerType(param_ty); | 1385 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1394 | const param = wip.arg(llvm_arg_i); | 1386 | const param = wip.arg(it.llvm_index - 1); |
| 1395 | llvm_arg_i += 1; | | |
| 1396 | | 1387 | |
| 1397 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); | 1388 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1398 | const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target); | 1389 | const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target); |
| 1399 | _ = try wip.store(.normal, param, arg_ptr, alignment); | 1390 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1400 | | 1391 | |
| 1401 | args.appendAssumeCapacity(if (isByRef(param_ty, zcu)) | 1392 | if (isByRef(param_ty, zcu)) { |
| 1402 | arg_ptr | 1393 | args.appendAssumeCapacity(arg_ptr); |
| 1403 | else | 1394 | } else { |
| 1404 | try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); | 1395 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); |
| | 1396 | } |
| 1405 | }, | 1397 | }, |
| 1406 | .i32_array, .i64_array => { | 1398 | .i32_array, .i64_array => { |
| 1407 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); | 1399 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1408 | const param_llvm_ty = try o.lowerType(param_ty); | 1400 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1409 | const param = wip.arg(llvm_arg_i); | 1401 | const param = wip.arg(it.llvm_index - 1); |
| 1410 | llvm_arg_i += 1; | | |
| 1411 | | 1402 | |
| 1412 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); | 1403 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1413 | const arg_ptr = try buildAllocaInner(&wip, param.typeOfWip(&wip), alignment, target); | 1404 | const arg_ptr = try buildAllocaInner(&wip, param.typeOfWip(&wip), alignment, target); |
| 1414 | _ = try wip.store(.normal, param, arg_ptr, alignment); | 1405 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1415 | | 1406 | |
| 1416 | args.appendAssumeCapacity(if (isByRef(param_ty, zcu)) | 1407 | if (isByRef(param_ty, zcu)) { |
| 1417 | arg_ptr | 1408 | args.appendAssumeCapacity(arg_ptr); |
| 1418 | else | 1409 | } else { |
| 1419 | try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); | 1410 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); |
| | 1411 | } |
| 1420 | }, | 1412 | }, |
| 1421 | } | 1413 | } |
| 1422 | } | 1414 | } |
| 1423 | } | 1415 | |
| | 1416 | break :implicit_args .{ ret_ptr, err_ret_trace }; |
| | 1417 | }; |
| 1424 | | 1418 | |
| 1425 | const file, const subprogram = if (!wip.strip) debug_info: { | 1419 | const file, const subprogram = if (!wip.strip) debug_info: { |
| 1426 | const file = try o.getDebugFile(file_scope); | 1420 | const file = try o.getDebugFile(file_scope); |
| ... | @@ -1432,7 +1426,7 @@ pub const Object = struct { | ... | @@ -1432,7 +1426,7 @@ pub const Object = struct { |
| 1432 | const subprogram = try o.builder.debugSubprogram( | 1426 | const subprogram = try o.builder.debugSubprogram( |
| 1433 | file, | 1427 | file, |
| 1434 | try o.builder.metadataString(nav.name.toSlice(ip)), | 1428 | try o.builder.metadataString(nav.name.toSlice(ip)), |
| 1435 | try o.builder.metadataStringFromStrtabString(function_index.name(&o.builder)), | 1429 | try o.builder.metadataString(nav.fqn.toSlice(ip)), |
| 1436 | line_number, | 1430 | line_number, |
| 1437 | line_number + func.lbrace_line, | 1431 | line_number + func.lbrace_line, |
| 1438 | debug_decl_type, | 1432 | debug_decl_type, |
| ... | @@ -1449,7 +1443,7 @@ pub const Object = struct { | ... | @@ -1449,7 +1443,7 @@ pub const Object = struct { |
| 1449 | }, | 1443 | }, |
| 1450 | o.debug_compile_unit.unwrap().?, | 1444 | o.debug_compile_unit.unwrap().?, |
| 1451 | ); | 1445 | ); |
| 1452 | function_index.setSubprogram(subprogram, &o.builder); | 1446 | llvm_function.setSubprogram(subprogram, &o.builder); |
| 1453 | break :debug_info .{ file, subprogram }; | 1447 | break :debug_info .{ file, subprogram }; |
| 1454 | } else .{undefined} ** 2; | 1448 | } else .{undefined} ** 2; |
| 1455 | | 1449 | |
| ... | @@ -1466,7 +1460,7 @@ pub const Object = struct { | ... | @@ -1466,7 +1460,7 @@ pub const Object = struct { |
| 1466 | const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len}); | 1460 | const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len}); |
| 1467 | const counters_variable = try o.builder.addVariable(anon_name, .void, .default); | 1461 | const counters_variable = try o.builder.addVariable(anon_name, .void, .default); |
| 1468 | try o.used.append(gpa, counters_variable.toConst(&o.builder)); | 1462 | try o.used.append(gpa, counters_variable.toConst(&o.builder)); |
| 1469 | counters_variable.setLinkage(.private, &o.builder); | 1463 | counters_variable.ptrConst(&o.builder).global.setLinkage(.private, &o.builder); |
| 1470 | counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); | 1464 | counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); |
| 1471 | | 1465 | |
| 1472 | if (target.ofmt == .macho) { | 1466 | if (target.ofmt == .macho) { |
| ... | @@ -1524,7 +1518,7 @@ pub const Object = struct { | ... | @@ -1524,7 +1518,7 @@ pub const Object = struct { |
| 1524 | _ = try attributes.removeFnAttr(.null_pointer_is_valid); | 1518 | _ = try attributes.removeFnAttr(.null_pointer_is_valid); |
| 1525 | } | 1519 | } |
| 1526 | | 1520 | |
| 1527 | function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); | 1521 | llvm_function.setAttributes(try attributes.finish(&o.builder), &o.builder); |
| 1528 | | 1522 | |
| 1529 | if (fg.fuzz) |*f| { | 1523 | if (fg.fuzz) |*f| { |
| 1530 | { | 1524 | { |
| ... | @@ -1539,158 +1533,162 @@ pub const Object = struct { | ... | @@ -1539,158 +1533,162 @@ pub const Object = struct { |
| 1539 | // Due to error "members of llvm.compiler.used must be named", this global needs a name. | 1533 | // Due to error "members of llvm.compiler.used must be named", this global needs a name. |
| 1540 | const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len}); | 1534 | const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len}); |
| 1541 | const pcs_variable = try o.builder.addVariable(anon_name, array_llvm_ty, .default); | 1535 | const pcs_variable = try o.builder.addVariable(anon_name, array_llvm_ty, .default); |
| 1542 | try o.used.append(gpa, pcs_variable.toConst(&o.builder)); | 1536 | try pcs_variable.setInitializer(init_val, &o.builder); |
| 1543 | pcs_variable.setLinkage(.private, &o.builder); | | |
| 1544 | pcs_variable.setMutability(.constant, &o.builder); | 1537 | pcs_variable.setMutability(.constant, &o.builder); |
| | 1538 | pcs_variable.setSection(switch (target.ofmt) { |
| | 1539 | .macho => try o.builder.string("__DATA,__sancov_pcs1"), |
| | 1540 | else => try o.builder.string("__sancov_pcs1"), |
| | 1541 | }, &o.builder); |
| 1545 | pcs_variable.setAlignment(Type.usize.abiAlignment(zcu).toLlvm(), &o.builder); | 1542 | pcs_variable.setAlignment(Type.usize.abiAlignment(zcu).toLlvm(), &o.builder); |
| 1546 | if (target.ofmt == .macho) { | 1543 | const pcs_global = pcs_variable.ptrConst(&o.builder).global; |
| 1547 | pcs_variable.setSection(try o.builder.string("__DATA,__sancov_pcs1"), &o.builder); | 1544 | pcs_global.setLinkage(.private, &o.builder); |
| 1548 | } else { | 1545 | try o.used.append(gpa, pcs_global.toConst()); |
| 1549 | pcs_variable.setSection(try o.builder.string("__sancov_pcs1"), &o.builder); | | |
| 1550 | } | | |
| 1551 | try pcs_variable.setInitializer(init_val, &o.builder); | | |
| 1552 | } | 1546 | } |
| 1553 | | 1547 | |
| 1554 | try fg.wip.finish(); | 1548 | try fg.wip.finish(); |
| 1555 | try o.flushTypePool(pt); | 1549 | try o.flushTypePool(pt); |
| 1556 | } | 1550 | } |
| 1557 | | 1551 | |
| 1558 | pub fn updateNav(o: *Object, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | 1552 | pub fn updateNav(o: *Object, pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) !void { |
| 1559 | const zcu = o.zcu; | 1553 | const zcu = o.zcu; |
| 1560 | const ip = &zcu.intern_pool; | 1554 | const ip = &zcu.intern_pool; |
| | 1555 | const comp = zcu.comp; |
| | 1556 | const gpa = comp.gpa; |
| 1561 | | 1557 | |
| 1562 | const nav = ip.getNav(nav_index); | 1558 | const nav = ip.getNav(nav_id); |
| 1563 | const resolved = nav.resolved.?; | 1559 | const resolved = nav.resolved.?; |
| 1564 | | 1560 | |
| 1565 | const lib_name, const linkage, const visibility: Builder.Visibility, const is_dll_import, const init_val, const owner_nav = switch (ip.indexToKey(resolved.value)) { | 1561 | const opt_extern: ?InternPool.Key.Extern = switch (ip.indexToKey(resolved.value)) { |
| 1566 | else => .{ .none, .internal, .default, false, resolved.value, nav_index }, | 1562 | .@"extern" => |@"extern"| @"extern", |
| 1567 | .@"extern" => |e| .{ e.lib_name, e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import, .none, e.owner_nav }, | 1563 | else => null, |
| | 1564 | }; |
| | 1565 | const nav_ty: Type = .fromInterned(resolved.type); |
| | 1566 | const llvm_ty: Builder.Type = if (opt_extern != null) ty: { |
| | 1567 | // We *must* lower this declaration no matter what. If it has a type we can't actually |
| | 1568 | // represent (because it doesn't have runtime bits), we instead lower as the zero-size |
| | 1569 | // type `[0 x i8]`. I don't think the type on an extern declaration actually does much |
| | 1570 | // anyway. |
| | 1571 | if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) break :ty try o.lowerType(nav_ty); |
| | 1572 | break :ty try o.builder.arrayType(0, .i8); |
| | 1573 | } else if (nav_ty.hasRuntimeBits(zcu)) ty: { |
| | 1574 | break :ty try o.lowerType(nav_ty); |
| | 1575 | } else { |
| | 1576 | // This is a non-extern zero-bit `Nav`---we're not interested in it. |
| | 1577 | // TODO: we might need to rethink this a little under incremental compilation. If a |
| | 1578 | // declaration becomes zero-bit, we can't just leave its old value there, because it |
| | 1579 | // might now be ill-formed. |
| | 1580 | return; |
| 1568 | }; | 1581 | }; |
| 1569 | const ty: Type = .fromInterned(nav.resolved.?.type); | | |
| 1570 | | 1582 | |
| 1571 | if (linkage != .internal and ip.isFunctionType(ty.toIntern())) { | 1583 | const gop = try o.nav_map.getOrPut(gpa, nav_id); |
| 1572 | const function_index = try o.resolveLlvmFunction(owner_nav); | 1584 | if (!gop.found_existing) { |
| 1573 | // Add parameter attributes which weren't set by `resolveLlvmFunction` | 1585 | errdefer assert(o.nav_map.remove(nav_id)); |
| 1574 | const fn_info = zcu.typeToFunc(ty).?; | 1586 | // First time lowering this NAV! Create a fresh global. |
| 1575 | var attributes = try function_index.ptrConst(&o.builder).attributes.toWip(&o.builder); | 1587 | const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip)); |
| 1576 | defer attributes.deinit(&o.builder); | 1588 | gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{ |
| 1577 | var it = iterateParamTypes(o, fn_info); | 1589 | .type = .void, // placeholder; populated below |
| 1578 | if (firstParamSRet(fn_info, zcu, zcu.getTarget())) it.llvm_index += 1; | 1590 | .kind = .{ .alias = .none }, // placeholder; populated below |
| 1579 | if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) it.llvm_index += 1; | 1591 | }); |
| 1580 | while (try it.next()) |lowering| switch (lowering) { | 1592 | } |
| 1581 | .byval => { | 1593 | const llvm_global = gop.value_ptr.*; |
| 1582 | const param_index = it.zig_index - 1; | 1594 | |
| 1583 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]); | 1595 | llvm_global.ptr(&o.builder).type = llvm_ty; |
| 1584 | if (!isByRef(param_ty, zcu)) { | 1596 | llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(resolved.@"addrspace", zcu.getTarget()); |
| 1585 | try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1); | 1597 | |
| | 1598 | if (opt_extern) |@"extern"| { |
| | 1599 | const name = name: { |
| | 1600 | const name_slice = nav.name.toSlice(ip); |
| | 1601 | if (zcu.getTarget().cpu.arch.isWasm() and nav_ty.zigTypeTag(zcu) == .@"fn") { |
| | 1602 | if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| { |
| | 1603 | if (!std.mem.eql(u8, lib_name_slice, "c")) { |
| | 1604 | break :name try o.builder.strtabStringFmt("{s}|{s}", .{ name_slice, lib_name_slice }); |
| | 1605 | } |
| 1586 | } | 1606 | } |
| 1587 | }, | 1607 | } |
| 1588 | .byref => { | 1608 | break :name try o.builder.strtabString(name_slice); |
| 1589 | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); | 1609 | }; |
| 1590 | const param_llvm_ty = try o.lowerType(param_ty); | 1610 | if (o.builder.getGlobal(name)) |other_global| { |
| 1591 | const alignment = param_ty.abiAlignment(zcu); | 1611 | if (other_global != llvm_global) { |
| 1592 | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty); | 1612 | // Another global already has this name; just use it in place of this global. |
| 1593 | }, | 1613 | try llvm_global.replace(other_global, &o.builder); |
| 1594 | .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), | 1614 | return; |
| 1595 | // No attributes needed for these. | 1615 | } |
| 1596 | .no_bits, | 1616 | } |
| 1597 | .abi_sized_int, | 1617 | try llvm_global.rename(name, &o.builder); |
| 1598 | .multiple_llvm_types, | 1618 | llvm_global.ptr(&o.builder).unnamed_addr = .default; |
| 1599 | .float_array, | 1619 | llvm_global.ptr(&o.builder).dll_storage_class = switch (@"extern".is_dll_import) { |
| 1600 | .i32_array, | 1620 | true => .dllimport, |
| 1601 | .i64_array, | 1621 | false => .default, |
| 1602 | => continue, | 1622 | }; |
| 1603 | | 1623 | llvm_global.ptr(&o.builder).linkage = switch (@"extern".linkage) { |
| 1604 | .slice => unreachable, // extern functions do not support slice types. | 1624 | .internal => if (o.builder.strip) .private else .internal, |
| | 1625 | .strong => .external, |
| | 1626 | .weak => .extern_weak, |
| | 1627 | .link_once => unreachable, |
| 1605 | }; | 1628 | }; |
| 1606 | function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); | 1629 | llvm_global.ptr(&o.builder).visibility = .fromSymbolVisibility(@"extern".visibility); |
| 1607 | } else { | 1630 | } else { |
| 1608 | const variable_index = try o.resolveGlobalNav(nav_index); | 1631 | llvm_global.ptr(&o.builder).linkage = if (o.builder.strip) .private else .internal; |
| 1609 | variable_index.setAlignment(zcu.navAlignment(nav_index).toLlvm(), &o.builder); | 1632 | llvm_global.ptr(&o.builder).visibility = .default; |
| 1610 | if (resolved.@"linksection".toSlice(ip)) |section| | 1633 | llvm_global.ptr(&o.builder).dll_storage_class = .default; |
| 1611 | variable_index.setSection(try o.builder.string(section), &o.builder); | 1634 | llvm_global.ptr(&o.builder).unnamed_addr = .unnamed_addr; |
| 1612 | if (resolved.@"const") variable_index.setMutability(.constant, &o.builder); | 1635 | } |
| 1613 | try variable_index.setInitializer(switch (init_val) { | 1636 | |
| 1614 | .none => .no_init, | 1637 | const llvm_align = switch (resolved.@"align") { |
| 1615 | else => try o.lowerValue(init_val), | 1638 | .none => nav_ty.abiAlignment(zcu).toLlvm(), |
| 1616 | }, &o.builder); | 1639 | else => |a| a.toLlvm(), |
| 1617 | variable_index.setVisibility(visibility, &o.builder); | 1640 | }; |
| | 1641 | const llvm_section: Builder.String = if (resolved.@"linksection".toSlice(ip)) |section| s: { |
| | 1642 | break :s try o.builder.string(section); |
| | 1643 | } else .none; |
| 1618 | | 1644 | |
| 1619 | const file_scope = zcu.navFileScopeIndex(nav_index); | 1645 | // Actual function bodies with AIR go through `updateFunc` instead, so the only functions we |
| | 1646 | // can see are extern functions or other comptime function body values (e.g. undefined). Of |
| | 1647 | // these, only extern functions need to be lowered to LLVM functions. |
| | 1648 | if (opt_extern != null and nav_ty.zigTypeTag(zcu) == .@"fn" and nav_ty.fnHasRuntimeBits(zcu)) { |
| | 1649 | const llvm_function: Builder.Function.Index = switch (llvm_global.ptrConst(&o.builder).kind) { |
| | 1650 | .function => |function| function, // re-use existing `Builder.Function` |
| | 1651 | .replaced, .alias, .variable => try llvm_global.toNewFunction(&o.builder), |
| | 1652 | }; |
| | 1653 | llvm_function.setAlignment(llvm_align, &o.builder); |
| | 1654 | llvm_function.setSection(llvm_section, &o.builder); |
| | 1655 | try o.addLlvmFunctionAttributes(pt, nav_id, llvm_function); |
| | 1656 | } else { |
| | 1657 | const file_scope = nav.srcInst(ip).resolveFile(ip); |
| 1620 | const mod = zcu.fileByIndex(file_scope).mod.?; | 1658 | const mod = zcu.fileByIndex(file_scope).mod.?; |
| 1621 | if (resolved.@"threadlocal" and !mod.single_threaded) | | |
| 1622 | variable_index.setThreadLocal(.generaldynamic, &o.builder); | | |
| 1623 | | 1659 | |
| 1624 | const line_number = zcu.navSrcLine(nav_index) + 1; | 1660 | const llvm_variable: Builder.Variable.Index = switch (llvm_global.ptrConst(&o.builder).kind) { |
| | 1661 | .variable => |variable| variable, // re-use existing `Builder.Variable` |
| | 1662 | .replaced, .alias, .function => try llvm_global.toNewVariable(&o.builder), |
| | 1663 | }; |
| | 1664 | llvm_variable.setAlignment(llvm_align, &o.builder); |
| | 1665 | llvm_variable.setSection(llvm_section, &o.builder); |
| | 1666 | llvm_variable.setMutability(if (resolved.@"const") .constant else .global, &o.builder); |
| | 1667 | try llvm_variable.setInitializer(if (opt_extern != null) .no_init else try o.lowerValue(resolved.value), &o.builder); |
| | 1668 | llvm_variable.setThreadLocal(tl: { |
| | 1669 | if (resolved.@"threadlocal" and !mod.single_threaded) break :tl .generaldynamic; |
| | 1670 | break :tl .default; |
| | 1671 | }, &o.builder); |
| 1625 | | 1672 | |
| 1626 | if (!mod.strip) { | 1673 | if (!mod.strip) { |
| 1627 | const debug_file = try o.getDebugFile(file_scope); | 1674 | const debug_file = try o.getDebugFile(file_scope); |
| 1628 | | 1675 | const debug_global_var_expr = try o.builder.debugGlobalVarExpression( |
| 1629 | const debug_global_var = try o.builder.debugGlobalVar( | 1676 | try o.builder.debugGlobalVar( |
| 1630 | try o.builder.metadataString(nav.name.toSlice(ip)), // Name | 1677 | try o.builder.metadataString(nav.name.toSlice(ip)), // Name |
| 1631 | try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name | 1678 | try o.builder.metadataString(nav.fqn.toSlice(ip)), // Linkage name |
| 1632 | debug_file, // File | 1679 | debug_file, // File |
| 1633 | debug_file, // Scope | 1680 | debug_file, // Scope |
| 1634 | line_number, | 1681 | zcu.navSrcLine(nav_id) + 1, |
| 1635 | try o.getDebugType(pt, ty), | 1682 | try o.getDebugType(pt, nav_ty), |
| 1636 | variable_index, | 1683 | llvm_variable, |
| 1637 | .{ .local = linkage == .internal }, | 1684 | .{ .local = llvm_global.ptrConst(&o.builder).linkage == .internal }, |
| 1638 | ); | 1685 | ), |
| 1639 | | 1686 | try o.builder.debugExpression(&.{}), |
| 1640 | const debug_expression = try o.builder.debugExpression(&.{}); | | |
| 1641 | | | |
| 1642 | const debug_global_var_expression = try o.builder.debugGlobalVarExpression( | | |
| 1643 | debug_global_var, | | |
| 1644 | debug_expression, | | |
| 1645 | ); | 1687 | ); |
| 1646 | | 1688 | llvm_variable.setGlobalVariableExpression(debug_global_var_expr, &o.builder); |
| 1647 | variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder); | 1689 | try o.debug_globals.append(o.gpa, debug_global_var_expr); |
| 1648 | try o.debug_globals.append(o.gpa, debug_global_var_expression); | | |
| 1649 | } | 1690 | } |
| 1650 | } | 1691 | } |
| 1651 | | | |
| 1652 | switch (linkage) { | | |
| 1653 | .internal => {}, | | |
| 1654 | .strong, .weak => { | | |
| 1655 | const global_index = o.nav_map.get(nav_index).?; | | |
| 1656 | | | |
| 1657 | const decl_name = decl_name: { | | |
| 1658 | if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") { | | |
| 1659 | if (lib_name.toSlice(ip)) |lib_name_slice| { | | |
| 1660 | if (!std.mem.eql(u8, lib_name_slice, "c")) { | | |
| 1661 | break :decl_name try o.builder.strtabStringFmt("{f}|{s}", .{ nav.name.fmt(ip), lib_name_slice }); | | |
| 1662 | } | | |
| 1663 | } | | |
| 1664 | } | | |
| 1665 | break :decl_name try o.builder.strtabString(nav.name.toSlice(ip)); | | |
| 1666 | }; | | |
| 1667 | | | |
| 1668 | if (o.builder.getGlobal(decl_name)) |other_global| { | | |
| 1669 | if (other_global != global_index) { | | |
| 1670 | // Another global already has this name; just use it in place of this global. | | |
| 1671 | try global_index.replace(other_global, &o.builder); | | |
| 1672 | return; | | |
| 1673 | } | | |
| 1674 | } | | |
| 1675 | | | |
| 1676 | try global_index.rename(decl_name, &o.builder); | | |
| 1677 | global_index.setUnnamedAddr(.default, &o.builder); | | |
| 1678 | if (is_dll_import) { | | |
| 1679 | global_index.setDllStorageClass(.dllimport, &o.builder); | | |
| 1680 | } else if (zcu.comp.config.dll_export_fns) { | | |
| 1681 | global_index.setDllStorageClass(.default, &o.builder); | | |
| 1682 | } | | |
| 1683 | | | |
| 1684 | global_index.setLinkage(switch (linkage) { | | |
| 1685 | .internal => unreachable, | | |
| 1686 | .strong => .external, | | |
| 1687 | .weak => .extern_weak, | | |
| 1688 | .link_once => unreachable, | | |
| 1689 | }, &o.builder); | | |
| 1690 | global_index.setVisibility(visibility, &o.builder); | | |
| 1691 | }, | | |
| 1692 | .link_once => unreachable, | | |
| 1693 | } | | |
| 1694 | } | 1692 | } |
| 1695 | | 1693 | |
| 1696 | fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void { | 1694 | fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void { |
| ... | @@ -1698,18 +1696,43 @@ pub const Object = struct { | ... | @@ -1698,18 +1696,43 @@ pub const Object = struct { |
| 1698 | } | 1696 | } |
| 1699 | | 1697 | |
| 1700 | pub fn updateExports( | 1698 | pub fn updateExports( |
| 1701 | self: *Object, | 1699 | o: *Object, |
| 1702 | exported: Zcu.Exported, | 1700 | exported: Zcu.Exported, |
| 1703 | export_indices: []const Zcu.Export.Index, | 1701 | export_indices: []const Zcu.Export.Index, |
| 1704 | ) link.File.UpdateExportsError!void { | 1702 | ) link.File.UpdateExportsError!void { |
| 1705 | const zcu = self.zcu; | 1703 | const zcu = o.zcu; |
| 1706 | const nav_index = switch (exported) { | | |
| 1707 | .nav => |nav| nav, | | |
| 1708 | .uav => |uav| return updateExportedValue(self, uav, export_indices), | | |
| 1709 | }; | | |
| 1710 | const ip = &zcu.intern_pool; | 1704 | const ip = &zcu.intern_pool; |
| 1711 | const global_index = self.nav_map.get(nav_index).?; | 1705 | const ty: Type, const llvm_ptr: Builder.Constant = switch (exported) { |
| | 1706 | .nav => |nav| exp: { |
| | 1707 | const nav_ty: Type = .fromInterned(ip.getNav(nav).resolved.?.type); |
| | 1708 | const nav_ref = try o.lowerNavRef(nav); |
| | 1709 | break :exp .{ nav_ty, nav_ref }; |
| | 1710 | }, |
| | 1711 | .uav => |uav| exp: { |
| | 1712 | const uav_ty = Value.fromInterned(uav).typeOf(zcu); |
| | 1713 | const uav_ref = try o.lowerUavRef( |
| | 1714 | uav, |
| | 1715 | uav_ty.abiAlignment(zcu), |
| | 1716 | target_util.defaultAddressSpace(zcu.getTarget(), .global_constant), |
| | 1717 | ); |
| | 1718 | break :exp .{ uav_ty, uav_ref }; |
| | 1719 | }, |
| | 1720 | }; |
| | 1721 | switch (llvm_ptr.unwrap()) { |
| | 1722 | .global => |global| return o.updateExportedGlobal(global, ty, export_indices), |
| | 1723 | .constant => @panic("LLVM TODO: export zero-bit value"), |
| | 1724 | } |
| | 1725 | } |
| | 1726 | |
| | 1727 | fn updateExportedGlobal( |
| | 1728 | o: *Object, |
| | 1729 | global_index: Builder.Global.Index, |
| | 1730 | ty: Type, |
| | 1731 | export_indices: []const Zcu.Export.Index, |
| | 1732 | ) link.File.UpdateExportsError!void { |
| | 1733 | const zcu = o.zcu; |
| 1712 | const comp = zcu.comp; | 1734 | const comp = zcu.comp; |
| | 1735 | const ip = &zcu.intern_pool; |
| 1713 | | 1736 | |
| 1714 | // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use. | 1737 | // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use. |
| 1715 | coff_export_flags: { | 1738 | coff_export_flags: { |
| ... | @@ -1719,7 +1742,7 @@ pub const Object = struct { | ... | @@ -1719,7 +1742,7 @@ pub const Object = struct { |
| 1719 | .elf, .wasm => break :coff_export_flags, | 1742 | .elf, .wasm => break :coff_export_flags, |
| 1720 | .coff => |*coff| coff, | 1743 | .coff => |*coff| coff, |
| 1721 | }; | 1744 | }; |
| 1722 | if (!ip.isFunctionType(ip.getNav(nav_index).resolved.?.type)) break :coff_export_flags; | 1745 | if (ty.zigTypeTag(zcu) != .@"fn") break :coff_export_flags; |
| 1723 | const flags = &coff.lld_export_flags; | 1746 | const flags = &coff.lld_export_flags; |
| 1724 | for (export_indices) |export_index| { | 1747 | for (export_indices) |export_index| { |
| 1725 | const name = export_index.ptr(zcu).opts.name; | 1748 | const name = export_index.ptr(zcu).opts.name; |
| ... | @@ -1732,152 +1755,88 @@ pub const Object = struct { | ... | @@ -1732,152 +1755,88 @@ pub const Object = struct { |
| 1732 | } | 1755 | } |
| 1733 | } | 1756 | } |
| 1734 | | 1757 | |
| 1735 | if (export_indices.len != 0) { | 1758 | // If the first export specifies a linksection, set the exported variable's section to that |
| 1736 | return updateExportedGlobal(self, zcu, global_index, export_indices); | 1759 | // one. This is kind of a hack because `std.builtin.ExportOptions.section` doesn't actually |
| 1737 | } else { | 1760 | // make much sense: the linksection should be associated with the declaration itself rather |
| 1738 | const fqn = try self.builder.strtabString(ip.getNav(nav_index).fqn.toSlice(ip)); | 1761 | // than some particular symbol it is exported as! |
| 1739 | try global_index.rename(fqn, &self.builder); | 1762 | if (export_indices[0].ptr(zcu).opts.section.toSlice(ip)) |section_slice| { |
| 1740 | global_index.setLinkage(if (self.builder.strip) .private else .internal, &self.builder); | 1763 | const variable = &global_index.ptrConst(&o.builder).kind.variable; |
| 1741 | if (comp.config.dll_export_fns) | 1764 | variable.setSection(try o.builder.string(section_slice), &o.builder); |
| 1742 | global_index.setDllStorageClass(.default, &self.builder); | | |
| 1743 | global_index.setUnnamedAddr(.unnamed_addr, &self.builder); | | |
| 1744 | } | 1765 | } |
| 1745 | } | | |
| 1746 | | 1766 | |
| 1747 | fn updateExportedValue( | 1767 | const llvm_global_ty = global_index.typeOf(&o.builder); |
| 1748 | o: *Object, | | |
| 1749 | exported_value: InternPool.Index, | | |
| 1750 | export_indices: []const Zcu.Export.Index, | | |
| 1751 | ) link.File.UpdateExportsError!void { | | |
| 1752 | const zcu = o.zcu; | | |
| 1753 | const gpa = zcu.gpa; | | |
| 1754 | const ip = &zcu.intern_pool; | | |
| 1755 | const main_exp_name = try o.builder.strtabString(export_indices[0].ptr(zcu).opts.name.toSlice(ip)); | | |
| 1756 | const global_index = i: { | | |
| 1757 | const gop = try o.uav_map.getOrPut(gpa, exported_value); | | |
| 1758 | if (gop.found_existing) { | | |
| 1759 | const global_index = gop.value_ptr.*; | | |
| 1760 | try global_index.rename(main_exp_name, &o.builder); | | |
| 1761 | break :i global_index; | | |
| 1762 | } | | |
| 1763 | const llvm_addr_space = toLlvmAddressSpace(.generic, zcu.getTarget()); | | |
| 1764 | const variable_index = try o.builder.addVariable( | | |
| 1765 | main_exp_name, | | |
| 1766 | try o.lowerType(.fromInterned(ip.typeOf(exported_value))), | | |
| 1767 | llvm_addr_space, | | |
| 1768 | ); | | |
| 1769 | const global_index = variable_index.ptrConst(&o.builder).global; | | |
| 1770 | gop.value_ptr.* = global_index; | | |
| 1771 | // This line invalidates `gop`. | | |
| 1772 | const init_val = try o.lowerValue(exported_value); | | |
| 1773 | try variable_index.setInitializer(init_val, &o.builder); | | |
| 1774 | break :i global_index; | | |
| 1775 | }; | | |
| 1776 | return updateExportedGlobal(o, zcu, global_index, export_indices); | | |
| 1777 | } | | |
| 1778 | | 1768 | |
| 1779 | fn updateExportedGlobal( | 1769 | // All exports are represented as aliases to the original global. |
| 1780 | o: *Object, | | |
| 1781 | zcu: *Zcu, | | |
| 1782 | global_index: Builder.Global.Index, | | |
| 1783 | export_indices: []const Zcu.Export.Index, | | |
| 1784 | ) link.File.UpdateExportsError!void { | | |
| 1785 | const comp = zcu.comp; | | |
| 1786 | const ip = &zcu.intern_pool; | | |
| 1787 | const first_export = export_indices[0].ptr(zcu); | | |
| 1788 | | | |
| 1789 | // We will rename this global to have a name matching `first_export`. | | |
| 1790 | // Successive exports become aliases. | | |
| 1791 | // If the first export name already exists, then there is a corresponding | | |
| 1792 | // extern global - we replace it with this global. | | |
| 1793 | const first_exp_name = try o.builder.strtabString(first_export.opts.name.toSlice(ip)); | | |
| 1794 | if (o.builder.getGlobal(first_exp_name)) |other_global| replace: { | | |
| 1795 | if (other_global.toConst().getBase(&o.builder) == global_index.toConst().getBase(&o.builder)) { | | |
| 1796 | break :replace; // this global already has the name we want | | |
| 1797 | } | | |
| 1798 | try global_index.takeName(other_global, &o.builder); | | |
| 1799 | try other_global.replace(global_index, &o.builder); | | |
| 1800 | // Problem: now we need to replace in the decl_map that | | |
| 1801 | // the extern decl index points to this new global. However we don't | | |
| 1802 | // know the decl index. | | |
| 1803 | // Even if we did, a future incremental update to the extern would then | | |
| 1804 | // treat the LLVM global as an extern rather than an export, so it would | | |
| 1805 | // need a way to check that. | | |
| 1806 | // This is a TODO that needs to be solved when making | | |
| 1807 | // the LLVM backend support incremental compilation. | | |
| 1808 | } else { | | |
| 1809 | try global_index.rename(first_exp_name, &o.builder); | | |
| 1810 | } | | |
| 1811 | | 1770 | |
| 1812 | global_index.setUnnamedAddr(.default, &o.builder); | 1771 | // TODO: we currently do not delete old exports. To do that we'll need to track which |
| 1813 | if (comp.config.dll_export_fns and first_export.opts.visibility != .hidden) | 1772 | // globals actually *are* exports. |
| 1814 | global_index.setDllStorageClass(.dllexport, &o.builder); | | |
| 1815 | global_index.setLinkage(switch (first_export.opts.linkage) { | | |
| 1816 | .internal => unreachable, | | |
| 1817 | .strong => .external, | | |
| 1818 | .weak => .weak_odr, | | |
| 1819 | .link_once => .linkonce_odr, | | |
| 1820 | }, &o.builder); | | |
| 1821 | global_index.setVisibility(switch (first_export.opts.visibility) { | | |
| 1822 | .default => .default, | | |
| 1823 | .hidden => .hidden, | | |
| 1824 | .protected => .protected, | | |
| 1825 | }, &o.builder); | | |
| 1826 | if (first_export.opts.section.toSlice(ip)) |section| | | |
| 1827 | switch (global_index.ptrConst(&o.builder).kind) { | | |
| 1828 | .variable => |impl_index| impl_index.setSection( | | |
| 1829 | try o.builder.string(section), | | |
| 1830 | &o.builder, | | |
| 1831 | ), | | |
| 1832 | .function => unreachable, | | |
| 1833 | .alias => unreachable, | | |
| 1834 | .replaced => unreachable, | | |
| 1835 | }; | | |
| 1836 | | 1773 | |
| 1837 | // If a Decl is exported more than one time (which is rare), | 1774 | for (export_indices) |export_idx| { |
| 1838 | // we add aliases for all but the first export. | | |
| 1839 | // TODO LLVM C API does not support deleting aliases. | | |
| 1840 | // The planned solution to this is https://github.com/ziglang/zig/issues/13265 | | |
| 1841 | // Until then we iterate over existing aliases and make them point | | |
| 1842 | // to the correct decl, or otherwise add a new alias. Old aliases are leaked. | | |
| 1843 | for (export_indices[1..]) |export_idx| { | | |
| 1844 | const exp = export_idx.ptr(zcu); | 1775 | const exp = export_idx.ptr(zcu); |
| 1845 | const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip)); | 1776 | const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip)); |
| 1846 | if (o.builder.getGlobal(exp_name)) |global| { | 1777 | |
| 1847 | switch (global.ptrConst(&o.builder).kind) { | 1778 | // Our goal is to make an alias with the name `exp_name`, but if that name is already |
| | 1779 | // taken by some existing global, we need to figure out what to do with that existing |
| | 1780 | // global. |
| | 1781 | // |
| | 1782 | // The name, aliasee, and type will be set within this block. Other properties of the |
| | 1783 | // alias will be set below. |
| | 1784 | const alias_global: Builder.Global.Index = global: { |
| | 1785 | const existing_global = o.builder.getGlobal(exp_name) orelse { |
| | 1786 | // There is no existing global with this name, so make a new alias. |
| | 1787 | const alias = try o.builder.addAlias( |
| | 1788 | exp_name, |
| | 1789 | llvm_global_ty, |
| | 1790 | .default, |
| | 1791 | global_index.toConst(), |
| | 1792 | ); |
| | 1793 | break :global alias.ptrConst(&o.builder).global; |
| | 1794 | }; |
| | 1795 | // There is an existing global with this name, so we can't just create an alias. We |
| | 1796 | // need to figure out what to do with the existing global instead. |
| | 1797 | switch (existing_global.ptrConst(&o.builder).kind) { |
| 1848 | .alias => |alias| { | 1798 | .alias => |alias| { |
| | 1799 | // We can just repurpose the existing alias. |
| 1849 | alias.setAliasee(global_index.toConst(), &o.builder); | 1800 | alias.setAliasee(global_index.toConst(), &o.builder); |
| 1850 | continue; | 1801 | alias.ptrConst(&o.builder).global.ptr(&o.builder).type = global_index.typeOf(&o.builder); |
| | 1802 | break :global existing_global; |
| 1851 | }, | 1803 | }, |
| 1852 | .variable, .function => { | 1804 | .variable, .function => { |
| 1853 | // This existing global is an `extern` corresponding to this export. | 1805 | // This must be an extern, which is no good to us---we need an alias. The |
| 1854 | // Replace it with the global being exported. | 1806 | // extern should refer to the value we're exporting, so replace it with the |
| 1855 | // This existing global must be replaced with the alias. | 1807 | // exported value. That will free up the name for us to create a new alias. |
| 1856 | try global.rename(.empty, &o.builder); | 1808 | // We need to make a new global which is an alias. Replace this existing one |
| 1857 | try global.replace(global_index, &o.builder); | 1809 | // with the target global, making the name available and fixing references |
| | 1810 | // to this global to point to the target. |
| | 1811 | try existing_global.replace(global_index, &o.builder); |
| | 1812 | // The name is now free, so create an alias. |
| | 1813 | const alias = try o.builder.addAlias( |
| | 1814 | exp_name, |
| | 1815 | llvm_global_ty, |
| | 1816 | .default, |
| | 1817 | global_index.toConst(), |
| | 1818 | ); |
| | 1819 | break :global alias.ptrConst(&o.builder).global; |
| 1858 | }, | 1820 | }, |
| 1859 | .replaced => unreachable, | 1821 | .replaced => unreachable, // a replaced global would have lost the name `exp_name` |
| 1860 | } | 1822 | } |
| 1861 | } | 1823 | }; |
| 1862 | const alias_index = try o.builder.addAlias( | 1824 | |
| 1863 | .empty, | 1825 | // Now for a bit of setup which |
| 1864 | global_index.typeOf(&o.builder), | 1826 | |
| 1865 | .default, | 1827 | // We need the alias to *not* be `unnamed_addr` to ensure that the alias address equals |
| 1866 | global_index.toConst(), | 1828 | // the address of the original global. |
| 1867 | ); | 1829 | alias_global.setUnnamedAddr(.default, &o.builder); |
| 1868 | try alias_index.rename(exp_name, &o.builder); | 1830 | |
| 1869 | | 1831 | if (comp.config.dll_export_fns and exp.opts.visibility != .hidden) |
| 1870 | const alias_global_index = alias_index.ptrConst(&o.builder).global; | 1832 | alias_global.setDllStorageClass(.dllexport, &o.builder); |
| 1871 | alias_global_index.setUnnamedAddr(.default, &o.builder); | 1833 | alias_global.setLinkage(switch (exp.opts.linkage) { |
| 1872 | if (comp.config.dll_export_fns and first_export.opts.visibility != .hidden) | 1834 | .internal => if (o.builder.strip) .private else .internal, // we still did useful work in replacing an existing symbol if there was one |
| 1873 | alias_global_index.setDllStorageClass(.dllexport, &o.builder); | | |
| 1874 | alias_global_index.setLinkage(switch (first_export.opts.linkage) { | | |
| 1875 | .internal => unreachable, | | |
| 1876 | .strong => .external, | 1835 | .strong => .external, |
| 1877 | .weak => .weak_odr, | 1836 | .weak => .weak_odr, |
| 1878 | .link_once => .linkonce_odr, | 1837 | .link_once => .linkonce_odr, |
| 1879 | }, &o.builder); | 1838 | }, &o.builder); |
| 1880 | alias_global_index.setVisibility(switch (first_export.opts.visibility) { | 1839 | alias_global.setVisibility(switch (exp.opts.visibility) { |
| 1881 | .default => .default, | 1840 | .default => .default, |
| 1882 | .hidden => .hidden, | 1841 | .hidden => .hidden, |
| 1883 | .protected => .protected, | 1842 | .protected => .protected, |
| ... | @@ -1940,7 +1899,12 @@ pub const Object = struct { | ... | @@ -1940,7 +1899,12 @@ pub const Object = struct { |
| 1940 | assert(val != .anyerror_type); | 1899 | assert(val != .anyerror_type); |
| 1941 | const fwd_ref = o.debug_types.items[@intFromEnum(index)]; | 1900 | const fwd_ref = o.debug_types.items[@intFromEnum(index)]; |
| 1942 | const name_str = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)}); | 1901 | const name_str = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)}); |
| 1943 | const debug_incomplete_type = try o.builder.debugSignedType(name_str, 0); | 1902 | // If `ty` is a function, use a dummy *function* type to prevent existing debug |
| | 1903 | // subprograms from becoming ill-formed. |
| | 1904 | const debug_incomplete_type = switch (ty.zigTypeTag(zcu)) { |
| | 1905 | .@"fn" => try o.builder.debugSubroutineType(null), |
| | 1906 | else => try o.builder.debugSignedType(name_str, 0), |
| | 1907 | }; |
| 1944 | o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type); | 1908 | o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type); |
| 1945 | } | 1909 | } |
| 1946 | } | 1910 | } |
| ... | @@ -2269,7 +2233,9 @@ pub const Object = struct { | ... | @@ -2269,7 +2233,9 @@ pub const Object = struct { |
| 2269 | }, | 2233 | }, |
| 2270 | .@"fn" => { | 2234 | .@"fn" => { |
| 2271 | if (!ty.fnHasRuntimeBits(zcu)) { | 2235 | if (!ty.fnHasRuntimeBits(zcu)) { |
| 2272 | return o.builder.debugSignedType(name, 0); | 2236 | // Use a dummy *function* type to prevent existing debug subprograms from |
| | 2237 | // becoming ill-formed. |
| | 2238 | return o.builder.debugSubroutineType(null); |
| 2273 | } | 2239 | } |
| 2274 | | 2240 | |
| 2275 | const fn_info = zcu.typeToFunc(ty).?; | 2241 | const fn_info = zcu.typeToFunc(ty).?; |
| ... | @@ -2716,75 +2682,38 @@ pub const Object = struct { | ... | @@ -2716,75 +2682,38 @@ pub const Object = struct { |
| 2716 | return o.getDebugType(pt, .fromInterned(namespace.owner_type)); | 2682 | return o.getDebugType(pt, .fromInterned(namespace.owner_type)); |
| 2717 | } | 2683 | } |
| 2718 | | 2684 | |
| 2719 | /// If the llvm function does not exist, create it. | 2685 | /// Sets the attributes and callconv of the given `Builder.Function`, which corresponds to the |
| 2720 | /// Note that this can be called before the function's semantic analysis has | 2686 | /// given `Nav` (which is a function). |
| 2721 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. | 2687 | fn addLlvmFunctionAttributes( |
| 2722 | pub fn resolveLlvmFunction( | | |
| 2723 | o: *Object, | 2688 | o: *Object, |
| 2724 | nav_index: InternPool.Nav.Index, | 2689 | pt: Zcu.PerThread, |
| 2725 | ) Allocator.Error!Builder.Function.Index { | 2690 | nav_id: InternPool.Nav.Index, |
| | 2691 | function_index: Builder.Function.Index, |
| | 2692 | ) Allocator.Error!void { |
| 2726 | const zcu = o.zcu; | 2693 | const zcu = o.zcu; |
| 2727 | const ip = &zcu.intern_pool; | 2694 | const ip = &zcu.intern_pool; |
| 2728 | const gpa = o.gpa; | 2695 | const nav = ip.getNav(nav_id); |
| 2729 | const nav = ip.getNav(nav_index); | 2696 | const owner_mod = zcu.navFileScope(nav_id).mod.?; |
| 2730 | const owner_mod = zcu.navFileScope(nav_index).mod.?; | | |
| 2731 | const ty: Type = .fromInterned(nav.resolved.?.type); | 2697 | const ty: Type = .fromInterned(nav.resolved.?.type); |
| 2732 | const gop = try o.nav_map.getOrPut(gpa, nav_index); | | |
| 2733 | if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function; | | |
| 2734 | | 2698 | |
| 2735 | const fn_info = zcu.typeToFunc(ty).?; | 2699 | const fn_info = zcu.typeToFunc(ty).?; |
| 2736 | const target = &owner_mod.resolved_target.result; | 2700 | const target = &owner_mod.resolved_target.result; |
| 2737 | | 2701 | |
| 2738 | const is_extern, const lib_name = if (nav.getExtern(ip)) |@"extern"| | | |
| 2739 | .{ true, @"extern".lib_name } | | |
| 2740 | else | | |
| 2741 | .{ false, .none }; | | |
| 2742 | const function_index = try o.builder.addFunction( | | |
| 2743 | try o.lowerType(ty), | | |
| 2744 | try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)), | | |
| 2745 | toLlvmAddressSpace(nav.resolved.?.@"addrspace", target), | | |
| 2746 | ); | | |
| 2747 | gop.value_ptr.* = function_index.ptrConst(&o.builder).global; | | |
| 2748 | | | |
| 2749 | var attributes: Builder.FunctionAttributes.Wip = .{}; | 2702 | var attributes: Builder.FunctionAttributes.Wip = .{}; |
| 2750 | defer attributes.deinit(&o.builder); | 2703 | defer attributes.deinit(&o.builder); |
| 2751 | | 2704 | |
| 2752 | if (!is_extern) { | 2705 | if (target.cpu.arch.isWasm()) if (nav.getExtern(ip)) |@"extern"| { |
| 2753 | function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); | 2706 | try attributes.addFnAttr(.{ .string = .{ |
| 2754 | function_index.setUnnamedAddr(.unnamed_addr, &o.builder); | 2707 | .kind = try o.builder.string("wasm-import-name"), |
| 2755 | } else { | 2708 | .value = try o.builder.string(nav.name.toSlice(ip)), |
| 2756 | if (target.cpu.arch.isWasm()) { | 2709 | } }, &o.builder); |
| 2757 | try attributes.addFnAttr(.{ .string = .{ | 2710 | if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| { |
| 2758 | .kind = try o.builder.string("wasm-import-name"), | 2711 | if (!std.mem.eql(u8, lib_name_slice, "c")) try attributes.addFnAttr(.{ .string = .{ |
| 2759 | .value = try o.builder.string(nav.name.toSlice(ip)), | 2712 | .kind = try o.builder.string("wasm-import-module"), |
| | 2713 | .value = try o.builder.string(lib_name_slice), |
| 2760 | } }, &o.builder); | 2714 | } }, &o.builder); |
| 2761 | if (lib_name.toSlice(ip)) |lib_name_slice| { | | |
| 2762 | if (!std.mem.eql(u8, lib_name_slice, "c")) try attributes.addFnAttr(.{ .string = .{ | | |
| 2763 | .kind = try o.builder.string("wasm-import-module"), | | |
| 2764 | .value = try o.builder.string(lib_name_slice), | | |
| 2765 | } }, &o.builder); | | |
| 2766 | } | | |
| 2767 | } | 2715 | } |
| 2768 | } | 2716 | }; |
| 2769 | | | |
| 2770 | var llvm_arg_i: u32 = 0; | | |
| 2771 | if (firstParamSRet(fn_info, zcu, target)) { | | |
| 2772 | // Sret pointers must not be address 0 | | |
| 2773 | try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); | | |
| 2774 | try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder); | | |
| 2775 | | | |
| 2776 | const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type)); | | |
| 2777 | try attributes.addParamAttr(llvm_arg_i, .{ .sret = raw_llvm_ret_ty }, &o.builder); | | |
| 2778 | | | |
| 2779 | llvm_arg_i += 1; | | |
| 2780 | } | | |
| 2781 | | | |
| 2782 | const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; | | |
| 2783 | | | |
| 2784 | if (err_return_tracing) { | | |
| 2785 | try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); | | |
| 2786 | llvm_arg_i += 1; | | |
| 2787 | } | | |
| 2788 | | 2717 | |
| 2789 | if (fn_info.cc == .async) { | 2718 | if (fn_info.cc == .async) { |
| 2790 | @panic("TODO: LLVM backend lower async function"); | 2719 | @panic("TODO: LLVM backend lower async function"); |
| ... | @@ -2859,9 +2788,6 @@ pub const Object = struct { | ... | @@ -2859,9 +2788,6 @@ pub const Object = struct { |
| 2859 | } | 2788 | } |
| 2860 | } | 2789 | } |
| 2861 | | 2790 | |
| 2862 | if (nav.resolved.?.@"align" != .none) | | |
| 2863 | function_index.setAlignment(nav.resolved.?.@"align".toLlvm(), &o.builder); | | |
| 2864 | | | |
| 2865 | // Function attributes that are independent of analysis results of the function body. | 2791 | // Function attributes that are independent of analysis results of the function body. |
| 2866 | try o.addCommonFnAttributes( | 2792 | try o.addCommonFnAttributes( |
| 2867 | &attributes, | 2793 | &attributes, |
| ... | @@ -2877,8 +2803,71 @@ pub const Object = struct { | ... | @@ -2877,8 +2803,71 @@ pub const Object = struct { |
| 2877 | | 2803 | |
| 2878 | if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder); | 2804 | if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder); |
| 2879 | | 2805 | |
| | 2806 | var it = iterateParamTypes(o, fn_info); |
| | 2807 | if (firstParamSRet(fn_info, zcu, target)) { |
| | 2808 | // Sret pointers must not be address 0 |
| | 2809 | try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder); |
| | 2810 | try attributes.addParamAttr(it.llvm_index, .@"noalias", &o.builder); |
| | 2811 | |
| | 2812 | const raw_llvm_ret_ty = try o.lowerType(.fromInterned(fn_info.return_type)); |
| | 2813 | try attributes.addParamAttr(it.llvm_index, .{ .sret = raw_llvm_ret_ty }, &o.builder); |
| | 2814 | it.llvm_index += 1; |
| | 2815 | } |
| | 2816 | const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; |
| | 2817 | if (err_return_tracing) { |
| | 2818 | try attributes.addParamAttr(it.llvm_index, .nonnull, &o.builder); |
| | 2819 | it.llvm_index += 1; |
| | 2820 | } |
| | 2821 | while (try it.next()) |lowering| switch (lowering) { |
| | 2822 | .byval => { |
| | 2823 | const param_index = it.zig_index - 1; |
| | 2824 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[param_index]); |
| | 2825 | if (!isByRef(param_ty, zcu)) { |
| | 2826 | try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1); |
| | 2827 | } |
| | 2828 | }, |
| | 2829 | .byref => { |
| | 2830 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| | 2831 | const param_llvm_ty = try o.lowerType(param_ty); |
| | 2832 | const alignment = param_ty.abiAlignment(zcu); |
| | 2833 | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty); |
| | 2834 | }, |
| | 2835 | .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), |
| | 2836 | .slice => { |
| | 2837 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| | 2838 | const ptr_info = param_ty.ptrInfo(zcu); |
| | 2839 | const llvm_ptr_index = it.llvm_index - 2; |
| | 2840 | if (std.math.cast(u5, it.zig_index - 1)) |i| { |
| | 2841 | if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) { |
| | 2842 | try attributes.addParamAttr(llvm_ptr_index, .@"noalias", &o.builder); |
| | 2843 | } |
| | 2844 | } |
| | 2845 | if (param_ty.zigTypeTag(zcu) != .optional and |
| | 2846 | !ptr_info.flags.is_allowzero and |
| | 2847 | ptr_info.flags.address_space == .generic) |
| | 2848 | { |
| | 2849 | try attributes.addParamAttr(llvm_ptr_index, .nonnull, &o.builder); |
| | 2850 | } |
| | 2851 | if (ptr_info.flags.is_const) { |
| | 2852 | try attributes.addParamAttr(llvm_ptr_index, .readonly, &o.builder); |
| | 2853 | } |
| | 2854 | const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) { |
| | 2855 | else => |a| .wrap(a.toLlvm()), |
| | 2856 | .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)), |
| | 2857 | }; |
| | 2858 | try attributes.addParamAttr(llvm_ptr_index, .{ .@"align" = elem_align }, &o.builder); |
| | 2859 | }, |
| | 2860 | // No attributes needed for these. |
| | 2861 | .no_bits, |
| | 2862 | .abi_sized_int, |
| | 2863 | .multiple_llvm_types, |
| | 2864 | .float_array, |
| | 2865 | .i32_array, |
| | 2866 | .i64_array, |
| | 2867 | => continue, |
| | 2868 | }; |
| | 2869 | |
| 2880 | function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); | 2870 | function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); |
| 2881 | return function_index; | | |
| 2882 | } | 2871 | } |
| 2883 | | 2872 | |
| 2884 | fn addCommonFnAttributes( | 2873 | fn addCommonFnAttributes( |
| ... | @@ -2951,97 +2940,6 @@ pub const Object = struct { | ... | @@ -2951,97 +2940,6 @@ pub const Object = struct { |
| 2951 | } | 2940 | } |
| 2952 | } | 2941 | } |
| 2953 | | 2942 | |
| 2954 | fn resolveGlobalUav( | | |
| 2955 | o: *Object, | | |
| 2956 | uav: InternPool.Index, | | |
| 2957 | llvm_addr_space: Builder.AddrSpace, | | |
| 2958 | alignment: InternPool.Alignment, | | |
| 2959 | ) Allocator.Error!Builder.Variable.Index { | | |
| 2960 | assert(alignment != .none); | | |
| 2961 | // TODO: Add address space to the anon_decl_map | | |
| 2962 | const gop = try o.uav_map.getOrPut(o.gpa, uav); | | |
| 2963 | if (gop.found_existing) { | | |
| 2964 | // Keep the greater of the two alignments. | | |
| 2965 | const variable_index = gop.value_ptr.ptr(&o.builder).kind.variable; | | |
| 2966 | const old_alignment = InternPool.Alignment.fromLlvm(variable_index.getAlignment(&o.builder)); | | |
| 2967 | const max_alignment = old_alignment.maxStrict(alignment); | | |
| 2968 | variable_index.setAlignment(max_alignment.toLlvm(), &o.builder); | | |
| 2969 | return variable_index; | | |
| 2970 | } | | |
| 2971 | errdefer assert(o.uav_map.remove(uav)); | | |
| 2972 | | | |
| 2973 | const zcu = o.zcu; | | |
| 2974 | const decl_ty = zcu.intern_pool.typeOf(uav); | | |
| 2975 | | | |
| 2976 | const variable_index = try o.builder.addVariable( | | |
| 2977 | try o.builder.strtabStringFmt("__anon_{d}", .{@intFromEnum(uav)}), | | |
| 2978 | try o.lowerType(.fromInterned(decl_ty)), | | |
| 2979 | llvm_addr_space, | | |
| 2980 | ); | | |
| 2981 | gop.value_ptr.* = variable_index.ptrConst(&o.builder).global; | | |
| 2982 | | | |
| 2983 | try variable_index.setInitializer(try o.lowerValue(uav), &o.builder); | | |
| 2984 | variable_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); | | |
| 2985 | variable_index.setMutability(.constant, &o.builder); | | |
| 2986 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); | | |
| 2987 | variable_index.setAlignment(alignment.toLlvm(), &o.builder); | | |
| 2988 | return variable_index; | | |
| 2989 | } | | |
| 2990 | | | |
| 2991 | fn resolveGlobalNav( | | |
| 2992 | o: *Object, | | |
| 2993 | nav_index: InternPool.Nav.Index, | | |
| 2994 | ) Allocator.Error!Builder.Variable.Index { | | |
| 2995 | const gop = try o.nav_map.getOrPut(o.gpa, nav_index); | | |
| 2996 | if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable; | | |
| 2997 | errdefer assert(o.nav_map.remove(nav_index)); | | |
| 2998 | | | |
| 2999 | const zcu = o.zcu; | | |
| 3000 | const ip = &zcu.intern_pool; | | |
| 3001 | const nav = ip.getNav(nav_index); | | |
| 3002 | const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_dll_import: bool = switch (nav.resolved.?.value) { | | |
| 3003 | .none => .{ .internal, .default, false }, // this is a source declaration which is *not* marked `extern` | | |
| 3004 | else => |val| switch (ip.indexToKey(val)) { | | |
| 3005 | else => .{ .internal, .default, false }, | | |
| 3006 | .@"extern" => |e| .{ e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import }, | | |
| 3007 | }, | | |
| 3008 | }; | | |
| 3009 | | | |
| 3010 | const variable_index = try o.builder.addVariable( | | |
| 3011 | try o.builder.strtabString(switch (linkage) { | | |
| 3012 | .internal => nav.fqn, | | |
| 3013 | .strong, .weak => nav.name, | | |
| 3014 | .link_once => unreachable, | | |
| 3015 | }.toSlice(ip)), | | |
| 3016 | try o.lowerType(.fromInterned(nav.resolved.?.type)), | | |
| 3017 | toLlvmGlobalAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget()), | | |
| 3018 | ); | | |
| 3019 | gop.value_ptr.* = variable_index.ptrConst(&o.builder).global; | | |
| 3020 | | | |
| 3021 | // This is needed for declarations created by `@extern`. | | |
| 3022 | switch (linkage) { | | |
| 3023 | .internal => { | | |
| 3024 | variable_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); | | |
| 3025 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); | | |
| 3026 | }, | | |
| 3027 | .strong, .weak => { | | |
| 3028 | variable_index.setLinkage(switch (linkage) { | | |
| 3029 | .internal => unreachable, | | |
| 3030 | .strong => .external, | | |
| 3031 | .weak => .extern_weak, | | |
| 3032 | .link_once => unreachable, | | |
| 3033 | }, &o.builder); | | |
| 3034 | variable_index.setUnnamedAddr(.default, &o.builder); | | |
| 3035 | if (nav.resolved.?.@"threadlocal" and !zcu.navFileScope(nav_index).mod.?.single_threaded) | | |
| 3036 | variable_index.setThreadLocal(.generaldynamic, &o.builder); | | |
| 3037 | if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder); | | |
| 3038 | }, | | |
| 3039 | .link_once => unreachable, | | |
| 3040 | } | | |
| 3041 | variable_index.setVisibility(visibility, &o.builder); | | |
| 3042 | return variable_index; | | |
| 3043 | } | | |
| 3044 | | | |
| 3045 | pub fn errorIntType(o: *Object) Allocator.Error!Builder.Type { | 2943 | pub fn errorIntType(o: *Object) Allocator.Error!Builder.Type { |
| 3046 | return o.builder.intType(o.zcu.errorSetBits()); | 2944 | return o.builder.intType(o.zcu.errorSetBits()); |
| 3047 | } | 2945 | } |
| ... | @@ -3051,7 +2949,7 @@ pub const Object = struct { | ... | @@ -3051,7 +2949,7 @@ pub const Object = struct { |
| 3051 | const target = zcu.getTarget(); | 2949 | const target = zcu.getTarget(); |
| 3052 | const ip = &zcu.intern_pool; | 2950 | const ip = &zcu.intern_pool; |
| 3053 | return switch (t.toIntern()) { | 2951 | return switch (t.toIntern()) { |
| 3054 | .u0_type, .i0_type => unreachable, | 2952 | .u0_type, .i0_type => unreachable, // no runtime bits |
| 3055 | inline .u1_type, | 2953 | inline .u1_type, |
| 3056 | .u8_type, | 2954 | .u8_type, |
| 3057 | .i8_type, | 2955 | .i8_type, |
| ... | @@ -3100,18 +2998,18 @@ pub const Object = struct { | ... | @@ -3100,18 +2998,18 @@ pub const Object = struct { |
| 3100 | return .i8; | 2998 | return .i8; |
| 3101 | }, | 2999 | }, |
| 3102 | .bool_type => .i1, | 3000 | .bool_type => .i1, |
| 3103 | .void_type => .void, | | |
| 3104 | .type_type => unreachable, | | |
| 3105 | .anyerror_type => try o.errorIntType(), | 3001 | .anyerror_type => try o.errorIntType(), |
| 3106 | .comptime_int_type, | 3002 | .void_type => unreachable, // no runtime bits |
| 3107 | .comptime_float_type, | 3003 | .type_type => unreachable, // no runtime bits |
| 3108 | .noreturn_type, | 3004 | .comptime_int_type => unreachable, // no runtime bits |
| 3109 | => unreachable, | 3005 | .comptime_float_type => unreachable, // no runtime bits |
| | 3006 | .noreturn_type => unreachable, // no runtime bits |
| | 3007 | .null_type => unreachable, // no runtime bits |
| | 3008 | .undefined_type => unreachable, // no runtime bits |
| | 3009 | .enum_literal_type => unreachable, // no runtime bits |
| | 3010 | .optional_noreturn_type => unreachable, // no runtime bits |
| | 3011 | .empty_tuple_type => unreachable, // no runtime bits |
| 3110 | .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"), | 3012 | .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"), |
| 3111 | .null_type, | | |
| 3112 | .undefined_type, | | |
| 3113 | .enum_literal_type, | | |
| 3114 | => unreachable, | | |
| 3115 | .ptr_usize_type, | 3013 | .ptr_usize_type, |
| 3116 | .ptr_const_comptime_int_type, | 3014 | .ptr_const_comptime_int_type, |
| 3117 | .manyptr_u8_type, | 3015 | .manyptr_u8_type, |
| ... | @@ -3121,13 +3019,10 @@ pub const Object = struct { | ... | @@ -3121,13 +3019,10 @@ pub const Object = struct { |
| 3121 | .slice_const_u8_type, | 3019 | .slice_const_u8_type, |
| 3122 | .slice_const_u8_sentinel_0_type, | 3020 | .slice_const_u8_sentinel_0_type, |
| 3123 | => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(.usize) }), | 3021 | => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(.usize) }), |
| 3124 | .optional_noreturn_type => unreachable, | | |
| 3125 | .anyerror_void_error_union_type, | 3022 | .anyerror_void_error_union_type, |
| 3126 | .adhoc_inferred_error_set_type, | 3023 | .adhoc_inferred_error_set_type, |
| 3127 | => try o.errorIntType(), | 3024 | => try o.errorIntType(), |
| 3128 | .generic_poison_type, | 3025 | .generic_poison_type => unreachable, |
| 3129 | .empty_tuple_type, | | |
| 3130 | => unreachable, | | |
| 3131 | // values, not types | 3026 | // values, not types |
| 3132 | .undef, | 3027 | .undef, |
| 3133 | .undef_bool, | 3028 | .undef_bool, |
| ... | @@ -3176,7 +3071,11 @@ pub const Object = struct { | ... | @@ -3176,7 +3071,11 @@ pub const Object = struct { |
| 3176 | ), | 3071 | ), |
| 3177 | .opt_type => |child_ty| { | 3072 | .opt_type => |child_ty| { |
| 3178 | // Must stay in sync with `opt_payload` logic in `lowerPtr`. | 3073 | // Must stay in sync with `opt_payload` logic in `lowerPtr`. |
| 3179 | if (!Type.fromInterned(child_ty).hasRuntimeBits(zcu)) return .i8; | 3074 | switch (Type.fromInterned(child_ty).classify(zcu)) { |
| | 3075 | .no_possible_value, .fully_comptime => unreachable, |
| | 3076 | .one_possible_value => return .i8, |
| | 3077 | .runtime, .partially_comptime => {}, |
| | 3078 | } |
| 3180 | | 3079 | |
| 3181 | const payload_ty = try o.lowerType(.fromInterned(child_ty)); | 3080 | const payload_ty = try o.lowerType(.fromInterned(child_ty)); |
| 3182 | if (t.optionalReprIsPayload(zcu)) return payload_ty; | 3081 | if (t.optionalReprIsPayload(zcu)) return payload_ty; |
| ... | @@ -3198,8 +3097,13 @@ pub const Object = struct { | ... | @@ -3198,8 +3097,13 @@ pub const Object = struct { |
| 3198 | // Must stay in sync with `codegen.errUnionPayloadOffset`. | 3097 | // Must stay in sync with `codegen.errUnionPayloadOffset`. |
| 3199 | // See logic in `lowerPtr`. | 3098 | // See logic in `lowerPtr`. |
| 3200 | const error_type = try o.errorIntType(); | 3099 | const error_type = try o.errorIntType(); |
| 3201 | if (!Type.fromInterned(error_union_type.payload_type).hasRuntimeBits(zcu)) | 3100 | |
| 3202 | return error_type; | 3101 | switch (Type.fromInterned(error_union_type.payload_type).classify(zcu)) { |
| | 3102 | .fully_comptime => unreachable, |
| | 3103 | .no_possible_value, .one_possible_value => return error_type, |
| | 3104 | .runtime, .partially_comptime => {}, |
| | 3105 | } |
| | 3106 | |
| 3203 | const payload_type = try o.lowerType(.fromInterned(error_union_type.payload_type)); | 3107 | const payload_type = try o.lowerType(.fromInterned(error_union_type.payload_type)); |
| 3204 | | 3108 | |
| 3205 | const payload_align = Type.fromInterned(error_union_type.payload_type).abiAlignment(zcu); | 3109 | const payload_align = Type.fromInterned(error_union_type.payload_type).abiAlignment(zcu); |
| ... | @@ -3245,6 +3149,8 @@ pub const Object = struct { | ... | @@ -3245,6 +3149,8 @@ pub const Object = struct { |
| 3245 | return int_ty; | 3149 | return int_ty; |
| 3246 | } | 3150 | } |
| 3247 | | 3151 | |
| | 3152 | assert(struct_type.size > 0); |
| | 3153 | |
| 3248 | var llvm_field_types: std.ArrayList(Builder.Type) = .empty; | 3154 | var llvm_field_types: std.ArrayList(Builder.Type) = .empty; |
| 3249 | defer llvm_field_types.deinit(o.gpa); | 3155 | defer llvm_field_types.deinit(o.gpa); |
| 3250 | // Although we can estimate how much capacity to add, these cannot be | 3156 | // Although we can estimate how much capacity to add, these cannot be |
| ... | @@ -3311,7 +3217,7 @@ pub const Object = struct { | ... | @@ -3311,7 +3217,7 @@ pub const Object = struct { |
| 3311 | | 3217 | |
| 3312 | comptime assert(struct_layout_version == 2); | 3218 | comptime assert(struct_layout_version == 2); |
| 3313 | var offset: u64 = 0; | 3219 | var offset: u64 = 0; |
| 3314 | var big_align: InternPool.Alignment = .none; | 3220 | var big_align: InternPool.Alignment = .@"1"; |
| 3315 | | 3221 | |
| 3316 | for ( | 3222 | for ( |
| 3317 | tuple_type.types.get(ip), | 3223 | tuple_type.types.get(ip), |
| ... | @@ -3345,6 +3251,7 @@ pub const Object = struct { | ... | @@ -3345,6 +3251,7 @@ pub const Object = struct { |
| 3345 | try o.builder.arrayType(padding_len, .i8), | 3251 | try o.builder.arrayType(padding_len, .i8), |
| 3346 | ); | 3252 | ); |
| 3347 | } | 3253 | } |
| | 3254 | assert(offset > 0); |
| 3348 | return o.builder.structType(.normal, llvm_field_types.items); | 3255 | return o.builder.structType(.normal, llvm_field_types.items); |
| 3349 | }, | 3256 | }, |
| 3350 | .union_type => { | 3257 | .union_type => { |
| ... | @@ -3358,6 +3265,8 @@ pub const Object = struct { | ... | @@ -3358,6 +3265,8 @@ pub const Object = struct { |
| 3358 | return int_ty; | 3265 | return int_ty; |
| 3359 | } | 3266 | } |
| 3360 | | 3267 | |
| | 3268 | assert(union_obj.size > 0); |
| | 3269 | |
| 3361 | const layout = Type.getUnionLayout(union_obj, zcu); | 3270 | const layout = Type.getUnionLayout(union_obj, zcu); |
| 3362 | | 3271 | |
| 3363 | if (layout.payload_size == 0) { | 3272 | if (layout.payload_size == 0) { |
| ... | @@ -3421,15 +3330,9 @@ pub const Object = struct { | ... | @@ -3421,15 +3330,9 @@ pub const Object = struct { |
| 3421 | ); | 3330 | ); |
| 3422 | return ty; | 3331 | return ty; |
| 3423 | }, | 3332 | }, |
| 3424 | .opaque_type => { | 3333 | .opaque_type => unreachable, // no runtime bits |
| 3425 | const gop = try o.type_map.getOrPut(o.gpa, t.toIntern()); | | |
| 3426 | if (!gop.found_existing) { | | |
| 3427 | gop.value_ptr.* = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).toSlice(ip))); | | |
| 3428 | } | | |
| 3429 | return gop.value_ptr.*; | | |
| 3430 | }, | | |
| 3431 | .enum_type => try o.lowerType(t.intTagType(zcu)), | 3334 | .enum_type => try o.lowerType(t.intTagType(zcu)), |
| 3432 | .func_type => |func_type| try o.lowerFnType(func_type), | 3335 | .func_type => |func_type| try o.lowerFnType(t, func_type), |
| 3433 | .error_set_type, .inferred_error_set_type => try o.errorIntType(), | 3336 | .error_set_type, .inferred_error_set_type => try o.errorIntType(), |
| 3434 | // values, not types | 3337 | // values, not types |
| 3435 | .undef, | 3338 | .undef, |
| ... | @@ -3455,10 +3358,13 @@ pub const Object = struct { | ... | @@ -3455,10 +3358,13 @@ pub const Object = struct { |
| 3455 | }; | 3358 | }; |
| 3456 | } | 3359 | } |
| 3457 | | 3360 | |
| 3458 | fn lowerFnType(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { | 3361 | fn lowerFnType(o: *Object, fn_ty: Type, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { |
| 3459 | const zcu = o.zcu; | 3362 | const zcu = o.zcu; |
| 3460 | const ip = &zcu.intern_pool; | 3363 | const ip = &zcu.intern_pool; |
| 3461 | const target = zcu.getTarget(); | 3364 | const target = zcu.getTarget(); |
| | 3365 | |
| | 3366 | assert(fn_ty.fnHasRuntimeBits(zcu)); |
| | 3367 | |
| 3462 | const ret_ty = try lowerFnRetTy(o, fn_info); | 3368 | const ret_ty = try lowerFnRetTy(o, fn_info); |
| 3463 | | 3369 | |
| 3464 | var llvm_params: std.ArrayList(Builder.Type) = .empty; | 3370 | var llvm_params: std.ArrayList(Builder.Type) = .empty; |
| ... | @@ -3526,15 +3432,12 @@ pub const Object = struct { | ... | @@ -3526,15 +3432,12 @@ pub const Object = struct { |
| 3526 | const ip = &zcu.intern_pool; | 3432 | const ip = &zcu.intern_pool; |
| 3527 | const target = zcu.getTarget(); | 3433 | const target = zcu.getTarget(); |
| 3528 | | 3434 | |
| 3529 | const val = Value.fromInterned(arg_val); | 3435 | const val: Value = .fromInterned(arg_val); |
| 3530 | const val_key = ip.indexToKey(val.toIntern()); | 3436 | const val_key = ip.indexToKey(val.toIntern()); |
| 3531 | | 3437 | |
| 3532 | if (val.isUndef(zcu)) { | | |
| 3533 | return o.builder.undefConst(try o.lowerType(.fromInterned(val_key.typeOf()))); | | |
| 3534 | } | | |
| 3535 | | | |
| 3536 | const ty: Type = .fromInterned(val_key.typeOf()); | 3438 | const ty: Type = .fromInterned(val_key.typeOf()); |
| 3537 | ty.assertHasLayout(zcu); | 3439 | ty.assertHasLayout(zcu); |
| | 3440 | assert(ty.hasRuntimeBits(zcu)); |
| 3538 | | 3441 | |
| 3539 | return switch (val_key) { | 3442 | return switch (val_key) { |
| 3540 | .int_type, | 3443 | .int_type, |
| ... | @@ -3555,7 +3458,7 @@ pub const Object = struct { | ... | @@ -3555,7 +3458,7 @@ pub const Object = struct { |
| 3555 | .inferred_error_set_type, | 3458 | .inferred_error_set_type, |
| 3556 | => unreachable, // types, not values | 3459 | => unreachable, // types, not values |
| 3557 | | 3460 | |
| 3558 | .undef => unreachable, // handled above | 3461 | .undef => return o.builder.undefConst(try o.lowerType(ty)), |
| 3559 | .simple_value => |simple_value| switch (simple_value) { | 3462 | .simple_value => |simple_value| switch (simple_value) { |
| 3560 | .void => unreachable, // non-runtime value | 3463 | .void => unreachable, // non-runtime value |
| 3561 | .null => unreachable, // non-runtime value | 3464 | .null => unreachable, // non-runtime value |
| ... | @@ -3565,14 +3468,8 @@ pub const Object = struct { | ... | @@ -3565,14 +3468,8 @@ pub const Object = struct { |
| 3565 | .true => .true, | 3468 | .true => .true, |
| 3566 | }, | 3469 | }, |
| 3567 | .enum_literal => unreachable, // non-runtime value | 3470 | .enum_literal => unreachable, // non-runtime value |
| 3568 | .@"extern" => |@"extern"| { | 3471 | .@"extern" => unreachable, // non-runtime value |
| 3569 | const function_index = try o.resolveLlvmFunction(@"extern".owner_nav); | 3472 | .func => unreachable, // non-runtime value |
| 3570 | return function_index.ptrConst(&o.builder).global.toConst(); | | |
| 3571 | }, | | |
| 3572 | .func => |func| { | | |
| 3573 | const function_index = try o.resolveLlvmFunction(func.owner_nav); | | |
| 3574 | return function_index.ptrConst(&o.builder).global.toConst(); | | |
| 3575 | }, | | |
| 3576 | .int => { | 3473 | .int => { |
| 3577 | var bigint_space: Value.BigIntSpace = undefined; | 3474 | var bigint_space: Value.BigIntSpace = undefined; |
| 3578 | const bigint = val.toBigInt(&bigint_space, zcu); | 3475 | const bigint = val.toBigInt(&bigint_space, zcu); |
| ... | @@ -3815,7 +3712,7 @@ pub const Object = struct { | ... | @@ -3815,7 +3712,7 @@ pub const Object = struct { |
| 3815 | comptime assert(struct_layout_version == 2); | 3712 | comptime assert(struct_layout_version == 2); |
| 3816 | var llvm_index: usize = 0; | 3713 | var llvm_index: usize = 0; |
| 3817 | var offset: u64 = 0; | 3714 | var offset: u64 = 0; |
| 3818 | var big_align: InternPool.Alignment = .none; | 3715 | var big_align: InternPool.Alignment = .@"1"; |
| 3819 | var need_unnamed = false; | 3716 | var need_unnamed = false; |
| 3820 | for ( | 3717 | for ( |
| 3821 | tuple.types.get(ip), | 3718 | tuple.types.get(ip), |
| ... | @@ -4033,7 +3930,7 @@ pub const Object = struct { | ... | @@ -4033,7 +3930,7 @@ pub const Object = struct { |
| 4033 | const offset: u64 = prev_offset + ptr.byte_offset; | 3930 | const offset: u64 = prev_offset + ptr.byte_offset; |
| 4034 | return switch (ptr.base_addr) { | 3931 | return switch (ptr.base_addr) { |
| 4035 | .nav => |nav| { | 3932 | .nav => |nav| { |
| 4036 | const base_ptr = try o.lowerNavRefValue(nav); | 3933 | const base_ptr = try o.lowerNavRef(nav); |
| 4037 | return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{ | 3934 | return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{ |
| 4038 | try o.builder.intConst(.i64, offset), | 3935 | try o.builder.intConst(.i64, offset), |
| 4039 | }); | 3936 | }); |
| ... | @@ -4092,8 +3989,19 @@ pub const Object = struct { | ... | @@ -4092,8 +3989,19 @@ pub const Object = struct { |
| 4092 | }; | 3989 | }; |
| 4093 | } | 3990 | } |
| 4094 | | 3991 | |
| 4095 | /// This logic is very similar to `lowerNavRefValue` but for anonymous declarations. | 3992 | pub fn lowerPtrToVoid( |
| 4096 | /// Maybe the logic could be unified. | 3993 | o: *Object, |
| | 3994 | /// Must not be `.none`. |
| | 3995 | @"align": InternPool.Alignment, |
| | 3996 | @"addrspace": std.builtin.AddressSpace, |
| | 3997 | ) Allocator.Error!Builder.Constant { |
| | 3998 | const addr: u64 = @"align".toByteUnits().?; |
| | 3999 | const llvm_usize = try o.lowerType(.usize); |
| | 4000 | const llvm_addr = try o.builder.intConst(llvm_usize, addr); |
| | 4001 | const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(@"addrspace", o.zcu.getTarget())); |
| | 4002 | return o.builder.castConst(.inttoptr, llvm_addr, llvm_ptr_ty); |
| | 4003 | } |
| | 4004 | |
| 4097 | pub fn lowerUavRef( | 4005 | pub fn lowerUavRef( |
| 4098 | o: *Object, | 4006 | o: *Object, |
| 4099 | uav_val: InternPool.Index, | 4007 | uav_val: InternPool.Index, |
| ... | @@ -4105,6 +4013,8 @@ pub const Object = struct { | ... | @@ -4105,6 +4013,8 @@ pub const Object = struct { |
| 4105 | | 4013 | |
| 4106 | const zcu = o.zcu; | 4014 | const zcu = o.zcu; |
| 4107 | const ip = &zcu.intern_pool; | 4015 | const ip = &zcu.intern_pool; |
| | 4016 | const gpa = zcu.comp.gpa; |
| | 4017 | |
| 4108 | const uav_ty: Type = .fromInterned(ip.typeOf(uav_val)); | 4018 | const uav_ty: Type = .fromInterned(ip.typeOf(uav_val)); |
| 4109 | | 4019 | |
| 4110 | switch (ip.indexToKey(uav_val)) { | 4020 | switch (ip.indexToKey(uav_val)) { |
| ... | @@ -4118,63 +4028,63 @@ pub const Object = struct { | ... | @@ -4118,63 +4028,63 @@ pub const Object = struct { |
| 4118 | } | 4028 | } |
| 4119 | | 4029 | |
| 4120 | const llvm_addrspace = toLlvmAddressSpace(@"addrspace", zcu.getTarget()); | 4030 | const llvm_addrspace = toLlvmAddressSpace(@"addrspace", zcu.getTarget()); |
| 4121 | const llvm_global = (try o.resolveGlobalUav(uav_val, llvm_addrspace, @"align")).ptrConst(&o.builder).global; | | |
| 4122 | | 4031 | |
| 4123 | return o.builder.convConst( | 4032 | const gop = try o.uav_map.getOrPut(gpa, .{ .val = uav_val, .@"addrspace" = @"addrspace" }); |
| 4124 | llvm_global.toConst(), | 4033 | if (gop.found_existing) { |
| 4125 | try o.builder.ptrType(llvm_addrspace), | 4034 | // Keep the greater of the two alignments. |
| 4126 | ); | 4035 | const llvm_variable = gop.value_ptr.*; |
| | 4036 | const old_align: InternPool.Alignment = .fromLlvm(llvm_variable.getAlignment(&o.builder)); |
| | 4037 | llvm_variable.setAlignment(old_align.maxStrict(@"align").toLlvm(), &o.builder); |
| | 4038 | return llvm_variable.ptrConst(&o.builder).global.toConst(); |
| | 4039 | } |
| | 4040 | errdefer assert(o.uav_map.remove(.{ .val = uav_val, .@"addrspace" = @"addrspace" })); |
| | 4041 | |
| | 4042 | const llvm_ty = try o.lowerType(uav_ty); |
| | 4043 | const llvm_name = try o.builder.strtabStringFmt("__anon_{d}", .{@intFromEnum(uav_val)}); |
| | 4044 | const llvm_variable = try o.builder.addVariable(llvm_name, llvm_ty, llvm_addrspace); |
| | 4045 | gop.value_ptr.* = llvm_variable; |
| | 4046 | try llvm_variable.setInitializer(try o.lowerValue(uav_val), &o.builder); |
| | 4047 | llvm_variable.setMutability(.constant, &o.builder); |
| | 4048 | llvm_variable.setAlignment(@"align".toLlvm(), &o.builder); |
| | 4049 | const llvm_global = llvm_variable.ptrConst(&o.builder).global; |
| | 4050 | llvm_global.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); |
| | 4051 | llvm_global.setUnnamedAddr(.unnamed_addr, &o.builder); |
| | 4052 | return llvm_global.toConst(); |
| 4127 | } | 4053 | } |
| 4128 | | 4054 | |
| 4129 | pub fn lowerNavRefValue(o: *Object, nav_index: InternPool.Nav.Index) Allocator.Error!Builder.Constant { | 4055 | pub fn lowerNavRef(o: *Object, nav_id: InternPool.Nav.Index) Allocator.Error!Builder.Constant { |
| 4130 | const zcu = o.zcu; | 4056 | const zcu = o.zcu; |
| 4131 | const ip = &zcu.intern_pool; | 4057 | const ip = &zcu.intern_pool; |
| | 4058 | const gpa = zcu.comp.gpa; |
| 4132 | | 4059 | |
| 4133 | const nav = ip.getNav(nav_index); | 4060 | const nav = ip.getNav(nav_id); |
| 4134 | | | |
| 4135 | const nav_ty: Type = .fromInterned(nav.resolved.?.type); | 4061 | const nav_ty: Type = .fromInterned(nav.resolved.?.type); |
| 4136 | | 4062 | if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and nav.getExtern(ip) == null) { |
| 4137 | if (nav.getExtern(ip) == null and !nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { | 4063 | const nav_align = switch (nav.resolved.?.@"align") { |
| 4138 | return o.lowerPtrToVoid(nav.resolved.?.@"align", nav.resolved.?.@"addrspace"); | 4064 | .none => nav_ty.abiAlignment(zcu), |
| | 4065 | else => |a| a, |
| | 4066 | }; |
| | 4067 | return o.lowerPtrToVoid(nav_align, nav.resolved.?.@"addrspace"); |
| 4139 | } | 4068 | } |
| 4140 | | 4069 | |
| 4141 | const llvm_global = if (nav_ty.zigTypeTag(zcu) == .@"fn") | 4070 | const gop = try o.nav_map.getOrPut(gpa, nav_id); |
| 4142 | (try o.resolveLlvmFunction(nav_index)).ptrConst(&o.builder).global | 4071 | if (!gop.found_existing) { |
| 4143 | else | 4072 | errdefer assert(o.nav_map.remove(nav_id)); |
| 4144 | (try o.resolveGlobalNav(nav_index)).ptrConst(&o.builder).global; | 4073 | // The NAV hasn't been lowered yet, so generate a placeholder global whose details will |
| | 4074 | // be filled in later. |
| | 4075 | const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip)); |
| | 4076 | gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{ |
| | 4077 | .type = .void, // placeholder; populated by `updateNav`/`updateFunc` |
| | 4078 | .kind = .{ .alias = .none }, // placeholder; populated by `updateNav`/`updateFunc` |
| | 4079 | }); |
| | 4080 | } |
| | 4081 | const llvm_global = gop.value_ptr.*; |
| 4145 | | 4082 | |
| 4146 | return try o.builder.convConst( | 4083 | // We need to make sure the global's address space is up to date, because that affects the |
| 4147 | llvm_global.toConst(), | 4084 | // type of a pointer to this global. But everything else about the global will be populated |
| 4148 | try o.builder.ptrType(toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget())), | 4085 | // by `updateNav` or `updateFunc`. |
| 4149 | ); | 4086 | llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget()); |
| 4150 | } | 4087 | return llvm_global.toConst(); |
| 4151 | | | |
| 4152 | pub fn lowerPtrToVoid( | | |
| 4153 | o: *Object, | | |
| 4154 | @"align": InternPool.Alignment, | | |
| 4155 | @"addrspace": std.builtin.AddressSpace, | | |
| 4156 | ) Allocator.Error!Builder.Constant { | | |
| 4157 | const target = o.zcu.getTarget(); | | |
| 4158 | // Even though we are pointing at something which has zero bits (e.g. `void`), | | |
| 4159 | // Pointers are defined to have bits. So we must return something here. | | |
| 4160 | // The value cannot be undefined, because we use the `nonnull` annotation | | |
| 4161 | // for non-optional pointers. We also need to respect the alignment, even though | | |
| 4162 | // the address will never be dereferenced. | | |
| 4163 | const int: u64 = @"align".toByteUnits() orelse | | |
| 4164 | // Note that these 0xaa values are appropriate even in release-optimized builds | | |
| 4165 | // because we need a well-defined value that is not null, and LLVM does not | | |
| 4166 | // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR | | |
| 4167 | // instruction is followed by a `wrap_optional`, it will return this value | | |
| 4168 | // verbatim, and the result should test as non-null. | | |
| 4169 | switch (target.ptrBitWidth()) { | | |
| 4170 | 16 => 0xaaaa, | | |
| 4171 | 32 => 0xaaaaaaaa, | | |
| 4172 | 64 => 0xaaaaaaaa_aaaaaaaa, | | |
| 4173 | else => unreachable, | | |
| 4174 | }; | | |
| 4175 | const llvm_usize = try o.lowerType(.usize); | | |
| 4176 | const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(@"addrspace", target)); | | |
| 4177 | return o.builder.castConst(.inttoptr, try o.builder.intConst(llvm_usize, int), llvm_ptr_ty); | | |
| 4178 | } | 4088 | } |
| 4179 | | 4089 | |
| 4180 | pub fn addByValParamAttrs( | 4090 | pub fn addByValParamAttrs( |
| ... | @@ -4243,13 +4153,14 @@ pub const Object = struct { | ... | @@ -4243,13 +4153,14 @@ pub const Object = struct { |
| 4243 | const name = try o.builder.strtabString("__zig_error_name_table"); | 4153 | const name = try o.builder.strtabString("__zig_error_name_table"); |
| 4244 | // TODO: Address space | 4154 | // TODO: Address space |
| 4245 | const variable_index = try o.builder.addVariable(name, .ptr, .default); | 4155 | const variable_index = try o.builder.addVariable(name, .ptr, .default); |
| 4246 | variable_index.setLinkage(.private, &o.builder); | | |
| 4247 | variable_index.setMutability(.constant, &o.builder); | 4156 | variable_index.setMutability(.constant, &o.builder); |
| 4248 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); | | |
| 4249 | variable_index.setAlignment( | 4157 | variable_index.setAlignment( |
| 4250 | Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(), | 4158 | Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(), |
| 4251 | &o.builder, | 4159 | &o.builder, |
| 4252 | ); | 4160 | ); |
| | 4161 | const global_index = variable_index.ptrConst(&o.builder).global; |
| | 4162 | global_index.setLinkage(.private, &o.builder); |
| | 4163 | global_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 4253 | | 4164 | |
| 4254 | o.error_name_table = variable_index; | 4165 | o.error_name_table = variable_index; |
| 4255 | return variable_index; | 4166 | return variable_index; |
| ... | @@ -4261,10 +4172,11 @@ pub const Object = struct { | ... | @@ -4261,10 +4172,11 @@ pub const Object = struct { |
| 4261 | const llvm_err_int_ty = try o.errorIntType(); | 4172 | const llvm_err_int_ty = try o.errorIntType(); |
| 4262 | const name = try builder.strtabString("__zig_errors_len"); | 4173 | const name = try builder.strtabString("__zig_errors_len"); |
| 4263 | const variable_index = try builder.addVariable(name, llvm_err_int_ty, .default); | 4174 | const variable_index = try builder.addVariable(name, llvm_err_int_ty, .default); |
| 4264 | variable_index.setLinkage(.private, builder); | | |
| 4265 | variable_index.setMutability(.constant, builder); | 4175 | variable_index.setMutability(.constant, builder); |
| 4266 | variable_index.setUnnamedAddr(.unnamed_addr, builder); | | |
| 4267 | variable_index.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder); | 4176 | variable_index.setAlignment(Type.errorAbiAlignment(o.zcu).toLlvm(), builder); |
| | 4177 | const global_index = variable_index.ptrConst(&o.builder).global; |
| | 4178 | global_index.setLinkage(.private, builder); |
| | 4179 | global_index.setUnnamedAddr(.unnamed_addr, builder); |
| 4268 | o.errors_len_variable = variable_index; | 4180 | o.errors_len_variable = variable_index; |
| 4269 | } | 4181 | } |
| 4270 | return o.errors_len_variable; | 4182 | return o.errors_len_variable; |
| ... | @@ -4332,16 +4244,16 @@ pub const Object = struct { | ... | @@ -4332,16 +4244,16 @@ pub const Object = struct { |
| 4332 | for (0..loaded_enum.field_names.len) |field_index| { | 4244 | for (0..loaded_enum.field_names.len) |field_index| { |
| 4333 | const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip)); | 4245 | const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip)); |
| 4334 | const name_init = try o.builder.stringConst(name); | 4246 | const name_init = try o.builder.stringConst(name); |
| 4335 | const name_variable_index = | 4247 | const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); |
| 4336 | try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); | | |
| 4337 | try name_variable_index.setInitializer(name_init, &o.builder); | 4248 | try name_variable_index.setInitializer(name_init, &o.builder); |
| 4338 | name_variable_index.setLinkage(.private, &o.builder); | | |
| 4339 | name_variable_index.setMutability(.constant, &o.builder); | 4249 | name_variable_index.setMutability(.constant, &o.builder); |
| 4340 | name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); | | |
| 4341 | name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); | 4250 | name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); |
| | 4251 | const name_global_index = name_variable_index.ptrConst(&o.builder).global; |
| | 4252 | name_global_index.setLinkage(.private, &o.builder); |
| | 4253 | name_global_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 4342 | | 4254 | |
| 4343 | const name_val = try o.builder.structValue(llvm_ret_ty, &.{ | 4255 | const name_val = try o.builder.structValue(llvm_ret_ty, &.{ |
| 4344 | name_variable_index.toConst(&o.builder), | 4256 | name_global_index.toConst(), |
| 4345 | try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1), | 4257 | try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1), |
| 4346 | }); | 4258 | }); |
| 4347 | | 4259 | |