| ... | ... | @@ -550,17 +550,13 @@ pub const Object = struct { |
| 550 | 550 | debug_anyerror_fwd_ref: Builder.Metadata.Optional, |
| 551 | 551 | |
| 552 | 552 | zcu: *Zcu, |
| 553 | | /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function, |
| 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. |
| 553 | /// Maps a `Nav` to the corresponding LLVM global. |
| 561 | 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. |
| 563 | | uav_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Global.Index), |
| 555 | /// Same as `nav_map` but for UAVs (which are always global constants). |
| 556 | uav_map: std.AutoHashMapUnmanaged(struct { |
| 557 | val: InternPool.Index, |
| 558 | @"addrspace": std.builtin.AddressSpace, |
| 559 | }, Builder.Variable.Index), |
| 564 | 560 | /// Maps enum types to their corresponding LLVM functions for implementing the `tag_name` instruction. |
| 565 | 561 | enum_tag_name_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Function.Index), |
| 566 | 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 | 713 | for (llvm_errors[1..], error_name_list) |*llvm_error, name| { |
| 718 | 714 | const name_string = try o.builder.stringNull(name.toSlice(ip)); |
| 719 | 715 | const name_init = try o.builder.stringConst(name_string); |
| 720 | | const name_variable_index = |
| 721 | | try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); |
| 716 | const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); |
| 722 | 717 | try name_variable_index.setInitializer(name_init, &o.builder); |
| 723 | | name_variable_index.setLinkage(.private, &o.builder); |
| 724 | 718 | name_variable_index.setMutability(.constant, &o.builder); |
| 725 | | name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 726 | 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 | 724 | llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{ |
| 729 | 725 | name_variable_index.toConst(&o.builder), |
| ... | ... | @@ -790,9 +786,9 @@ pub const Object = struct { |
| 790 | 786 | array_llvm_ty, |
| 791 | 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 | 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 | 794 | if (!o.builder.strip) { |
| ... | ... | @@ -1140,6 +1136,7 @@ pub const Object = struct { |
| 1140 | 1136 | ) Zcu.CodegenFailError!void { |
| 1141 | 1137 | const zcu = o.zcu; |
| 1142 | 1138 | const comp = zcu.comp; |
| 1139 | const gpa = comp.gpa; |
| 1143 | 1140 | const ip = &zcu.intern_pool; |
| 1144 | 1141 | const func = zcu.funcInfo(func_index); |
| 1145 | 1142 | const nav = ip.getNav(func.owner_nav); |
| ... | ... | @@ -1149,9 +1146,42 @@ pub const Object = struct { |
| 1149 | 1146 | const fn_info = zcu.typeToFunc(fn_ty).?; |
| 1150 | 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 | 1185 | defer attributes.deinit(&o.builder); |
| 1156 | 1186 | |
| 1157 | 1187 | const func_analysis = func.analysisUnordered(ip); |
| ... | ... | @@ -1221,47 +1251,41 @@ pub const Object = struct { |
| 1221 | 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 | 1254 | var deinit_wip = true; |
| 1228 | 1255 | var wip = try Builder.WipFunction.init(&o.builder, .{ |
| 1229 | | .function = function_index, |
| 1256 | .function = llvm_function, |
| 1230 | 1257 | .strip = owner_mod.strip, |
| 1231 | 1258 | }); |
| 1232 | 1259 | defer if (deinit_wip) wip.deinit(); |
| 1233 | 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 | 1262 | if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { |
| 1244 | 1263 | .signed => try attributes.addRetAttr(.signext, &o.builder), |
| 1245 | 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 | 1267 | // This is the list of args we will use that correspond directly to the AIR arg |
| 1257 | 1268 | // instructions. Depending on the calling convention, this list is not necessarily |
| 1258 | 1269 | // a bijection with the actual LLVM parameters of the function. |
| 1259 | | const gpa = o.gpa; |
| 1260 | 1270 | var args: std.ArrayList(Builder.Value) = .empty; |
| 1261 | 1271 | defer args.deinit(gpa); |
| 1262 | 1272 | |
| 1263 | | { |
| 1273 | const ret_ptr: Builder.Value, const err_ret_trace: Builder.Value = implicit_args: { |
| 1264 | 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 | 1289 | while (try it.next()) |lowering| { |
| 1266 | 1290 | try args.ensureUnusedCapacity(gpa, 1); |
| 1267 | 1291 | |
| ... | ... | @@ -1271,7 +1295,7 @@ pub const Object = struct { |
| 1271 | 1295 | assert(!it.byval_attr); |
| 1272 | 1296 | const param_index = it.zig_index - 1; |
| 1273 | 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 | 1300 | if (isByRef(param_ty, zcu)) { |
| 1277 | 1301 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| ... | ... | @@ -1281,146 +1305,116 @@ pub const Object = struct { |
| 1281 | 1305 | args.appendAssumeCapacity(arg_ptr); |
| 1282 | 1306 | } else { |
| 1283 | 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 | 1310 | .byref => { |
| 1290 | | 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); |
| 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; |
| 1311 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1312 | const param = wip.arg(it.llvm_index - 1); |
| 1297 | 1313 | |
| 1298 | 1314 | if (isByRef(param_ty, zcu)) { |
| 1299 | 1315 | args.appendAssumeCapacity(param); |
| 1300 | 1316 | } else { |
| 1317 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1318 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1301 | 1319 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); |
| 1302 | 1320 | } |
| 1303 | 1321 | }, |
| 1304 | 1322 | .byref_mut => { |
| 1305 | | 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); |
| 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; |
| 1323 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1324 | const param = wip.arg(it.llvm_index - 1); |
| 1312 | 1325 | |
| 1313 | 1326 | if (isByRef(param_ty, zcu)) { |
| 1314 | 1327 | args.appendAssumeCapacity(param); |
| 1315 | 1328 | } else { |
| 1329 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1330 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1316 | 1331 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); |
| 1317 | 1332 | } |
| 1318 | 1333 | }, |
| 1319 | 1334 | .abi_sized_int => { |
| 1320 | 1335 | assert(!it.byval_attr); |
| 1321 | | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1322 | | const param = wip.arg(llvm_arg_i); |
| 1323 | | llvm_arg_i += 1; |
| 1336 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1337 | const param = wip.arg(it.llvm_index - 1); |
| 1324 | 1338 | |
| 1325 | 1339 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1326 | 1340 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1327 | 1341 | const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target); |
| 1328 | 1342 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1329 | 1343 | |
| 1330 | | args.appendAssumeCapacity(if (isByRef(param_ty, zcu)) |
| 1331 | | arg_ptr |
| 1332 | | else |
| 1333 | | try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); |
| 1344 | if (isByRef(param_ty, zcu)) { |
| 1345 | args.appendAssumeCapacity(arg_ptr); |
| 1346 | } else { |
| 1347 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); |
| 1348 | } |
| 1334 | 1349 | }, |
| 1335 | 1350 | .slice => { |
| 1336 | 1351 | assert(!it.byval_attr); |
| 1337 | | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1338 | | const ptr_info = param_ty.ptrInfo(zcu); |
| 1339 | | |
| 1340 | | if (std.math.cast(u5, it.zig_index - 1)) |i| { |
| 1341 | | if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) { |
| 1342 | | try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder); |
| 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 }, ""), |
| 1352 | const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1353 | assert(!isByRef(param_ty, zcu)); |
| 1354 | const slice_val = try wip.buildAggregate( |
| 1355 | try o.lowerType(param_ty), |
| 1356 | &.{ wip.arg(it.llvm_index - 2), wip.arg(it.llvm_index - 1) }, |
| 1357 | "", |
| 1367 | 1358 | ); |
| 1359 | args.appendAssumeCapacity(slice_val); |
| 1368 | 1360 | }, |
| 1369 | 1361 | .multiple_llvm_types => { |
| 1370 | 1362 | assert(!it.byval_attr); |
| 1371 | 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 | 1365 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1374 | 1366 | const param_alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1375 | 1367 | const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, param_alignment, target); |
| 1376 | 1368 | const llvm_ty = try o.builder.structType(.normal, field_types); |
| 1377 | | for (0..field_types.len) |field_i| { |
| 1378 | | const param = wip.arg(llvm_arg_i); |
| 1379 | | llvm_arg_i += 1; |
| 1369 | const llvm_args_start = it.llvm_index - field_types.len; |
| 1370 | for (0..field_types.len, llvm_args_start..) |field_i, llvm_arg_index| { |
| 1371 | const param = wip.arg(@intCast(llvm_arg_index)); |
| 1380 | 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 | 1374 | _ = try wip.store(.normal, param, field_ptr, alignment); |
| 1383 | 1375 | } |
| 1384 | 1376 | |
| 1385 | | const is_by_ref = isByRef(param_ty, zcu); |
| 1386 | | args.appendAssumeCapacity(if (is_by_ref) |
| 1387 | | arg_ptr |
| 1388 | | else |
| 1389 | | try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, "")); |
| 1377 | if (isByRef(param_ty, zcu)) { |
| 1378 | args.appendAssumeCapacity(arg_ptr); |
| 1379 | } else { |
| 1380 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, "")); |
| 1381 | } |
| 1390 | 1382 | }, |
| 1391 | 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 | 1385 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1394 | | const param = wip.arg(llvm_arg_i); |
| 1395 | | llvm_arg_i += 1; |
| 1386 | const param = wip.arg(it.llvm_index - 1); |
| 1396 | 1387 | |
| 1397 | 1388 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1398 | 1389 | const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target); |
| 1399 | 1390 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1400 | 1391 | |
| 1401 | | args.appendAssumeCapacity(if (isByRef(param_ty, zcu)) |
| 1402 | | arg_ptr |
| 1403 | | else |
| 1404 | | try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); |
| 1392 | if (isByRef(param_ty, zcu)) { |
| 1393 | args.appendAssumeCapacity(arg_ptr); |
| 1394 | } else { |
| 1395 | args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); |
| 1396 | } |
| 1405 | 1397 | }, |
| 1406 | 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 | 1400 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1409 | | const param = wip.arg(llvm_arg_i); |
| 1410 | | llvm_arg_i += 1; |
| 1401 | const param = wip.arg(it.llvm_index - 1); |
| 1411 | 1402 | |
| 1412 | 1403 | const alignment = param_ty.abiAlignment(zcu).toLlvm(); |
| 1413 | 1404 | const arg_ptr = try buildAllocaInner(&wip, param.typeOfWip(&wip), alignment, target); |
| 1414 | 1405 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1415 | 1406 | |
| 1416 | | args.appendAssumeCapacity(if (isByRef(param_ty, zcu)) |
| 1417 | | arg_ptr |
| 1418 | | else |
| 1419 | | try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); |
| 1407 | if (isByRef(param_ty, zcu)) { |
| 1408 | args.appendAssumeCapacity(arg_ptr); |
| 1409 | } else { |
| 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 | 1419 | const file, const subprogram = if (!wip.strip) debug_info: { |
| 1426 | 1420 | const file = try o.getDebugFile(file_scope); |
| ... | ... | @@ -1432,7 +1426,7 @@ pub const Object = struct { |
| 1432 | 1426 | const subprogram = try o.builder.debugSubprogram( |
| 1433 | 1427 | file, |
| 1434 | 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 | 1430 | line_number, |
| 1437 | 1431 | line_number + func.lbrace_line, |
| 1438 | 1432 | debug_decl_type, |
| ... | ... | @@ -1449,7 +1443,7 @@ pub const Object = struct { |
| 1449 | 1443 | }, |
| 1450 | 1444 | o.debug_compile_unit.unwrap().?, |
| 1451 | 1445 | ); |
| 1452 | | function_index.setSubprogram(subprogram, &o.builder); |
| 1446 | llvm_function.setSubprogram(subprogram, &o.builder); |
| 1453 | 1447 | break :debug_info .{ file, subprogram }; |
| 1454 | 1448 | } else .{undefined} ** 2; |
| 1455 | 1449 | |
| ... | ... | @@ -1466,7 +1460,7 @@ pub const Object = struct { |
| 1466 | 1460 | const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len}); |
| 1467 | 1461 | const counters_variable = try o.builder.addVariable(anon_name, .void, .default); |
| 1468 | 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 | 1464 | counters_variable.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); |
| 1471 | 1465 | |
| 1472 | 1466 | if (target.ofmt == .macho) { |
| ... | ... | @@ -1524,7 +1518,7 @@ pub const Object = struct { |
| 1524 | 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 | 1523 | if (fg.fuzz) |*f| { |
| 1530 | 1524 | { |
| ... | ... | @@ -1539,158 +1533,162 @@ pub const Object = struct { |
| 1539 | 1533 | // Due to error "members of llvm.compiler.used must be named", this global needs a name. |
| 1540 | 1534 | const anon_name = try o.builder.strtabStringFmt("__sancov_gen_.{d}", .{o.used.items.len}); |
| 1541 | 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)); |
| 1543 | | pcs_variable.setLinkage(.private, &o.builder); |
| 1536 | try pcs_variable.setInitializer(init_val, &o.builder); |
| 1544 | 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 | 1542 | pcs_variable.setAlignment(Type.usize.abiAlignment(zcu).toLlvm(), &o.builder); |
| 1546 | | if (target.ofmt == .macho) { |
| 1547 | | pcs_variable.setSection(try o.builder.string("__DATA,__sancov_pcs1"), &o.builder); |
| 1548 | | } else { |
| 1549 | | pcs_variable.setSection(try o.builder.string("__sancov_pcs1"), &o.builder); |
| 1550 | | } |
| 1551 | | try pcs_variable.setInitializer(init_val, &o.builder); |
| 1543 | const pcs_global = pcs_variable.ptrConst(&o.builder).global; |
| 1544 | pcs_global.setLinkage(.private, &o.builder); |
| 1545 | try o.used.append(gpa, pcs_global.toConst()); |
| 1552 | 1546 | } |
| 1553 | 1547 | |
| 1554 | 1548 | try fg.wip.finish(); |
| 1555 | 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 | 1553 | const zcu = o.zcu; |
| 1560 | 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 | 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)) { |
| 1566 | | else => .{ .none, .internal, .default, false, resolved.value, nav_index }, |
| 1567 | | .@"extern" => |e| .{ e.lib_name, e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import, .none, e.owner_nav }, |
| 1561 | const opt_extern: ?InternPool.Key.Extern = switch (ip.indexToKey(resolved.value)) { |
| 1562 | .@"extern" => |@"extern"| @"extern", |
| 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())) { |
| 1572 | | const function_index = try o.resolveLlvmFunction(owner_nav); |
| 1573 | | // Add parameter attributes which weren't set by `resolveLlvmFunction` |
| 1574 | | const fn_info = zcu.typeToFunc(ty).?; |
| 1575 | | var attributes = try function_index.ptrConst(&o.builder).attributes.toWip(&o.builder); |
| 1576 | | defer attributes.deinit(&o.builder); |
| 1577 | | var it = iterateParamTypes(o, fn_info); |
| 1578 | | if (firstParamSRet(fn_info, zcu, zcu.getTarget())) it.llvm_index += 1; |
| 1579 | | if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) it.llvm_index += 1; |
| 1580 | | while (try it.next()) |lowering| switch (lowering) { |
| 1581 | | .byval => { |
| 1582 | | const param_index = it.zig_index - 1; |
| 1583 | | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]); |
| 1584 | | if (!isByRef(param_ty, zcu)) { |
| 1585 | | try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1); |
| 1583 | const gop = try o.nav_map.getOrPut(gpa, nav_id); |
| 1584 | if (!gop.found_existing) { |
| 1585 | errdefer assert(o.nav_map.remove(nav_id)); |
| 1586 | // First time lowering this NAV! Create a fresh global. |
| 1587 | const llvm_name = try o.builder.strtabString(nav.fqn.toSlice(ip)); |
| 1588 | gop.value_ptr.* = try o.builder.addGlobal(llvm_name, .{ |
| 1589 | .type = .void, // placeholder; populated below |
| 1590 | .kind = .{ .alias = .none }, // placeholder; populated below |
| 1591 | }); |
| 1592 | } |
| 1593 | const llvm_global = gop.value_ptr.*; |
| 1594 | |
| 1595 | llvm_global.ptr(&o.builder).type = llvm_ty; |
| 1596 | llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(resolved.@"addrspace", zcu.getTarget()); |
| 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 | | }, |
| 1588 | | .byref => { |
| 1589 | | const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); |
| 1590 | | const param_llvm_ty = try o.lowerType(param_ty); |
| 1591 | | const alignment = param_ty.abiAlignment(zcu); |
| 1592 | | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty); |
| 1593 | | }, |
| 1594 | | .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), |
| 1595 | | // No attributes needed for these. |
| 1596 | | .no_bits, |
| 1597 | | .abi_sized_int, |
| 1598 | | .multiple_llvm_types, |
| 1599 | | .float_array, |
| 1600 | | .i32_array, |
| 1601 | | .i64_array, |
| 1602 | | => continue, |
| 1603 | | |
| 1604 | | .slice => unreachable, // extern functions do not support slice types. |
| 1607 | } |
| 1608 | break :name try o.builder.strtabString(name_slice); |
| 1609 | }; |
| 1610 | if (o.builder.getGlobal(name)) |other_global| { |
| 1611 | if (other_global != llvm_global) { |
| 1612 | // Another global already has this name; just use it in place of this global. |
| 1613 | try llvm_global.replace(other_global, &o.builder); |
| 1614 | return; |
| 1615 | } |
| 1616 | } |
| 1617 | try llvm_global.rename(name, &o.builder); |
| 1618 | llvm_global.ptr(&o.builder).unnamed_addr = .default; |
| 1619 | llvm_global.ptr(&o.builder).dll_storage_class = switch (@"extern".is_dll_import) { |
| 1620 | true => .dllimport, |
| 1621 | false => .default, |
| 1622 | }; |
| 1623 | llvm_global.ptr(&o.builder).linkage = switch (@"extern".linkage) { |
| 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 | 1630 | } else { |
| 1608 | | const variable_index = try o.resolveGlobalNav(nav_index); |
| 1609 | | variable_index.setAlignment(zcu.navAlignment(nav_index).toLlvm(), &o.builder); |
| 1610 | | if (resolved.@"linksection".toSlice(ip)) |section| |
| 1611 | | variable_index.setSection(try o.builder.string(section), &o.builder); |
| 1612 | | if (resolved.@"const") variable_index.setMutability(.constant, &o.builder); |
| 1613 | | try variable_index.setInitializer(switch (init_val) { |
| 1614 | | .none => .no_init, |
| 1615 | | else => try o.lowerValue(init_val), |
| 1616 | | }, &o.builder); |
| 1617 | | variable_index.setVisibility(visibility, &o.builder); |
| 1631 | llvm_global.ptr(&o.builder).linkage = if (o.builder.strip) .private else .internal; |
| 1632 | llvm_global.ptr(&o.builder).visibility = .default; |
| 1633 | llvm_global.ptr(&o.builder).dll_storage_class = .default; |
| 1634 | llvm_global.ptr(&o.builder).unnamed_addr = .unnamed_addr; |
| 1635 | } |
| 1636 | |
| 1637 | const llvm_align = switch (resolved.@"align") { |
| 1638 | .none => nav_ty.abiAlignment(zcu).toLlvm(), |
| 1639 | else => |a| a.toLlvm(), |
| 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 | 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 | 1673 | if (!mod.strip) { |
| 1627 | 1674 | const debug_file = try o.getDebugFile(file_scope); |
| 1628 | | |
| 1629 | | const debug_global_var = try o.builder.debugGlobalVar( |
| 1630 | | try o.builder.metadataString(nav.name.toSlice(ip)), // Name |
| 1631 | | try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name |
| 1632 | | debug_file, // File |
| 1633 | | debug_file, // Scope |
| 1634 | | line_number, |
| 1635 | | try o.getDebugType(pt, ty), |
| 1636 | | variable_index, |
| 1637 | | .{ .local = linkage == .internal }, |
| 1638 | | ); |
| 1639 | | |
| 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, |
| 1675 | const debug_global_var_expr = try o.builder.debugGlobalVarExpression( |
| 1676 | try o.builder.debugGlobalVar( |
| 1677 | try o.builder.metadataString(nav.name.toSlice(ip)), // Name |
| 1678 | try o.builder.metadataString(nav.fqn.toSlice(ip)), // Linkage name |
| 1679 | debug_file, // File |
| 1680 | debug_file, // Scope |
| 1681 | zcu.navSrcLine(nav_id) + 1, |
| 1682 | try o.getDebugType(pt, nav_ty), |
| 1683 | llvm_variable, |
| 1684 | .{ .local = llvm_global.ptrConst(&o.builder).linkage == .internal }, |
| 1685 | ), |
| 1686 | try o.builder.debugExpression(&.{}), |
| 1645 | 1687 | ); |
| 1646 | | |
| 1647 | | variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder); |
| 1648 | | try o.debug_globals.append(o.gpa, debug_global_var_expression); |
| 1688 | llvm_variable.setGlobalVariableExpression(debug_global_var_expr, &o.builder); |
| 1689 | try o.debug_globals.append(o.gpa, debug_global_var_expr); |
| 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 | 1694 | fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void { |
| ... | ... | @@ -1698,18 +1696,43 @@ pub const Object = struct { |
| 1698 | 1696 | } |
| 1699 | 1697 | |
| 1700 | 1698 | pub fn updateExports( |
| 1701 | | self: *Object, |
| 1699 | o: *Object, |
| 1702 | 1700 | exported: Zcu.Exported, |
| 1703 | 1701 | export_indices: []const Zcu.Export.Index, |
| 1704 | 1702 | ) link.File.UpdateExportsError!void { |
| 1705 | | const zcu = self.zcu; |
| 1706 | | const nav_index = switch (exported) { |
| 1707 | | .nav => |nav| nav, |
| 1708 | | .uav => |uav| return updateExportedValue(self, uav, export_indices), |
| 1709 | | }; |
| 1703 | const zcu = o.zcu; |
| 1710 | 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 | 1734 | const comp = zcu.comp; |
| 1735 | const ip = &zcu.intern_pool; |
| 1713 | 1736 | |
| 1714 | 1737 | // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use. |
| 1715 | 1738 | coff_export_flags: { |
| ... | ... | @@ -1719,7 +1742,7 @@ pub const Object = struct { |
| 1719 | 1742 | .elf, .wasm => break :coff_export_flags, |
| 1720 | 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 | 1746 | const flags = &coff.lld_export_flags; |
| 1724 | 1747 | for (export_indices) |export_index| { |
| 1725 | 1748 | const name = export_index.ptr(zcu).opts.name; |
| ... | ... | @@ -1732,152 +1755,88 @@ pub const Object = struct { |
| 1732 | 1755 | } |
| 1733 | 1756 | } |
| 1734 | 1757 | |
| 1735 | | if (export_indices.len != 0) { |
| 1736 | | return updateExportedGlobal(self, zcu, global_index, export_indices); |
| 1737 | | } else { |
| 1738 | | const fqn = try self.builder.strtabString(ip.getNav(nav_index).fqn.toSlice(ip)); |
| 1739 | | try global_index.rename(fqn, &self.builder); |
| 1740 | | global_index.setLinkage(if (self.builder.strip) .private else .internal, &self.builder); |
| 1741 | | if (comp.config.dll_export_fns) |
| 1742 | | global_index.setDllStorageClass(.default, &self.builder); |
| 1743 | | global_index.setUnnamedAddr(.unnamed_addr, &self.builder); |
| 1758 | // If the first export specifies a linksection, set the exported variable's section to that |
| 1759 | // one. This is kind of a hack because `std.builtin.ExportOptions.section` doesn't actually |
| 1760 | // make much sense: the linksection should be associated with the declaration itself rather |
| 1761 | // than some particular symbol it is exported as! |
| 1762 | if (export_indices[0].ptr(zcu).opts.section.toSlice(ip)) |section_slice| { |
| 1763 | const variable = &global_index.ptrConst(&o.builder).kind.variable; |
| 1764 | variable.setSection(try o.builder.string(section_slice), &o.builder); |
| 1744 | 1765 | } |
| 1745 | | } |
| 1746 | 1766 | |
| 1747 | | fn updateExportedValue( |
| 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 | | } |
| 1767 | const llvm_global_ty = global_index.typeOf(&o.builder); |
| 1778 | 1768 | |
| 1779 | | fn updateExportedGlobal( |
| 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 | | } |
| 1769 | // All exports are represented as aliases to the original global. |
| 1811 | 1770 | |
| 1812 | | global_index.setUnnamedAddr(.default, &o.builder); |
| 1813 | | if (comp.config.dll_export_fns and first_export.opts.visibility != .hidden) |
| 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 | | }; |
| 1771 | // TODO: we currently do not delete old exports. To do that we'll need to track which |
| 1772 | // globals actually *are* exports. |
| 1836 | 1773 | |
| 1837 | | // If a Decl is exported more than one time (which is rare), |
| 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| { |
| 1774 | for (export_indices) |export_idx| { |
| 1844 | 1775 | const exp = export_idx.ptr(zcu); |
| 1845 | 1776 | const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip)); |
| 1846 | | if (o.builder.getGlobal(exp_name)) |global| { |
| 1847 | | switch (global.ptrConst(&o.builder).kind) { |
| 1777 | |
| 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 | 1798 | .alias => |alias| { |
| 1799 | // We can just repurpose the existing alias. |
| 1849 | 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 | 1804 | .variable, .function => { |
| 1853 | | // This existing global is an `extern` corresponding to this export. |
| 1854 | | // Replace it with the global being exported. |
| 1855 | | // This existing global must be replaced with the alias. |
| 1856 | | try global.rename(.empty, &o.builder); |
| 1857 | | try global.replace(global_index, &o.builder); |
| 1805 | // This must be an extern, which is no good to us---we need an alias. The |
| 1806 | // extern should refer to the value we're exporting, so replace it with the |
| 1807 | // exported value. That will free up the name for us to create a new alias. |
| 1808 | // We need to make a new global which is an alias. Replace this existing one |
| 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 | | } |
| 1862 | | const alias_index = try o.builder.addAlias( |
| 1863 | | .empty, |
| 1864 | | global_index.typeOf(&o.builder), |
| 1865 | | .default, |
| 1866 | | global_index.toConst(), |
| 1867 | | ); |
| 1868 | | try alias_index.rename(exp_name, &o.builder); |
| 1869 | | |
| 1870 | | const alias_global_index = alias_index.ptrConst(&o.builder).global; |
| 1871 | | alias_global_index.setUnnamedAddr(.default, &o.builder); |
| 1872 | | if (comp.config.dll_export_fns and first_export.opts.visibility != .hidden) |
| 1873 | | alias_global_index.setDllStorageClass(.dllexport, &o.builder); |
| 1874 | | alias_global_index.setLinkage(switch (first_export.opts.linkage) { |
| 1875 | | .internal => unreachable, |
| 1823 | }; |
| 1824 | |
| 1825 | // Now for a bit of setup which |
| 1826 | |
| 1827 | // We need the alias to *not* be `unnamed_addr` to ensure that the alias address equals |
| 1828 | // the address of the original global. |
| 1829 | alias_global.setUnnamedAddr(.default, &o.builder); |
| 1830 | |
| 1831 | if (comp.config.dll_export_fns and exp.opts.visibility != .hidden) |
| 1832 | alias_global.setDllStorageClass(.dllexport, &o.builder); |
| 1833 | alias_global.setLinkage(switch (exp.opts.linkage) { |
| 1834 | .internal => if (o.builder.strip) .private else .internal, // we still did useful work in replacing an existing symbol if there was one |
| 1876 | 1835 | .strong => .external, |
| 1877 | 1836 | .weak => .weak_odr, |
| 1878 | 1837 | .link_once => .linkonce_odr, |
| 1879 | 1838 | }, &o.builder); |
| 1880 | | alias_global_index.setVisibility(switch (first_export.opts.visibility) { |
| 1839 | alias_global.setVisibility(switch (exp.opts.visibility) { |
| 1881 | 1840 | .default => .default, |
| 1882 | 1841 | .hidden => .hidden, |
| 1883 | 1842 | .protected => .protected, |
| ... | ... | @@ -1940,7 +1899,12 @@ pub const Object = struct { |
| 1940 | 1899 | assert(val != .anyerror_type); |
| 1941 | 1900 | const fwd_ref = o.debug_types.items[@intFromEnum(index)]; |
| 1942 | 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 | 1908 | o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type); |
| 1945 | 1909 | } |
| 1946 | 1910 | } |
| ... | ... | @@ -2269,7 +2233,9 @@ pub const Object = struct { |
| 2269 | 2233 | }, |
| 2270 | 2234 | .@"fn" => { |
| 2271 | 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 | 2241 | const fn_info = zcu.typeToFunc(ty).?; |
| ... | ... | @@ -2716,75 +2682,38 @@ pub const Object = struct { |
| 2716 | 2682 | return o.getDebugType(pt, .fromInterned(namespace.owner_type)); |
| 2717 | 2683 | } |
| 2718 | 2684 | |
| 2719 | | /// If the llvm function does not exist, create it. |
| 2720 | | /// Note that this can be called before the function's semantic analysis has |
| 2721 | | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. |
| 2722 | | pub fn resolveLlvmFunction( |
| 2685 | /// Sets the attributes and callconv of the given `Builder.Function`, which corresponds to the |
| 2686 | /// given `Nav` (which is a function). |
| 2687 | fn addLlvmFunctionAttributes( |
| 2723 | 2688 | o: *Object, |
| 2724 | | nav_index: InternPool.Nav.Index, |
| 2725 | | ) Allocator.Error!Builder.Function.Index { |
| 2689 | pt: Zcu.PerThread, |
| 2690 | nav_id: InternPool.Nav.Index, |
| 2691 | function_index: Builder.Function.Index, |
| 2692 | ) Allocator.Error!void { |
| 2726 | 2693 | const zcu = o.zcu; |
| 2727 | 2694 | const ip = &zcu.intern_pool; |
| 2728 | | const gpa = o.gpa; |
| 2729 | | const nav = ip.getNav(nav_index); |
| 2730 | | const owner_mod = zcu.navFileScope(nav_index).mod.?; |
| 2695 | const nav = ip.getNav(nav_id); |
| 2696 | const owner_mod = zcu.navFileScope(nav_id).mod.?; |
| 2731 | 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 | 2699 | const fn_info = zcu.typeToFunc(ty).?; |
| 2736 | 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 | 2702 | var attributes: Builder.FunctionAttributes.Wip = .{}; |
| 2750 | 2703 | defer attributes.deinit(&o.builder); |
| 2751 | 2704 | |
| 2752 | | if (!is_extern) { |
| 2753 | | function_index.setLinkage(if (o.builder.strip) .private else .internal, &o.builder); |
| 2754 | | function_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 2755 | | } else { |
| 2756 | | if (target.cpu.arch.isWasm()) { |
| 2757 | | try attributes.addFnAttr(.{ .string = .{ |
| 2758 | | .kind = try o.builder.string("wasm-import-name"), |
| 2759 | | .value = try o.builder.string(nav.name.toSlice(ip)), |
| 2705 | if (target.cpu.arch.isWasm()) if (nav.getExtern(ip)) |@"extern"| { |
| 2706 | try attributes.addFnAttr(.{ .string = .{ |
| 2707 | .kind = try o.builder.string("wasm-import-name"), |
| 2708 | .value = try o.builder.string(nav.name.toSlice(ip)), |
| 2709 | } }, &o.builder); |
| 2710 | if (@"extern".lib_name.toSlice(ip)) |lib_name_slice| { |
| 2711 | if (!std.mem.eql(u8, lib_name_slice, "c")) try attributes.addFnAttr(.{ .string = .{ |
| 2712 | .kind = try o.builder.string("wasm-import-module"), |
| 2713 | .value = try o.builder.string(lib_name_slice), |
| 2760 | 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 | | } |
| 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 | | } |
| 2716 | }; |
| 2788 | 2717 | |
| 2789 | 2718 | if (fn_info.cc == .async) { |
| 2790 | 2719 | @panic("TODO: LLVM backend lower async function"); |
| ... | ... | @@ -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 | 2791 | // Function attributes that are independent of analysis results of the function body. |
| 2866 | 2792 | try o.addCommonFnAttributes( |
| 2867 | 2793 | &attributes, |
| ... | ... | @@ -2877,8 +2803,71 @@ pub const Object = struct { |
| 2877 | 2803 | |
| 2878 | 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 | 2870 | function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); |
| 2881 | | return function_index; |
| 2882 | 2871 | } |
| 2883 | 2872 | |
| 2884 | 2873 | fn addCommonFnAttributes( |
| ... | ... | @@ -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 | 2943 | pub fn errorIntType(o: *Object) Allocator.Error!Builder.Type { |
| 3046 | 2944 | return o.builder.intType(o.zcu.errorSetBits()); |
| 3047 | 2945 | } |
| ... | ... | @@ -3051,7 +2949,7 @@ pub const Object = struct { |
| 3051 | 2949 | const target = zcu.getTarget(); |
| 3052 | 2950 | const ip = &zcu.intern_pool; |
| 3053 | 2951 | return switch (t.toIntern()) { |
| 3054 | | .u0_type, .i0_type => unreachable, |
| 2952 | .u0_type, .i0_type => unreachable, // no runtime bits |
| 3055 | 2953 | inline .u1_type, |
| 3056 | 2954 | .u8_type, |
| 3057 | 2955 | .i8_type, |
| ... | ... | @@ -3100,18 +2998,18 @@ pub const Object = struct { |
| 3100 | 2998 | return .i8; |
| 3101 | 2999 | }, |
| 3102 | 3000 | .bool_type => .i1, |
| 3103 | | .void_type => .void, |
| 3104 | | .type_type => unreachable, |
| 3105 | 3001 | .anyerror_type => try o.errorIntType(), |
| 3106 | | .comptime_int_type, |
| 3107 | | .comptime_float_type, |
| 3108 | | .noreturn_type, |
| 3109 | | => unreachable, |
| 3002 | .void_type => unreachable, // no runtime bits |
| 3003 | .type_type => unreachable, // no runtime bits |
| 3004 | .comptime_int_type => unreachable, // no runtime bits |
| 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 | 3012 | .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"), |
| 3111 | | .null_type, |
| 3112 | | .undefined_type, |
| 3113 | | .enum_literal_type, |
| 3114 | | => unreachable, |
| 3115 | 3013 | .ptr_usize_type, |
| 3116 | 3014 | .ptr_const_comptime_int_type, |
| 3117 | 3015 | .manyptr_u8_type, |
| ... | ... | @@ -3121,13 +3019,10 @@ pub const Object = struct { |
| 3121 | 3019 | .slice_const_u8_type, |
| 3122 | 3020 | .slice_const_u8_sentinel_0_type, |
| 3123 | 3021 | => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(.usize) }), |
| 3124 | | .optional_noreturn_type => unreachable, |
| 3125 | 3022 | .anyerror_void_error_union_type, |
| 3126 | 3023 | .adhoc_inferred_error_set_type, |
| 3127 | 3024 | => try o.errorIntType(), |
| 3128 | | .generic_poison_type, |
| 3129 | | .empty_tuple_type, |
| 3130 | | => unreachable, |
| 3025 | .generic_poison_type => unreachable, |
| 3131 | 3026 | // values, not types |
| 3132 | 3027 | .undef, |
| 3133 | 3028 | .undef_bool, |
| ... | ... | @@ -3176,7 +3071,11 @@ pub const Object = struct { |
| 3176 | 3071 | ), |
| 3177 | 3072 | .opt_type => |child_ty| { |
| 3178 | 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 | 3080 | const payload_ty = try o.lowerType(.fromInterned(child_ty)); |
| 3182 | 3081 | if (t.optionalReprIsPayload(zcu)) return payload_ty; |
| ... | ... | @@ -3198,8 +3097,13 @@ pub const Object = struct { |
| 3198 | 3097 | // Must stay in sync with `codegen.errUnionPayloadOffset`. |
| 3199 | 3098 | // See logic in `lowerPtr`. |
| 3200 | 3099 | const error_type = try o.errorIntType(); |
| 3201 | | if (!Type.fromInterned(error_union_type.payload_type).hasRuntimeBits(zcu)) |
| 3202 | | return error_type; |
| 3100 | |
| 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 | 3107 | const payload_type = try o.lowerType(.fromInterned(error_union_type.payload_type)); |
| 3204 | 3108 | |
| 3205 | 3109 | const payload_align = Type.fromInterned(error_union_type.payload_type).abiAlignment(zcu); |
| ... | ... | @@ -3245,6 +3149,8 @@ pub const Object = struct { |
| 3245 | 3149 | return int_ty; |
| 3246 | 3150 | } |
| 3247 | 3151 | |
| 3152 | assert(struct_type.size > 0); |
| 3153 | |
| 3248 | 3154 | var llvm_field_types: std.ArrayList(Builder.Type) = .empty; |
| 3249 | 3155 | defer llvm_field_types.deinit(o.gpa); |
| 3250 | 3156 | // Although we can estimate how much capacity to add, these cannot be |
| ... | ... | @@ -3311,7 +3217,7 @@ pub const Object = struct { |
| 3311 | 3217 | |
| 3312 | 3218 | comptime assert(struct_layout_version == 2); |
| 3313 | 3219 | var offset: u64 = 0; |
| 3314 | | var big_align: InternPool.Alignment = .none; |
| 3220 | var big_align: InternPool.Alignment = .@"1"; |
| 3315 | 3221 | |
| 3316 | 3222 | for ( |
| 3317 | 3223 | tuple_type.types.get(ip), |
| ... | ... | @@ -3345,6 +3251,7 @@ pub const Object = struct { |
| 3345 | 3251 | try o.builder.arrayType(padding_len, .i8), |
| 3346 | 3252 | ); |
| 3347 | 3253 | } |
| 3254 | assert(offset > 0); |
| 3348 | 3255 | return o.builder.structType(.normal, llvm_field_types.items); |
| 3349 | 3256 | }, |
| 3350 | 3257 | .union_type => { |
| ... | ... | @@ -3358,6 +3265,8 @@ pub const Object = struct { |
| 3358 | 3265 | return int_ty; |
| 3359 | 3266 | } |
| 3360 | 3267 | |
| 3268 | assert(union_obj.size > 0); |
| 3269 | |
| 3361 | 3270 | const layout = Type.getUnionLayout(union_obj, zcu); |
| 3362 | 3271 | |
| 3363 | 3272 | if (layout.payload_size == 0) { |
| ... | ... | @@ -3421,15 +3330,9 @@ pub const Object = struct { |
| 3421 | 3330 | ); |
| 3422 | 3331 | return ty; |
| 3423 | 3332 | }, |
| 3424 | | .opaque_type => { |
| 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 | | }, |
| 3333 | .opaque_type => unreachable, // no runtime bits |
| 3431 | 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 | 3336 | .error_set_type, .inferred_error_set_type => try o.errorIntType(), |
| 3434 | 3337 | // values, not types |
| 3435 | 3338 | .undef, |
| ... | ... | @@ -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 | 3362 | const zcu = o.zcu; |
| 3460 | 3363 | const ip = &zcu.intern_pool; |
| 3461 | 3364 | const target = zcu.getTarget(); |
| 3365 | |
| 3366 | assert(fn_ty.fnHasRuntimeBits(zcu)); |
| 3367 | |
| 3462 | 3368 | const ret_ty = try lowerFnRetTy(o, fn_info); |
| 3463 | 3369 | |
| 3464 | 3370 | var llvm_params: std.ArrayList(Builder.Type) = .empty; |
| ... | ... | @@ -3526,15 +3432,12 @@ pub const Object = struct { |
| 3526 | 3432 | const ip = &zcu.intern_pool; |
| 3527 | 3433 | const target = zcu.getTarget(); |
| 3528 | 3434 | |
| 3529 | | const val = Value.fromInterned(arg_val); |
| 3435 | const val: Value = .fromInterned(arg_val); |
| 3530 | 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 | 3438 | const ty: Type = .fromInterned(val_key.typeOf()); |
| 3537 | 3439 | ty.assertHasLayout(zcu); |
| 3440 | assert(ty.hasRuntimeBits(zcu)); |
| 3538 | 3441 | |
| 3539 | 3442 | return switch (val_key) { |
| 3540 | 3443 | .int_type, |
| ... | ... | @@ -3555,7 +3458,7 @@ pub const Object = struct { |
| 3555 | 3458 | .inferred_error_set_type, |
| 3556 | 3459 | => unreachable, // types, not values |
| 3557 | 3460 | |
| 3558 | | .undef => unreachable, // handled above |
| 3461 | .undef => return o.builder.undefConst(try o.lowerType(ty)), |
| 3559 | 3462 | .simple_value => |simple_value| switch (simple_value) { |
| 3560 | 3463 | .void => unreachable, // non-runtime value |
| 3561 | 3464 | .null => unreachable, // non-runtime value |
| ... | ... | @@ -3565,14 +3468,8 @@ pub const Object = struct { |
| 3565 | 3468 | .true => .true, |
| 3566 | 3469 | }, |
| 3567 | 3470 | .enum_literal => unreachable, // non-runtime value |
| 3568 | | .@"extern" => |@"extern"| { |
| 3569 | | const function_index = try o.resolveLlvmFunction(@"extern".owner_nav); |
| 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 | | }, |
| 3471 | .@"extern" => unreachable, // non-runtime value |
| 3472 | .func => unreachable, // non-runtime value |
| 3576 | 3473 | .int => { |
| 3577 | 3474 | var bigint_space: Value.BigIntSpace = undefined; |
| 3578 | 3475 | const bigint = val.toBigInt(&bigint_space, zcu); |
| ... | ... | @@ -3815,7 +3712,7 @@ pub const Object = struct { |
| 3815 | 3712 | comptime assert(struct_layout_version == 2); |
| 3816 | 3713 | var llvm_index: usize = 0; |
| 3817 | 3714 | var offset: u64 = 0; |
| 3818 | | var big_align: InternPool.Alignment = .none; |
| 3715 | var big_align: InternPool.Alignment = .@"1"; |
| 3819 | 3716 | var need_unnamed = false; |
| 3820 | 3717 | for ( |
| 3821 | 3718 | tuple.types.get(ip), |
| ... | ... | @@ -4033,7 +3930,7 @@ pub const Object = struct { |
| 4033 | 3930 | const offset: u64 = prev_offset + ptr.byte_offset; |
| 4034 | 3931 | return switch (ptr.base_addr) { |
| 4035 | 3932 | .nav => |nav| { |
| 4036 | | const base_ptr = try o.lowerNavRefValue(nav); |
| 3933 | const base_ptr = try o.lowerNavRef(nav); |
| 4037 | 3934 | return o.builder.gepConst(.inbounds, .i8, base_ptr, null, &.{ |
| 4038 | 3935 | try o.builder.intConst(.i64, offset), |
| 4039 | 3936 | }); |
| ... | ... | @@ -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. |
| 4096 | | /// Maybe the logic could be unified. |
| 3992 | pub fn lowerPtrToVoid( |
| 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 | 4005 | pub fn lowerUavRef( |
| 4098 | 4006 | o: *Object, |
| 4099 | 4007 | uav_val: InternPool.Index, |
| ... | ... | @@ -4105,6 +4013,8 @@ pub const Object = struct { |
| 4105 | 4013 | |
| 4106 | 4014 | const zcu = o.zcu; |
| 4107 | 4015 | const ip = &zcu.intern_pool; |
| 4016 | const gpa = zcu.comp.gpa; |
| 4017 | |
| 4108 | 4018 | const uav_ty: Type = .fromInterned(ip.typeOf(uav_val)); |
| 4109 | 4019 | |
| 4110 | 4020 | switch (ip.indexToKey(uav_val)) { |
| ... | ... | @@ -4118,63 +4028,63 @@ pub const Object = struct { |
| 4118 | 4028 | } |
| 4119 | 4029 | |
| 4120 | 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( |
| 4124 | | llvm_global.toConst(), |
| 4125 | | try o.builder.ptrType(llvm_addrspace), |
| 4126 | | ); |
| 4032 | const gop = try o.uav_map.getOrPut(gpa, .{ .val = uav_val, .@"addrspace" = @"addrspace" }); |
| 4033 | if (gop.found_existing) { |
| 4034 | // Keep the greater of the two alignments. |
| 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 | 4056 | const zcu = o.zcu; |
| 4131 | 4057 | const ip = &zcu.intern_pool; |
| 4058 | const gpa = zcu.comp.gpa; |
| 4132 | 4059 | |
| 4133 | | const nav = ip.getNav(nav_index); |
| 4134 | | |
| 4060 | const nav = ip.getNav(nav_id); |
| 4135 | 4061 | const nav_ty: Type = .fromInterned(nav.resolved.?.type); |
| 4136 | | |
| 4137 | | if (nav.getExtern(ip) == null and !nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { |
| 4138 | | return o.lowerPtrToVoid(nav.resolved.?.@"align", nav.resolved.?.@"addrspace"); |
| 4062 | if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and nav.getExtern(ip) == null) { |
| 4063 | const nav_align = switch (nav.resolved.?.@"align") { |
| 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") |
| 4142 | | (try o.resolveLlvmFunction(nav_index)).ptrConst(&o.builder).global |
| 4143 | | else |
| 4144 | | (try o.resolveGlobalNav(nav_index)).ptrConst(&o.builder).global; |
| 4070 | const gop = try o.nav_map.getOrPut(gpa, nav_id); |
| 4071 | if (!gop.found_existing) { |
| 4072 | errdefer assert(o.nav_map.remove(nav_id)); |
| 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( |
| 4147 | | llvm_global.toConst(), |
| 4148 | | try o.builder.ptrType(toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget())), |
| 4149 | | ); |
| 4150 | | } |
| 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); |
| 4083 | // We need to make sure the global's address space is up to date, because that affects the |
| 4084 | // type of a pointer to this global. But everything else about the global will be populated |
| 4085 | // by `updateNav` or `updateFunc`. |
| 4086 | llvm_global.ptr(&o.builder).addr_space = toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget()); |
| 4087 | return llvm_global.toConst(); |
| 4178 | 4088 | } |
| 4179 | 4089 | |
| 4180 | 4090 | pub fn addByValParamAttrs( |
| ... | ... | @@ -4243,13 +4153,14 @@ pub const Object = struct { |
| 4243 | 4153 | const name = try o.builder.strtabString("__zig_error_name_table"); |
| 4244 | 4154 | // TODO: Address space |
| 4245 | 4155 | const variable_index = try o.builder.addVariable(name, .ptr, .default); |
| 4246 | | variable_index.setLinkage(.private, &o.builder); |
| 4247 | 4156 | variable_index.setMutability(.constant, &o.builder); |
| 4248 | | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 4249 | 4157 | variable_index.setAlignment( |
| 4250 | 4158 | Type.slice_const_u8_sentinel_0.abiAlignment(o.zcu).toLlvm(), |
| 4251 | 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 | 4165 | o.error_name_table = variable_index; |
| 4255 | 4166 | return variable_index; |
| ... | ... | @@ -4261,10 +4172,11 @@ pub const Object = struct { |
| 4261 | 4172 | const llvm_err_int_ty = try o.errorIntType(); |
| 4262 | 4173 | const name = try builder.strtabString("__zig_errors_len"); |
| 4263 | 4174 | const variable_index = try builder.addVariable(name, llvm_err_int_ty, .default); |
| 4264 | | variable_index.setLinkage(.private, builder); |
| 4265 | 4175 | variable_index.setMutability(.constant, builder); |
| 4266 | | variable_index.setUnnamedAddr(.unnamed_addr, builder); |
| 4267 | 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 | 4180 | o.errors_len_variable = variable_index; |
| 4269 | 4181 | } |
| 4270 | 4182 | return o.errors_len_variable; |
| ... | ... | @@ -4332,16 +4244,16 @@ pub const Object = struct { |
| 4332 | 4244 | for (0..loaded_enum.field_names.len) |field_index| { |
| 4333 | 4245 | const name = try o.builder.stringNull(loaded_enum.field_names.get(ip)[field_index].toSlice(ip)); |
| 4334 | 4246 | const name_init = try o.builder.stringConst(name); |
| 4335 | | const name_variable_index = |
| 4336 | | try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); |
| 4247 | const name_variable_index = try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); |
| 4337 | 4248 | try name_variable_index.setInitializer(name_init, &o.builder); |
| 4338 | | name_variable_index.setLinkage(.private, &o.builder); |
| 4339 | 4249 | name_variable_index.setMutability(.constant, &o.builder); |
| 4340 | | name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 4341 | 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 | 4255 | const name_val = try o.builder.structValue(llvm_ret_ty, &.{ |
| 4344 | | name_variable_index.toConst(&o.builder), |
| 4256 | name_global_index.toConst(), |
| 4345 | 4257 | try o.builder.intConst(llvm_usize_ty, name.slice(&o.builder).?.len - 1), |
| 4346 | 4258 | }); |
| 4347 | 4259 | |