authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-17 11:38:46-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-19 23:38:40-04:00
log9afb349abaeaf6470329ea8990eb06eb37dd79e1
tree859eac097aa0ececa5f074c1eff21d3955be543c
parentef84e869925d8a95e8e57895c421f398903b5f4f

llvm: convert most instructions


4 files changed, 6109 insertions(+), 2609 deletions(-)

src/codegen/llvm.zig+2321-2231
......@@ -549,7 +549,6 @@ pub const Object = struct {
549549 /// - *Module.Decl (Non-Fn) => *DIGlobalVariable
550550 di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode),
551551 di_compile_unit: ?*llvm.DICompileUnit,
552 context: *llvm.Context,
553552 target_machine: *llvm.TargetMachine,
554553 target_data: *llvm.TargetData,
555554 target: std.Target,
......@@ -727,7 +726,6 @@ pub const Object = struct {
727726 .di_map = .{},
728727 .di_builder = builder.llvm.di_builder,
729728 .di_compile_unit = builder.llvm.di_compile_unit,
730 .context = builder.llvm.context,
731729 .target_machine = target_machine,
732730 .target_data = target_data,
733731 .target = options.target,
......@@ -803,13 +801,13 @@ pub const Object = struct {
803801 .linkage = .private,
804802 .unnamed_addr = .unnamed_addr,
805803 .type = str_ty,
806 .alignment = comptime Builder.Alignment.fromByteUnits(1),
807804 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
808805 };
809806 var str_variable = Builder.Variable{
810807 .global = @enumFromInt(o.builder.globals.count()),
811808 .mutability = .constant,
812809 .init = str_init,
810 .alignment = comptime Builder.Alignment.fromByteUnits(1),
813811 };
814812 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);
815813 const global_index = try o.builder.addGlobal(.empty, str_global);
......@@ -833,13 +831,13 @@ pub const Object = struct {
833831 .linkage = .private,
834832 .unnamed_addr = .unnamed_addr,
835833 .type = llvm_table_ty,
836 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
837834 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
838835 };
839836 var variable = Builder.Variable{
840837 .global = @enumFromInt(o.builder.globals.count()),
841838 .mutability = .constant,
842839 .init = error_name_table_init,
840 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
843841 };
844842 try o.builder.llvm.globals.append(o.gpa, error_name_table_global);
845843 _ = try o.builder.addGlobal(.empty, global);
......@@ -857,25 +855,19 @@ pub const Object = struct {
857855 const mod = o.module;
858856 const errors_len = mod.global_error_set.count();
859857
860 var wip = Builder.WipFunction.init(&o.builder, llvm_fn.ptrConst(&o.builder).kind.function);
858 var wip = try Builder.WipFunction.init(&o.builder, llvm_fn.ptrConst(&o.builder).kind.function);
861859 defer wip.deinit();
862
863 const builder = wip.llvm.builder;
864 const entry_block = try wip.block("Entry");
865 wip.cursor = .{ .block = entry_block };
866 builder.positionBuilderAtEnd(entry_block.toLlvm(&wip));
867 builder.clearCurrentDebugLocation();
860 wip.cursor = .{ .block = try wip.block(0, "Entry") };
868861
869862 // Example source of the following LLVM IR:
870863 // fn __zig_lt_errors_len(index: u16) bool {
871864 // return index < total_errors_len;
872865 // }
873866
874 const lhs = llvm_fn.toLlvm(&o.builder).getParam(0);
875 const rhs = try o.builder.intConst(Builder.Type.err_int, errors_len);
876 const is_lt = builder.buildICmp(.ULT, lhs, rhs.toLlvm(&o.builder), "");
877 _ = builder.buildRet(is_lt);
878
867 const lhs = wip.arg(0);
868 const rhs = try o.builder.intValue(Builder.Type.err_int, errors_len);
869 const is_lt = try wip.icmp(.ult, lhs, rhs, "");
870 _ = try wip.ret(is_lt);
879871 try wip.finish();
880872 }
881873
......@@ -1148,29 +1140,26 @@ pub const Object = struct {
11481140 }
11491141
11501142 if (ip.stringToSliceUnwrap(decl.@"linksection")) |section| {
1151 global.ptr(&o.builder).section = try o.builder.string(section);
1143 function.ptr(&o.builder).section = try o.builder.string(section);
11521144 llvm_func.setSection(section);
11531145 }
11541146
1155 // Remove all the basic blocks of a function in order to start over, generating
1156 // LLVM IR from an empty function body.
1157 while (llvm_func.getFirstBasicBlock()) |bb| {
1158 bb.deleteBasicBlock();
1159 }
1160
11611147 var deinit_wip = true;
1162 var wip = Builder.WipFunction.init(&o.builder, function);
1148 var wip = try Builder.WipFunction.init(&o.builder, function);
11631149 defer if (deinit_wip) wip.deinit();
1150 wip.cursor = .{ .block = try wip.block(0, "Entry") };
11641151
11651152 const builder = wip.llvm.builder;
1166 const entry_block = try wip.block("Entry");
1167 wip.cursor = .{ .block = entry_block };
1168 builder.positionBuilderAtEnd(entry_block.toLlvm(&wip));
1153 var llvm_arg_i: u32 = 0;
11691154
11701155 // This gets the LLVM values from the function and stores them in `dg.args`.
11711156 const fn_info = mod.typeToFunc(decl.ty).?;
11721157 const sret = firstParamSRet(fn_info, mod);
1173 const ret_ptr = if (sret) llvm_func.getParam(0) else null;
1158 const ret_ptr: Builder.Value = if (sret) param: {
1159 const param = wip.arg(llvm_arg_i);
1160 llvm_arg_i += 1;
1161 break :param param;
1162 } else .none;
11741163 const gpa = o.gpa;
11751164
11761165 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
......@@ -1181,205 +1170,183 @@ pub const Object = struct {
11811170 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
11821171 mod.comp.bin_file.options.error_return_tracing;
11831172
1184 const err_ret_trace = if (err_return_tracing)
1185 llvm_func.getParam(@intFromBool(ret_ptr != null))
1186 else
1187 null;
1173 const err_ret_trace: Builder.Value = if (err_return_tracing) param: {
1174 const param = wip.arg(llvm_arg_i);
1175 llvm_arg_i += 1;
1176 break :param param;
1177 } else .none;
11881178
11891179 // This is the list of args we will use that correspond directly to the AIR arg
11901180 // instructions. Depending on the calling convention, this list is not necessarily
11911181 // a bijection with the actual LLVM parameters of the function.
1192 var args = std.ArrayList(*llvm.Value).init(gpa);
1193 defer args.deinit();
1182 var args: std.ArrayListUnmanaged(Builder.Value) = .{};
1183 defer args.deinit(gpa);
11941184
11951185 {
1196 var llvm_arg_i = @as(c_uint, @intFromBool(ret_ptr != null)) + @intFromBool(err_return_tracing);
11971186 var it = iterateParamTypes(o, fn_info);
1198 while (try it.next()) |lowering| switch (lowering) {
1199 .no_bits => continue,
1200 .byval => {
1201 assert(!it.byval_attr);
1202 const param_index = it.zig_index - 1;
1203 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
1204 const param = llvm_func.getParam(llvm_arg_i);
1205 try args.ensureUnusedCapacity(1);
1206
1207 if (isByRef(param_ty, mod)) {
1208 const alignment = param_ty.abiAlignment(mod);
1209 const param_llvm_ty = param.typeOf();
1210 const arg_ptr = try o.buildAllocaInner(&wip, builder, llvm_func, false, param_llvm_ty, alignment, target);
1211 const store_inst = builder.buildStore(param, arg_ptr);
1212 store_inst.setAlignment(alignment);
1213 args.appendAssumeCapacity(arg_ptr);
1214 } else {
1215 args.appendAssumeCapacity(param);
1216
1217 o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, llvm_arg_i);
1218 }
1219 llvm_arg_i += 1;
1220 },
1221 .byref => {
1222 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1223 const param_llvm_ty = try o.lowerType(param_ty);
1224 const param = llvm_func.getParam(llvm_arg_i);
1225 const alignment = param_ty.abiAlignment(mod);
1226
1227 o.addByRefParamAttrs(llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
1228 llvm_arg_i += 1;
1229
1230 try args.ensureUnusedCapacity(1);
1231
1232 if (isByRef(param_ty, mod)) {
1233 args.appendAssumeCapacity(param);
1234 } else {
1235 const load_inst = builder.buildLoad(param_llvm_ty.toLlvm(&o.builder), param, "");
1236 load_inst.setAlignment(alignment);
1237 args.appendAssumeCapacity(load_inst);
1238 }
1239 },
1240 .byref_mut => {
1241 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1242 const param_llvm_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);
1243 const param = llvm_func.getParam(llvm_arg_i);
1244 const alignment = param_ty.abiAlignment(mod);
1187 while (try it.next()) |lowering| {
1188 try args.ensureUnusedCapacity(gpa, 1);
1189
1190 switch (lowering) {
1191 .no_bits => continue,
1192 .byval => {
1193 assert(!it.byval_attr);
1194 const param_index = it.zig_index - 1;
1195 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
1196 const param = wip.arg(llvm_arg_i);
1197
1198 if (isByRef(param_ty, mod)) {
1199 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1200 const param_llvm_ty = param.typeOfWip(&wip);
1201 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1202 _ = try wip.store(.normal, param, arg_ptr, alignment);
1203 args.appendAssumeCapacity(arg_ptr);
1204 } else {
1205 args.appendAssumeCapacity(param);
12451206
1246 o.addArgAttr(llvm_func, llvm_arg_i, "noundef");
1247 llvm_arg_i += 1;
1207 o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, @intCast(llvm_arg_i));
1208 }
1209 llvm_arg_i += 1;
1210 },
1211 .byref => {
1212 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1213 const param_llvm_ty = try o.lowerType(param_ty);
1214 const param = wip.arg(llvm_arg_i);
1215 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
12481216
1249 try args.ensureUnusedCapacity(1);
1217 o.addByRefParamAttrs(llvm_func, @intCast(llvm_arg_i), @intCast(alignment.toByteUnits() orelse 0), it.byval_attr, param_llvm_ty);
1218 llvm_arg_i += 1;
12501219
1251 if (isByRef(param_ty, mod)) {
1252 args.appendAssumeCapacity(param);
1253 } else {
1254 const load_inst = builder.buildLoad(param_llvm_ty, param, "");
1255 load_inst.setAlignment(alignment);
1256 args.appendAssumeCapacity(load_inst);
1257 }
1258 },
1259 .abi_sized_int => {
1260 assert(!it.byval_attr);
1261 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1262 const param = llvm_func.getParam(llvm_arg_i);
1263 llvm_arg_i += 1;
1220 if (isByRef(param_ty, mod)) {
1221 args.appendAssumeCapacity(param);
1222 } else {
1223 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
1224 }
1225 },
1226 .byref_mut => {
1227 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1228 const param_llvm_ty = try o.lowerType(param_ty);
1229 const param = wip.arg(llvm_arg_i);
1230 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
12641231
1265 const param_llvm_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);
1266 const int_llvm_ty = (try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8))).toLlvm(&o.builder);
1267 const alignment = @max(
1268 param_ty.abiAlignment(mod),
1269 o.target_data.abiAlignmentOfType(int_llvm_ty),
1270 );
1271 const arg_ptr = try o.buildAllocaInner(&wip, builder, llvm_func, false, param_llvm_ty, alignment, target);
1272 const store_inst = builder.buildStore(param, arg_ptr);
1273 store_inst.setAlignment(alignment);
1232 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noundef");
1233 llvm_arg_i += 1;
12741234
1275 try args.ensureUnusedCapacity(1);
1235 if (isByRef(param_ty, mod)) {
1236 args.appendAssumeCapacity(param);
1237 } else {
1238 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
1239 }
1240 },
1241 .abi_sized_int => {
1242 assert(!it.byval_attr);
1243 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1244 const param = wip.arg(llvm_arg_i);
1245 llvm_arg_i += 1;
12761246
1277 if (isByRef(param_ty, mod)) {
1278 args.appendAssumeCapacity(arg_ptr);
1279 } else {
1280 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1281 load_inst.setAlignment(alignment);
1282 args.appendAssumeCapacity(load_inst);
1283 }
1284 },
1285 .slice => {
1286 assert(!it.byval_attr);
1287 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1288 const ptr_info = param_ty.ptrInfo(mod);
1247 const param_llvm_ty = try o.lowerType(param_ty);
1248 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
1249 const alignment = Builder.Alignment.fromByteUnits(@max(
1250 param_ty.abiAlignment(mod),
1251 o.target_data.abiAlignmentOfType(int_llvm_ty.toLlvm(&o.builder)),
1252 ));
1253 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1254 _ = try wip.store(.normal, param, arg_ptr, alignment);
12891255
1290 if (math.cast(u5, it.zig_index - 1)) |i| {
1291 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
1292 o.addArgAttr(llvm_func, llvm_arg_i, "noalias");
1256 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1257 arg_ptr
1258 else
1259 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1260 },
1261 .slice => {
1262 assert(!it.byval_attr);
1263 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1264 const ptr_info = param_ty.ptrInfo(mod);
1265
1266 if (math.cast(u5, it.zig_index - 1)) |i| {
1267 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
1268 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noalias");
1269 }
1270 }
1271 if (param_ty.zigTypeTag(mod) != .Optional) {
1272 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "nonnull");
1273 }
1274 if (ptr_info.flags.is_const) {
1275 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "readonly");
1276 }
1277 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
1278 @max(ptr_info.child.toType().abiAlignment(mod), 1);
1279 o.addArgAttrInt(llvm_func, @intCast(llvm_arg_i), "align", elem_align);
1280 const ptr_param = wip.arg(llvm_arg_i + 0);
1281 const len_param = wip.arg(llvm_arg_i + 1);
1282 llvm_arg_i += 2;
1283
1284 const slice_llvm_ty = try o.lowerType(param_ty);
1285 args.appendAssumeCapacity(
1286 try wip.buildAggregate(slice_llvm_ty, &.{ ptr_param, len_param }, ""),
1287 );
1288 },
1289 .multiple_llvm_types => {
1290 assert(!it.byval_attr);
1291 const field_types = it.types_buffer[0..it.types_len];
1292 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1293 const param_llvm_ty = try o.lowerType(param_ty);
1294 const param_alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1295 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target);
1296 const llvm_ty = try o.builder.structType(.normal, field_types);
1297 for (0..field_types.len) |field_i| {
1298 const param = wip.arg(llvm_arg_i);
1299 llvm_arg_i += 1;
1300 const field_ptr = try wip.gepStruct(llvm_ty, arg_ptr, field_i, "");
1301 const alignment =
1302 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
1303 _ = try wip.store(.normal, param, field_ptr, alignment);
12931304 }
1294 }
1295 if (param_ty.zigTypeTag(mod) != .Optional) {
1296 o.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
1297 }
1298 if (ptr_info.flags.is_const) {
1299 o.addArgAttr(llvm_func, llvm_arg_i, "readonly");
1300 }
1301 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
1302 @max(ptr_info.child.toType().abiAlignment(mod), 1);
1303 o.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align);
1304 const ptr_param = llvm_func.getParam(llvm_arg_i);
1305 llvm_arg_i += 1;
1306 const len_param = llvm_func.getParam(llvm_arg_i);
1307 llvm_arg_i += 1;
1308
1309 const slice_llvm_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);
1310 const partial = builder.buildInsertValue(slice_llvm_ty.getUndef(), ptr_param, 0, "");
1311 const aggregate = builder.buildInsertValue(partial, len_param, 1, "");
1312 try args.append(aggregate);
1313 },
1314 .multiple_llvm_types => {
1315 assert(!it.byval_attr);
1316 const field_types = it.types_buffer[0..it.types_len];
1317 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1318 const param_llvm_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);
1319 const param_alignment = param_ty.abiAlignment(mod);
1320 const arg_ptr = try o.buildAllocaInner(&wip, builder, llvm_func, false, param_llvm_ty, param_alignment, target);
1321 const llvm_ty = (try o.builder.structType(.normal, field_types)).toLlvm(&o.builder);
1322 for (0..field_types.len) |field_i| {
1323 const param = llvm_func.getParam(llvm_arg_i);
1324 llvm_arg_i += 1;
1325 const field_ptr = builder.buildStructGEP(llvm_ty, arg_ptr, @intCast(field_i), "");
1326 const store_inst = builder.buildStore(param, field_ptr);
1327 store_inst.setAlignment(target.ptrBitWidth() / 8);
1328 }
13291305
1330 const is_by_ref = isByRef(param_ty, mod);
1331 const loaded = if (is_by_ref) arg_ptr else l: {
1332 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1333 load_inst.setAlignment(param_alignment);
1334 break :l load_inst;
1335 };
1336 try args.append(loaded);
1337 },
1338 .as_u16 => {
1339 assert(!it.byval_attr);
1340 const param = llvm_func.getParam(llvm_arg_i);
1341 llvm_arg_i += 1;
1342 const casted = builder.buildBitCast(param, Builder.Type.half.toLlvm(&o.builder), "");
1343 try args.ensureUnusedCapacity(1);
1344 args.appendAssumeCapacity(casted);
1345 },
1346 .float_array => {
1347 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1348 const param_llvm_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);
1349 const param = llvm_func.getParam(llvm_arg_i);
1350 llvm_arg_i += 1;
1306 const is_by_ref = isByRef(param_ty, mod);
1307 args.appendAssumeCapacity(if (is_by_ref)
1308 arg_ptr
1309 else
1310 try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, ""));
1311 },
1312 .as_u16 => {
1313 assert(!it.byval_attr);
1314 const param = wip.arg(llvm_arg_i);
1315 llvm_arg_i += 1;
1316 args.appendAssumeCapacity(try wip.cast(.bitcast, param, .half, ""));
1317 },
1318 .float_array => {
1319 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1320 const param_llvm_ty = try o.lowerType(param_ty);
1321 const param = wip.arg(llvm_arg_i);
1322 llvm_arg_i += 1;
13511323
1352 const alignment = param_ty.abiAlignment(mod);
1353 const arg_ptr = try o.buildAllocaInner(&wip, builder, llvm_func, false, param_llvm_ty, alignment, target);
1354 _ = builder.buildStore(param, arg_ptr);
1324 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1325 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1326 _ = try wip.store(.normal, param, arg_ptr, alignment);
13551327
1356 if (isByRef(param_ty, mod)) {
1357 try args.append(arg_ptr);
1358 } else {
1359 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1360 load_inst.setAlignment(alignment);
1361 try args.append(load_inst);
1362 }
1363 },
1364 .i32_array, .i64_array => {
1365 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1366 const param_llvm_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);
1367 const param = llvm_func.getParam(llvm_arg_i);
1368 llvm_arg_i += 1;
1328 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1329 arg_ptr
1330 else
1331 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1332 },
1333 .i32_array, .i64_array => {
1334 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1335 const param_llvm_ty = try o.lowerType(param_ty);
1336 const param = wip.arg(llvm_arg_i);
1337 llvm_arg_i += 1;
13691338
1370 const alignment = param_ty.abiAlignment(mod);
1371 const arg_ptr = try o.buildAllocaInner(&wip, builder, llvm_func, false, param_llvm_ty, alignment, target);
1372 _ = builder.buildStore(param, arg_ptr);
1339 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1340 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1341 _ = try wip.store(.normal, param, arg_ptr, alignment);
13731342
1374 if (isByRef(param_ty, mod)) {
1375 try args.append(arg_ptr);
1376 } else {
1377 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
1378 load_inst.setAlignment(alignment);
1379 try args.append(load_inst);
1380 }
1381 },
1382 };
1343 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1344 arg_ptr
1345 else
1346 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1347 },
1348 }
1349 }
13831350 }
13841351
13851352 var di_file: ?*llvm.DIFile = null;
......@@ -1421,7 +1388,6 @@ pub const Object = struct {
14211388 .gpa = gpa,
14221389 .air = air,
14231390 .liveness = liveness,
1424 .context = o.context,
14251391 .dg = &dg,
14261392 .wip = wip,
14271393 .builder = builder,
......@@ -1429,9 +1395,8 @@ pub const Object = struct {
14291395 .args = args.items,
14301396 .arg_index = 0,
14311397 .func_inst_table = .{},
1432 .llvm_func = llvm_func,
14331398 .blocks = .{},
1434 .single_threaded = mod.comp.bin_file.options.single_threaded,
1399 .sync_scope = if (mod.comp.bin_file.options.single_threaded) .singlethread else .system,
14351400 .di_scope = di_scope,
14361401 .di_file = di_file,
14371402 .base_line = dg.decl.src_line,
......@@ -1523,11 +1488,11 @@ pub const Object = struct {
15231488 const decl_name_slice = decl_name.toSlice(&self.builder).?;
15241489 if (try decl.isFunction(mod)) {
15251490 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1526 const linkage_name = llvm.MDString.get(self.context, decl_name_slice.ptr, decl_name_slice.len);
1491 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
15271492 di_func.replaceLinkageName(linkage_name);
15281493 } else {
15291494 const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);
1530 const linkage_name = llvm.MDString.get(self.context, decl_name_slice.ptr, decl_name_slice.len);
1495 const linkage_name = llvm.MDString.get(self.builder.llvm.context, decl_name_slice.ptr, decl_name_slice.len);
15311496 di_global.replaceLinkageName(linkage_name);
15321497 }
15331498 }
......@@ -1560,11 +1525,11 @@ pub const Object = struct {
15601525 const exp_name_slice = exp_name.toSlice(&self.builder).?;
15611526 if (try decl.isFunction(mod)) {
15621527 const di_func: *llvm.DISubprogram = @ptrCast(di_node);
1563 const linkage_name = llvm.MDString.get(self.context, exp_name_slice.ptr, exp_name_slice.len);
1528 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
15641529 di_func.replaceLinkageName(linkage_name);
15651530 } else {
15661531 const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);
1567 const linkage_name = llvm.MDString.get(self.context, exp_name_slice.ptr, exp_name_slice.len);
1532 const linkage_name = llvm.MDString.get(self.builder.llvm.context, exp_name_slice.ptr, exp_name_slice.len);
15681533 di_global.replaceLinkageName(linkage_name);
15691534 }
15701535 }
......@@ -1598,7 +1563,11 @@ pub const Object = struct {
15981563 },
15991564 }
16001565 if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| {
1601 global.ptr(&self.builder).section = try self.builder.string(section);
1566 switch (global.ptrConst(&self.builder).kind) {
1567 inline .variable, .function => |impl_index| impl_index.ptr(&self.builder).section =
1568 try self.builder.string(section),
1569 else => unreachable,
1570 }
16021571 llvm_global.setSection(section);
16031572 }
16041573 if (decl.val.getVariable(mod)) |decl_var| {
......@@ -1623,7 +1592,7 @@ pub const Object = struct {
16231592 alias.setAliasee(llvm_global);
16241593 } else {
16251594 _ = self.llvm_module.addAlias(
1626 llvm_global.globalGetValueType(),
1595 global.ptrConst(&self.builder).type.toLlvm(&self.builder),
16271596 0,
16281597 llvm_global,
16291598 exp_name_z,
......@@ -2773,7 +2742,7 @@ pub const Object = struct {
27732742 }
27742743
27752744 if (fn_info.alignment.toByteUnitsOptional()) |a| {
2776 global.alignment = Builder.Alignment.fromByteUnits(a);
2745 function.alignment = Builder.Alignment.fromByteUnits(a);
27772746 llvm_fn.setAlignment(@intCast(a));
27782747 }
27792748
......@@ -2944,7 +2913,7 @@ pub const Object = struct {
29442913 const llvm_ty = ty.toLlvm(&o.builder);
29452914 if (t.zigTypeTag(mod) == .Opaque) break :check;
29462915 if (!t.hasRuntimeBits(mod)) break :check;
2947 if (!llvm_ty.isSized().toBool()) break :check;
2916 if (!try ty.isSized(&o.builder)) break :check;
29482917
29492918 const zig_size = t.abiSize(mod);
29502919 const llvm_size = o.target_data.abiSizeOfType(llvm_ty);
......@@ -3807,7 +3776,7 @@ pub const Object = struct {
38073776 }
38083777 assert(llvm_index == llvm_len);
38093778
3810 return try o.builder.structConst(if (need_unnamed)
3779 return o.builder.structConst(if (need_unnamed)
38113780 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
38123781 else
38133782 struct_ty, vals);
......@@ -3904,7 +3873,7 @@ pub const Object = struct {
39043873 }
39053874 assert(llvm_index == llvm_len);
39063875
3907 return try o.builder.structConst(if (need_unnamed)
3876 return o.builder.structConst(if (need_unnamed)
39083877 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
39093878 else
39103879 struct_ty, vals);
......@@ -3978,7 +3947,7 @@ pub const Object = struct {
39783947 vals[2] = try o.builder.undefConst(fields[2]);
39793948 len = 3;
39803949 }
3981 return try o.builder.structConst(if (need_unnamed)
3950 return o.builder.structConst(if (need_unnamed)
39823951 try o.builder.structType(union_ty.structKind(&o.builder), fields[0..len])
39833952 else
39843953 union_ty, vals[0..len]);
......@@ -4012,7 +3981,7 @@ pub const Object = struct {
40123981
40133982 const ParentPtr = struct {
40143983 ty: Type,
4015 llvm_ptr: *llvm.Value,
3984 llvm_ptr: Builder.Value,
40163985 };
40173986
40183987 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
......@@ -4040,12 +4009,10 @@ pub const Object = struct {
40404009 return parent_ptr;
40414010 }
40424011
4043 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, &.{
4044 try o.builder.intConst(.i32, 0),
4045 try o.builder.intConst(.i32, @as(
4046 i32,
4047 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1,
4048 )),
4012 const index: u32 =
4013 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1;
4014 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{
4015 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index),
40494016 });
40504017 },
40514018 .opt_payload => |opt_ptr| {
......@@ -4061,16 +4028,16 @@ pub const Object = struct {
40614028 return parent_ptr;
40624029 }
40634030
4064 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, &(.{
4065 try o.builder.intConst(.i32, 0),
4066 } ** 2));
4031 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, null, &.{
4032 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, 0),
4033 });
40674034 },
40684035 .comptime_field => unreachable,
40694036 .elem => |elem_ptr| {
40704037 const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true);
40714038 const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
40724039
4073 return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, &.{
4040 return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{
40744041 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),
40754042 });
40764043 },
......@@ -4092,9 +4059,9 @@ pub const Object = struct {
40924059 return parent_ptr;
40934060 }
40944061
4095 return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{
4096 try o.builder.intConst(.i32, 0),
4097 try o.builder.intConst(.i32, @intFromBool(
4062 const parent_llvm_ty = try o.lowerType(parent_ty);
4063 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4064 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, @intFromBool(
40984065 layout.tag_size > 0 and layout.tag_align >= layout.payload_align,
40994066 )),
41004067 });
......@@ -4109,7 +4076,8 @@ pub const Object = struct {
41094076 const prev_bits = b: {
41104077 var b: usize = 0;
41114078 for (parent_ty.structFields(mod).values()[0..field_index]) |field| {
4112 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
4079 if (field.is_comptime) continue;
4080 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
41134081 b += @intCast(field.ty.bitSize(mod));
41144082 }
41154083 break :b b;
......@@ -4123,6 +4091,7 @@ pub const Object = struct {
41234091 .inbounds,
41244092 try o.lowerType(parent_ty),
41254093 parent_ptr,
4094 null,
41264095 if (llvmField(parent_ty, field_index, mod)) |llvm_field| &.{
41274096 try o.builder.intConst(.i32, 0),
41284097 try o.builder.intConst(.i32, llvm_field.index),
......@@ -4135,9 +4104,9 @@ pub const Object = struct {
41354104 },
41364105 .Pointer => {
41374106 assert(parent_ty.isSlice(mod));
4138 return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{
4139 try o.builder.intConst(.i32, 0),
4140 try o.builder.intConst(.i32, field_index),
4107 const parent_llvm_ty = try o.lowerType(parent_ty);
4108 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4109 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, field_index),
41414110 });
41424111 },
41434112 else => unreachable,
......@@ -4167,8 +4136,7 @@ pub const Object = struct {
41674136
41684137 const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn;
41694138 if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or
4170 (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic))
4171 return o.lowerPtrToVoid(ty);
4139 (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) return o.lowerPtrToVoid(ty);
41724140
41734141 try mod.markDeclAlive(decl);
41744142
......@@ -4240,7 +4208,7 @@ pub const Object = struct {
42404208 ) void {
42414209 const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
42424210 assert(kind_id != 0);
4243 const llvm_attr = o.context.createEnumAttribute(kind_id, int);
4211 const llvm_attr = o.builder.llvm.context.createEnumAttribute(kind_id, int);
42444212 val.addAttributeAtIndex(index, llvm_attr);
42454213 }
42464214
......@@ -4251,7 +4219,7 @@ pub const Object = struct {
42514219 name: []const u8,
42524220 value: []const u8,
42534221 ) void {
4254 const llvm_attr = o.context.createStringAttribute(
4222 const llvm_attr = o.builder.llvm.context.createStringAttribute(
42554223 name.ptr,
42564224 @intCast(name.len),
42574225 value.ptr,
......@@ -4346,51 +4314,6 @@ pub const Object = struct {
43464314 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));
43474315 }
43484316 }
4349
4350 fn buildAllocaInner(
4351 o: *Object,
4352 wip: *Builder.WipFunction,
4353 builder: *llvm.Builder,
4354 llvm_func: *llvm.Value,
4355 di_scope_non_null: bool,
4356 llvm_ty: *llvm.Type,
4357 maybe_alignment: ?c_uint,
4358 target: std.Target,
4359 ) Allocator.Error!*llvm.Value {
4360 const address_space = llvmAllocaAddressSpace(target);
4361
4362 const alloca = blk: {
4363 const prev_cursor = wip.cursor;
4364 const prev_block = builder.getInsertBlock();
4365 const prev_debug_location = builder.getCurrentDebugLocation2();
4366 defer {
4367 wip.cursor = prev_cursor;
4368 builder.positionBuilderAtEnd(prev_block);
4369 if (di_scope_non_null) {
4370 builder.setCurrentDebugLocation2(prev_debug_location);
4371 }
4372 }
4373
4374 const entry_block = llvm_func.getFirstBasicBlock().?;
4375 wip.cursor = .{ .block = .entry };
4376 builder.positionBuilder(entry_block, entry_block.getFirstInstruction());
4377 builder.clearCurrentDebugLocation();
4378
4379 break :blk builder.buildAllocaInAddressSpace(llvm_ty, @intFromEnum(address_space), "");
4380 };
4381
4382 if (maybe_alignment) |alignment| {
4383 alloca.setAlignment(alignment);
4384 }
4385
4386 // The pointer returned from this function should have the generic address space,
4387 // if this isn't the case then cast it to the generic address space.
4388 if (address_space != .default) {
4389 return builder.buildAddrSpaceCast(alloca, Builder.Type.ptr.toLlvm(&o.builder), "");
4390 }
4391
4392 return alloca;
4393 }
43944317};
43954318
43964319pub const DeclGen = struct {
......@@ -4424,10 +4347,10 @@ pub const DeclGen = struct {
44244347 const variable = try o.resolveGlobalDecl(decl_index);
44254348 const global = variable.ptrConst(&o.builder).global;
44264349 var llvm_global = global.toLlvm(&o.builder);
4427 global.ptr(&o.builder).alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod));
4350 variable.ptr(&o.builder).alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod));
44284351 llvm_global.setAlignment(decl.getAlignment(mod));
44294352 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| {
4430 global.ptr(&o.builder).section = try o.builder.string(section);
4353 variable.ptr(&o.builder).section = try o.builder.string(section);
44314354 llvm_global.setSection(section);
44324355 }
44334356 assert(decl.has_tv);
......@@ -4439,10 +4362,7 @@ pub const DeclGen = struct {
44394362 if (init_val != .none) {
44404363 const llvm_init = try o.lowerValue(init_val);
44414364 const llvm_init_ty = llvm_init.typeOf(&o.builder);
4442 global.ptr(&o.builder).type = llvm_init_ty;
4443 variable.ptr(&o.builder).mutability = .global;
4444 variable.ptr(&o.builder).init = llvm_init;
4445 if (llvm_global.globalGetValueType() == llvm_init.typeOf(&o.builder).toLlvm(&o.builder)) {
4365 if (global.ptrConst(&o.builder).type == llvm_init_ty) {
44464366 llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));
44474367 } else {
44484368 // LLVM does not allow us to change the type of globals. So we must
......@@ -4477,7 +4397,10 @@ pub const DeclGen = struct {
44774397 new_global;
44784398 llvm_global.deleteGlobal();
44794399 llvm_global = new_global;
4400 variable.ptr(&o.builder).mutability = .global;
4401 global.ptr(&o.builder).type = llvm_init_ty;
44804402 }
4403 variable.ptr(&o.builder).init = llvm_init;
44814404 }
44824405
44834406 if (o.di_builder) |dib| {
......@@ -4508,7 +4431,6 @@ pub const FuncGen = struct {
45084431 air: Air,
45094432 liveness: Liveness,
45104433 wip: Builder.WipFunction,
4511 context: *llvm.Context,
45124434 builder: *llvm.Builder,
45134435 di_scope: ?*llvm.DIScope,
45144436 di_file: ?*llvm.DIFile,
......@@ -4525,26 +4447,24 @@ pub const FuncGen = struct {
45254447
45264448 /// This stores the LLVM values used in a function, such that they can be referred to
45274449 /// in other instructions. This table is cleared before every function is generated.
4528 func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, *llvm.Value),
4450 func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, Builder.Value),
45294451
45304452 /// If the return type is sret, this is the result pointer. Otherwise null.
45314453 /// Note that this can disagree with isByRef for the return type in the case
45324454 /// of C ABI functions.
4533 ret_ptr: ?*llvm.Value,
4455 ret_ptr: Builder.Value,
45344456 /// Any function that needs to perform Valgrind client requests needs an array alloca
45354457 /// instruction, however a maximum of one per function is needed.
4536 valgrind_client_request_array: ?*llvm.Value = null,
4458 valgrind_client_request_array: Builder.Value = .none,
45374459 /// These fields are used to refer to the LLVM value of the function parameters
45384460 /// in an Arg instruction.
45394461 /// This list may be shorter than the list according to the zig type system;
45404462 /// it omits 0-bit types. If the function uses sret as the first parameter,
45414463 /// this slice does not include it.
4542 args: []const *llvm.Value,
4543 arg_index: c_uint,
4464 args: []const Builder.Value,
4465 arg_index: usize,
45444466
4545 llvm_func: *llvm.Value,
4546
4547 err_ret_trace: ?*llvm.Value = null,
4467 err_ret_trace: Builder.Value = .none,
45484468
45494469 /// This data structure is used to implement breaking to blocks.
45504470 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
......@@ -4552,13 +4472,16 @@ pub const FuncGen = struct {
45524472 breaks: *BreakList,
45534473 }),
45544474
4555 single_threaded: bool,
4475 sync_scope: Builder.SyncScope,
45564476
45574477 const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };
4558 const BreakList = std.MultiArrayList(struct {
4559 bb: *llvm.BasicBlock,
4560 val: *llvm.Value,
4561 });
4478 const BreakList = union {
4479 list: std.MultiArrayList(struct {
4480 bb: Builder.Function.Block.Index,
4481 val: Builder.Value,
4482 }),
4483 len: usize,
4484 };
45624485
45634486 fn deinit(self: *FuncGen) void {
45644487 self.wip.deinit();
......@@ -4573,7 +4496,7 @@ pub const FuncGen = struct {
45734496 return self.dg.todo(format, args);
45744497 }
45754498
4576 fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !*llvm.Value {
4499 fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !Builder.Value {
45774500 const gpa = self.gpa;
45784501 const gop = try self.func_inst_table.getOrPut(gpa, inst);
45794502 if (gop.found_existing) return gop.value_ptr.*;
......@@ -4584,8 +4507,8 @@ pub const FuncGen = struct {
45844507 .ty = self.typeOf(inst),
45854508 .val = (try self.air.value(inst, mod)).?,
45864509 });
4587 gop.value_ptr.* = llvm_val.toLlvm(&o.builder);
4588 return gop.value_ptr.*;
4510 gop.value_ptr.* = llvm_val.toValue();
4511 return llvm_val.toValue();
45894512 }
45904513
45914514 fn resolveValue(self: *FuncGen, tv: TypedValue) Error!Builder.Constant {
......@@ -4613,19 +4536,19 @@ pub const FuncGen = struct {
46134536 .unnamed_addr = .unnamed_addr,
46144537 .addr_space = llvm_actual_addrspace,
46154538 .type = llvm_ty,
4616 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),
46174539 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
46184540 };
46194541 var variable = Builder.Variable{
46204542 .global = @enumFromInt(o.builder.globals.count()),
46214543 .mutability = .constant,
46224544 .init = llvm_val,
4545 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),
46234546 };
46244547 try o.builder.llvm.globals.append(o.gpa, llvm_global);
46254548 const global_index = try o.builder.addGlobal(.empty, global);
46264549 try o.builder.variables.append(o.gpa, variable);
46274550
4628 return try o.builder.convConst(
4551 return o.builder.convConst(
46294552 .unneeded,
46304553 global_index.toConst(),
46314554 try o.builder.ptrType(llvm_wanted_addrspace),
......@@ -4651,10 +4574,9 @@ pub const FuncGen = struct {
46514574 const ip = &mod.intern_pool;
46524575 const air_tags = self.air.instructions.items(.tag);
46534576 for (body, 0..) |inst, i| {
4654 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip))
4655 continue;
4577 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;
46564578
4657 const opt_value: ?*llvm.Value = switch (air_tags[inst]) {
4579 const val: Builder.Value = switch (air_tags[inst]) {
46584580 // zig fmt: off
46594581 .add => try self.airAdd(inst, false),
46604582 .add_optimized => try self.airAdd(inst, true),
......@@ -4745,15 +4667,15 @@ pub const FuncGen = struct {
47454667 .cmp_vector_optimized => try self.airCmpVector(inst, true),
47464668 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
47474669
4748 .is_non_null => try self.airIsNonNull(inst, false, .NE),
4749 .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE),
4750 .is_null => try self.airIsNonNull(inst, false, .EQ),
4751 .is_null_ptr => try self.airIsNonNull(inst, true , .EQ),
4670 .is_non_null => try self.airIsNonNull(inst, false, .ne),
4671 .is_non_null_ptr => try self.airIsNonNull(inst, true , .ne),
4672 .is_null => try self.airIsNonNull(inst, false, .eq),
4673 .is_null_ptr => try self.airIsNonNull(inst, true , .eq),
47524674
4753 .is_non_err => try self.airIsErr(inst, .EQ, false),
4754 .is_non_err_ptr => try self.airIsErr(inst, .EQ, true),
4755 .is_err => try self.airIsErr(inst, .NE, false),
4756 .is_err_ptr => try self.airIsErr(inst, .NE, true),
4675 .is_non_err => try self.airIsErr(inst, .eq, false),
4676 .is_non_err_ptr => try self.airIsErr(inst, .eq, true),
4677 .is_err => try self.airIsErr(inst, .ne, false),
4678 .is_err_ptr => try self.airIsErr(inst, .ne, true),
47574679
47584680 .alloc => try self.airAlloc(inst),
47594681 .ret_ptr => try self.airRetPtr(inst),
......@@ -4830,10 +4752,10 @@ pub const FuncGen = struct {
48304752 .reduce => try self.airReduce(inst, false),
48314753 .reduce_optimized => try self.airReduce(inst, true),
48324754
4833 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
4834 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
4835 .atomic_store_release => try self.airAtomicStore(inst, .Release),
4836 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SequentiallyConsistent),
4755 .atomic_store_unordered => try self.airAtomicStore(inst, .unordered),
4756 .atomic_store_monotonic => try self.airAtomicStore(inst, .monotonic),
4757 .atomic_store_release => try self.airAtomicStore(inst, .release),
4758 .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst),
48374759
48384760 .struct_field_ptr => try self.airStructFieldPtr(inst),
48394761 .struct_field_val => try self.airStructFieldVal(body[i..]),
......@@ -4875,8 +4797,8 @@ pub const FuncGen = struct {
48754797
48764798 .inferred_alloc, .inferred_alloc_comptime => unreachable,
48774799
4878 .unreach => self.airUnreach(inst),
4879 .dbg_stmt => self.airDbgStmt(inst),
4800 .unreach => try self.airUnreach(inst),
4801 .dbg_stmt => try self.airDbgStmt(inst),
48804802 .dbg_inline_begin => try self.airDbgInlineBegin(inst),
48814803 .dbg_inline_end => try self.airDbgInlineEnd(inst),
48824804 .dbg_block_begin => try self.airDbgBlockBegin(),
......@@ -4894,14 +4816,11 @@ pub const FuncGen = struct {
48944816 .work_group_id => try self.airWorkGroupId(inst),
48954817 // zig fmt: on
48964818 };
4897 if (opt_value) |val| {
4898 const ref = Air.indexToRef(inst);
4899 try self.func_inst_table.putNoClobber(self.gpa, ref, val);
4900 }
4819 if (val != .none) try self.func_inst_table.putNoClobber(self.gpa, Air.indexToRef(inst), val);
49014820 }
49024821 }
49034822
4904 fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !?*llvm.Value {
4823 fn airCall(self: *FuncGen, inst: Air.Inst.Index, attr: llvm.CallAttr) !Builder.Value {
49054824 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
49064825 const extra = self.air.extraData(Air.Call, pl_op.payload);
49074826 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
......@@ -4924,16 +4843,18 @@ pub const FuncGen = struct {
49244843 defer llvm_args.deinit();
49254844
49264845 const ret_ptr = if (!sret) null else blk: {
4927 const llvm_ret_ty = (try o.lowerType(return_type)).toLlvm(&o.builder);
4928 const ret_ptr = try self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(mod));
4929 try llvm_args.append(ret_ptr);
4846 const llvm_ret_ty = try o.lowerType(return_type);
4847 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
4848 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
4849 try llvm_args.append(ret_ptr.toLlvm(&self.wip));
49304850 break :blk ret_ptr;
49314851 };
49324852
49334853 const err_return_tracing = return_type.isError(mod) and
49344854 o.module.comp.bin_file.options.error_return_tracing;
49354855 if (err_return_tracing) {
4936 try llvm_args.append(self.err_ret_trace.?);
4856 assert(self.err_ret_trace != .none);
4857 try llvm_args.append(self.err_ret_trace.toLlvm(&self.wip));
49374858 }
49384859
49394860 var it = iterateParamTypes(o, fn_info);
......@@ -4943,14 +4864,13 @@ pub const FuncGen = struct {
49434864 const arg = args[it.zig_index - 1];
49444865 const param_ty = self.typeOf(arg);
49454866 const llvm_arg = try self.resolveInst(arg);
4946 const llvm_param_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);
4867 const llvm_param_ty = try o.lowerType(param_ty);
49474868 if (isByRef(param_ty, mod)) {
4948 const alignment = param_ty.abiAlignment(mod);
4949 const load_inst = self.builder.buildLoad(llvm_param_ty, llvm_arg, "");
4950 load_inst.setAlignment(alignment);
4951 try llvm_args.append(load_inst);
4869 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4870 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
4871 try llvm_args.append(loaded.toLlvm(&self.wip));
49524872 } else {
4953 try llvm_args.append(llvm_arg);
4873 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
49544874 }
49554875 },
49564876 .byref => {
......@@ -4958,14 +4878,13 @@ pub const FuncGen = struct {
49584878 const param_ty = self.typeOf(arg);
49594879 const llvm_arg = try self.resolveInst(arg);
49604880 if (isByRef(param_ty, mod)) {
4961 try llvm_args.append(llvm_arg);
4881 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
49624882 } else {
4963 const alignment = param_ty.abiAlignment(mod);
4964 const param_llvm_ty = llvm_arg.typeOf();
4883 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4884 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
49654885 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
4966 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
4967 store_inst.setAlignment(alignment);
4968 try llvm_args.append(arg_ptr);
4886 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
4887 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
49694888 }
49704889 },
49714890 .byref_mut => {
......@@ -4973,56 +4892,46 @@ pub const FuncGen = struct {
49734892 const param_ty = self.typeOf(arg);
49744893 const llvm_arg = try self.resolveInst(arg);
49754894
4976 const alignment = param_ty.abiAlignment(mod);
4977 const param_llvm_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);
4895 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4896 const param_llvm_ty = try o.lowerType(param_ty);
49784897 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
49794898 if (isByRef(param_ty, mod)) {
4980 const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, "");
4981 load_inst.setAlignment(alignment);
4982
4983 const store_inst = self.builder.buildStore(load_inst, arg_ptr);
4984 store_inst.setAlignment(alignment);
4985 try llvm_args.append(arg_ptr);
4899 const loaded = try self.wip.load(.normal, param_llvm_ty, llvm_arg, alignment, "");
4900 _ = try self.wip.store(.normal, loaded, arg_ptr, alignment);
49864901 } else {
4987 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
4988 store_inst.setAlignment(alignment);
4989 try llvm_args.append(arg_ptr);
4902 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
49904903 }
4904 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
49914905 },
49924906 .abi_sized_int => {
49934907 const arg = args[it.zig_index - 1];
49944908 const param_ty = self.typeOf(arg);
49954909 const llvm_arg = try self.resolveInst(arg);
4996 const int_llvm_ty = (try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8))).toLlvm(&o.builder);
4910 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
49974911
49984912 if (isByRef(param_ty, mod)) {
4999 const alignment = param_ty.abiAlignment(mod);
5000 const load_inst = self.builder.buildLoad(int_llvm_ty, llvm_arg, "");
5001 load_inst.setAlignment(alignment);
5002 try llvm_args.append(load_inst);
4913 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4914 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
4915 try llvm_args.append(loaded.toLlvm(&self.wip));
50034916 } else {
50044917 // LLVM does not allow bitcasting structs so we must allocate
50054918 // a local, store as one type, and then load as another type.
5006 const alignment = @max(
4919 const alignment = Builder.Alignment.fromByteUnits(@max(
50074920 param_ty.abiAlignment(mod),
5008 o.target_data.abiAlignmentOfType(int_llvm_ty),
5009 );
4921 o.target_data.abiAlignmentOfType(int_llvm_ty.toLlvm(&o.builder)),
4922 ));
50104923 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
5011 const store_inst = self.builder.buildStore(llvm_arg, int_ptr);
5012 store_inst.setAlignment(alignment);
5013 const load_inst = self.builder.buildLoad(int_llvm_ty, int_ptr, "");
5014 load_inst.setAlignment(alignment);
5015 try llvm_args.append(load_inst);
4924 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
4925 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
4926 try llvm_args.append(loaded.toLlvm(&self.wip));
50164927 }
50174928 },
50184929 .slice => {
50194930 const arg = args[it.zig_index - 1];
50204931 const llvm_arg = try self.resolveInst(arg);
5021 const ptr = self.builder.buildExtractValue(llvm_arg, 0, "");
5022 const len = self.builder.buildExtractValue(llvm_arg, 1, "");
5023 try llvm_args.ensureUnusedCapacity(2);
5024 llvm_args.appendAssumeCapacity(ptr);
5025 llvm_args.appendAssumeCapacity(len);
4932 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
4933 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");
4934 try llvm_args.appendSlice(&.{ ptr.toLlvm(&self.wip), len.toLlvm(&self.wip) });
50264935 },
50274936 .multiple_llvm_types => {
50284937 const arg = args[it.zig_index - 1];
......@@ -5030,75 +4939,77 @@ pub const FuncGen = struct {
50304939 const llvm_types = it.types_buffer[0..it.types_len];
50314940 const llvm_arg = try self.resolveInst(arg);
50324941 const is_by_ref = isByRef(param_ty, mod);
5033 const arg_ptr = if (is_by_ref) llvm_arg else p: {
5034 const p = try self.buildAlloca(llvm_arg.typeOf(), null);
5035 const store_inst = self.builder.buildStore(llvm_arg, p);
5036 store_inst.setAlignment(param_ty.abiAlignment(mod));
5037 break :p p;
4942 const arg_ptr = if (is_by_ref) llvm_arg else ptr: {
4943 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4944 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
4945 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
4946 break :ptr ptr;
50384947 };
50394948
5040 const llvm_ty = (try o.builder.structType(.normal, llvm_types)).toLlvm(&o.builder);
4949 const llvm_ty = try o.builder.structType(.normal, llvm_types);
50414950 try llvm_args.ensureUnusedCapacity(it.types_len);
50424951 for (llvm_types, 0..) |field_ty, i| {
5043 const field_ptr = self.builder.buildStructGEP(llvm_ty, arg_ptr, @intCast(i), "");
5044 const load_inst = self.builder.buildLoad(field_ty.toLlvm(&o.builder), field_ptr, "");
5045 load_inst.setAlignment(target.ptrBitWidth() / 8);
5046 llvm_args.appendAssumeCapacity(load_inst);
4952 const alignment =
4953 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
4954 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");
4955 const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");
4956 llvm_args.appendAssumeCapacity(loaded.toLlvm(&self.wip));
50474957 }
50484958 },
50494959 .as_u16 => {
50504960 const arg = args[it.zig_index - 1];
50514961 const llvm_arg = try self.resolveInst(arg);
5052 const casted = self.builder.buildBitCast(llvm_arg, Builder.Type.i16.toLlvm(&o.builder), "");
5053 try llvm_args.append(casted);
4962 const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");
4963 try llvm_args.append(casted.toLlvm(&self.wip));
50544964 },
50554965 .float_array => |count| {
50564966 const arg = args[it.zig_index - 1];
50574967 const arg_ty = self.typeOf(arg);
50584968 var llvm_arg = try self.resolveInst(arg);
4969 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
50594970 if (!isByRef(arg_ty, mod)) {
5060 const p = try self.buildAlloca(llvm_arg.typeOf(), null);
5061 const store_inst = self.builder.buildStore(llvm_arg, p);
5062 store_inst.setAlignment(arg_ty.abiAlignment(mod));
5063 llvm_arg = store_inst;
4971 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
4972 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
4973 llvm_arg = ptr;
50644974 }
50654975
50664976 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, mod).?);
50674977 const array_ty = try o.builder.arrayType(count, float_ty);
50684978
5069 const alignment = arg_ty.abiAlignment(mod);
5070 const load_inst = self.builder.buildLoad(array_ty.toLlvm(&o.builder), llvm_arg, "");
5071 load_inst.setAlignment(alignment);
5072 try llvm_args.append(load_inst);
4979 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
4980 try llvm_args.append(loaded.toLlvm(&self.wip));
50734981 },
50744982 .i32_array, .i64_array => |arr_len| {
50754983 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
50764984 const arg = args[it.zig_index - 1];
50774985 const arg_ty = self.typeOf(arg);
50784986 var llvm_arg = try self.resolveInst(arg);
4987 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
50794988 if (!isByRef(arg_ty, mod)) {
5080 const p = try self.buildAlloca(llvm_arg.typeOf(), null);
5081 const store_inst = self.builder.buildStore(llvm_arg, p);
5082 store_inst.setAlignment(arg_ty.abiAlignment(mod));
5083 llvm_arg = store_inst;
4989 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
4990 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
4991 llvm_arg = ptr;
50844992 }
50854993
5086 const array_ty = try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
5087 const alignment = arg_ty.abiAlignment(mod);
5088 const load_inst = self.builder.buildLoad(array_ty.toLlvm(&o.builder), llvm_arg, "");
5089 load_inst.setAlignment(alignment);
5090 try llvm_args.append(load_inst);
4994 const array_ty =
4995 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
4996 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
4997 try llvm_args.append(loaded.toLlvm(&self.wip));
50914998 },
50924999 };
50935000
5094 const call = self.builder.buildCall(
5095 (try o.lowerType(zig_fn_ty)).toLlvm(&o.builder),
5096 llvm_fn,
5097 llvm_args.items.ptr,
5098 @intCast(llvm_args.items.len),
5099 toLlvmCallConv(fn_info.cc, target),
5100 attr,
5101 "",
5001 const llvm_fn_ty = try o.lowerType(zig_fn_ty);
5002 const call = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
5003 self.builder.buildCall(
5004 llvm_fn_ty.toLlvm(&o.builder),
5005 llvm_fn.toLlvm(&self.wip),
5006 llvm_args.items.ptr,
5007 @intCast(llvm_args.items.len),
5008 toLlvmCallConv(fn_info.cc, target),
5009 attr,
5010 "",
5011 ),
5012 &self.wip,
51025013 );
51035014
51045015 if (callee_ty.zigTypeTag(mod) == .Pointer) {
......@@ -5111,7 +5022,7 @@ pub const FuncGen = struct {
51115022 const param_index = it.zig_index - 1;
51125023 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
51135024 if (!isByRef(param_ty, mod)) {
5114 o.addByValParamAttrs(call, param_ty, param_index, fn_info, it.llvm_index - 1);
5025 o.addByValParamAttrs(call.toLlvm(&self.wip), param_ty, param_index, fn_info, it.llvm_index - 1);
51155026 }
51165027 },
51175028 .byref => {
......@@ -5119,10 +5030,10 @@ pub const FuncGen = struct {
51195030 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
51205031 const param_llvm_ty = try o.lowerType(param_ty);
51215032 const alignment = param_ty.abiAlignment(mod);
5122 o.addByRefParamAttrs(call, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
5033 o.addByRefParamAttrs(call.toLlvm(&self.wip), it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
51235034 },
51245035 .byref_mut => {
5125 o.addArgAttr(call, it.llvm_index - 1, "noundef");
5036 o.addArgAttr(call.toLlvm(&self.wip), it.llvm_index - 1, "noundef");
51265037 },
51275038 // No attributes needed for these.
51285039 .no_bits,
......@@ -5142,70 +5053,63 @@ pub const FuncGen = struct {
51425053
51435054 if (math.cast(u5, it.zig_index - 1)) |i| {
51445055 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
5145 o.addArgAttr(call, llvm_arg_i, "noalias");
5056 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "noalias");
51465057 }
51475058 }
51485059 if (param_ty.zigTypeTag(mod) != .Optional) {
5149 o.addArgAttr(call, llvm_arg_i, "nonnull");
5060 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "nonnull");
51505061 }
51515062 if (ptr_info.flags.is_const) {
5152 o.addArgAttr(call, llvm_arg_i, "readonly");
5063 o.addArgAttr(call.toLlvm(&self.wip), llvm_arg_i, "readonly");
51535064 }
51545065 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
51555066 @max(ptr_info.child.toType().abiAlignment(mod), 1);
5156 o.addArgAttrInt(call, llvm_arg_i, "align", elem_align);
5067 o.addArgAttrInt(call.toLlvm(&self.wip), llvm_arg_i, "align", elem_align);
51575068 },
51585069 };
51595070 }
51605071
51615072 if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {
5162 return null;
5073 return .none;
51635074 }
51645075
51655076 if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime(mod)) {
5166 return null;
5077 return .none;
51675078 }
51685079
5169 const llvm_ret_ty = (try o.lowerType(return_type)).toLlvm(&o.builder);
5080 const llvm_ret_ty = try o.lowerType(return_type);
51705081
51715082 if (ret_ptr) |rp| {
5172 call.setCallSret(llvm_ret_ty);
5083 call.toLlvm(&self.wip).setCallSret(llvm_ret_ty.toLlvm(&o.builder));
51735084 if (isByRef(return_type, mod)) {
51745085 return rp;
51755086 } else {
51765087 // our by-ref status disagrees with sret so we must load.
5177 const loaded = self.builder.buildLoad(llvm_ret_ty, rp, "");
5178 loaded.setAlignment(return_type.abiAlignment(mod));
5179 return loaded;
5088 const return_alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
5089 return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, "");
51805090 }
51815091 }
51825092
5183 const abi_ret_ty = (try lowerFnRetTy(o, fn_info)).toLlvm(&o.builder);
5093 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
51845094
51855095 if (abi_ret_ty != llvm_ret_ty) {
51865096 // In this case the function return type is honoring the calling convention by having
51875097 // a different LLVM type than the usual one. We solve this here at the callsite
51885098 // by using our canonical type, then loading it if necessary.
5189 const alignment = o.target_data.abiAlignmentOfType(abi_ret_ty);
5190 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5191 const store_inst = self.builder.buildStore(call, rp);
5192 store_inst.setAlignment(alignment);
5193 if (isByRef(return_type, mod)) {
5194 return rp;
5195 } else {
5196 const load_inst = self.builder.buildLoad(llvm_ret_ty, rp, "");
5197 load_inst.setAlignment(alignment);
5198 return load_inst;
5199 }
5099 const rp = try self.buildAlloca(llvm_ret_ty, .default);
5100 _ = try self.wip.store(.normal, call, rp, .default);
5101 return if (isByRef(return_type, mod))
5102 rp
5103 else
5104 try self.wip.load(.normal, llvm_ret_ty, rp, .default, "");
52005105 }
52015106
52025107 if (isByRef(return_type, mod)) {
52035108 // our by-ref status disagrees with sret so we must allocate, store,
52045109 // and return the allocation pointer.
5205 const alignment = return_type.abiAlignment(mod);
5110 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
52065111 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5207 const store_inst = self.builder.buildStore(call, rp);
5208 store_inst.setAlignment(alignment);
5112 _ = try self.wip.store(.normal, call, rp, alignment);
52095113 return rp;
52105114 } else {
52115115 return call;
......@@ -5239,7 +5143,7 @@ pub const FuncGen = struct {
52395143 const panic_decl = mod.declPtr(panic_func.owner_decl);
52405144 const fn_info = mod.typeToFunc(panic_decl.ty).?;
52415145 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);
5242 _ = fg.builder.buildCall(
5146 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildCall(
52435147 (try o.lowerType(panic_decl.ty)).toLlvm(&o.builder),
52445148 panic_global.toLlvm(&o.builder),
52455149 &args,
......@@ -5247,21 +5151,21 @@ pub const FuncGen = struct {
52475151 toLlvmCallConv(fn_info.cc, target),
52485152 .Auto,
52495153 "",
5250 );
5251 _ = fg.builder.buildUnreachable();
5154 ), &fg.wip);
5155 _ = try fg.wip.@"unreachable"();
52525156 }
52535157
5254 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5158 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
52555159 const o = self.dg.object;
52565160 const mod = o.module;
52575161 const un_op = self.air.instructions.items(.data)[inst].un_op;
52585162 const ret_ty = self.typeOf(un_op);
5259 if (self.ret_ptr) |ret_ptr| {
5163 if (self.ret_ptr != .none) {
52605164 const operand = try self.resolveInst(un_op);
52615165 const ptr_ty = try mod.singleMutPtrType(ret_ty);
5262 try self.store(ret_ptr, ptr_ty, operand, .NotAtomic);
5263 try self.wip.retVoid();
5264 return null;
5166 try self.store(self.ret_ptr, ptr_ty, operand, .none);
5167 _ = try self.wip.retVoid();
5168 return .none;
52655169 }
52665170 const fn_info = mod.typeToFunc(self.dg.decl.ty).?;
52675171 if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
......@@ -5269,43 +5173,37 @@ pub const FuncGen = struct {
52695173 // Functions with an empty error set are emitted with an error code
52705174 // return type and return zero so they can be function pointers coerced
52715175 // to functions that return anyerror.
5272 const int = try o.builder.intConst(Builder.Type.err_int, 0);
5273 _ = self.builder.buildRet(int.toLlvm(&o.builder));
5176 _ = try self.wip.ret(try o.builder.intValue(Builder.Type.err_int, 0));
52745177 } else {
5275 try self.wip.retVoid();
5178 _ = try self.wip.retVoid();
52765179 }
5277 return null;
5180 return .none;
52785181 }
52795182
5280 const abi_ret_ty = (try lowerFnRetTy(o, fn_info)).toLlvm(&o.builder);
5183 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
52815184 const operand = try self.resolveInst(un_op);
5282 const alignment = ret_ty.abiAlignment(mod);
5185 const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod));
52835186
52845187 if (isByRef(ret_ty, mod)) {
52855188 // operand is a pointer however self.ret_ptr is null so that means
52865189 // we need to return a value.
5287 const load_inst = self.builder.buildLoad(abi_ret_ty, operand, "");
5288 load_inst.setAlignment(alignment);
5289 _ = self.builder.buildRet(load_inst);
5290 return null;
5190 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, operand, alignment, ""));
5191 return .none;
52915192 }
52925193
5293 const llvm_ret_ty = operand.typeOf();
5194 const llvm_ret_ty = operand.typeOfWip(&self.wip);
52945195 if (abi_ret_ty == llvm_ret_ty) {
5295 _ = self.builder.buildRet(operand);
5296 return null;
5196 _ = try self.wip.ret(operand);
5197 return .none;
52975198 }
52985199
52995200 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5300 const store_inst = self.builder.buildStore(operand, rp);
5301 store_inst.setAlignment(alignment);
5302 const load_inst = self.builder.buildLoad(abi_ret_ty, rp, "");
5303 load_inst.setAlignment(alignment);
5304 _ = self.builder.buildRet(load_inst);
5305 return null;
5201 _ = try self.wip.store(.normal, operand, rp, alignment);
5202 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, rp, alignment, ""));
5203 return .none;
53065204 }
53075205
5308 fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5206 fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
53095207 const o = self.dg.object;
53105208 const mod = o.module;
53115209 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -5317,106 +5215,121 @@ pub const FuncGen = struct {
53175215 // Functions with an empty error set are emitted with an error code
53185216 // return type and return zero so they can be function pointers coerced
53195217 // to functions that return anyerror.
5320 const int = try o.builder.intConst(Builder.Type.err_int, 0);
5321 _ = self.builder.buildRet(int.toLlvm(&o.builder));
5218 _ = try self.wip.ret(try o.builder.intValue(Builder.Type.err_int, 0));
53225219 } else {
5323 try self.wip.retVoid();
5220 _ = try self.wip.retVoid();
53245221 }
5325 return null;
5222 return .none;
53265223 }
5327 if (self.ret_ptr != null) {
5328 try self.wip.retVoid();
5329 return null;
5224 if (self.ret_ptr != .none) {
5225 _ = try self.wip.retVoid();
5226 return .none;
53305227 }
53315228 const ptr = try self.resolveInst(un_op);
5332 const abi_ret_ty = (try lowerFnRetTy(o, fn_info)).toLlvm(&o.builder);
5333 const loaded = self.builder.buildLoad(abi_ret_ty, ptr, "");
5334 loaded.setAlignment(ret_ty.abiAlignment(mod));
5335 _ = self.builder.buildRet(loaded);
5336 return null;
5229 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
5230 const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod));
5231 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, ""));
5232 return .none;
53375233 }
53385234
5339 fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5235 fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
53405236 const o = self.dg.object;
53415237 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
53425238 const list = try self.resolveInst(ty_op.operand);
53435239 const arg_ty = self.air.getRefType(ty_op.ty);
5344 const llvm_arg_ty = (try o.lowerType(arg_ty)).toLlvm(&o.builder);
5240 const llvm_arg_ty = try o.lowerType(arg_ty);
53455241
5346 return self.builder.buildVAArg(list, llvm_arg_ty, "");
5242 return self.wip.vaArg(list, llvm_arg_ty, "");
53475243 }
53485244
5349 fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5245 fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
53505246 const o = self.dg.object;
53515247 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
53525248 const src_list = try self.resolveInst(ty_op.operand);
53535249 const va_list_ty = self.air.getRefType(ty_op.ty);
5354 const llvm_va_list_ty = (try o.lowerType(va_list_ty)).toLlvm(&o.builder);
5250 const llvm_va_list_ty = try o.lowerType(va_list_ty);
53555251 const mod = o.module;
53565252
5357 const result_alignment = va_list_ty.abiAlignment(mod);
5253 const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
53585254 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
53595255
53605256 const llvm_fn_name = "llvm.va_copy";
5361 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
5362 const fn_type = try o.builder.fnType(.void, &.{ .ptr, .ptr }, .normal);
5363 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));
5364 };
5257 const llvm_fn_ty = try o.builder.fnType(.void, &.{ .ptr, .ptr }, .normal);
5258 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5259 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
53655260
5366 const args: [2]*llvm.Value = .{ dest_list, src_list };
5367 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
5261 const args: [2]*llvm.Value = .{ dest_list.toLlvm(&self.wip), src_list.toLlvm(&self.wip) };
5262 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5263 llvm_fn_ty.toLlvm(&o.builder),
5264 llvm_fn,
5265 &args,
5266 args.len,
5267 .Fast,
5268 .Auto,
5269 "",
5270 ), &self.wip);
53685271
5369 if (isByRef(va_list_ty, mod)) {
5370 return dest_list;
5371 } else {
5372 const loaded = self.builder.buildLoad(llvm_va_list_ty, dest_list, "");
5373 loaded.setAlignment(result_alignment);
5374 return loaded;
5375 }
5272 return if (isByRef(va_list_ty, mod))
5273 dest_list
5274 else
5275 try self.wip.load(.normal, llvm_va_list_ty, dest_list, result_alignment, "");
53765276 }
53775277
5378 fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5278 fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
53795279 const o = self.dg.object;
53805280 const un_op = self.air.instructions.items(.data)[inst].un_op;
53815281 const list = try self.resolveInst(un_op);
53825282
53835283 const llvm_fn_name = "llvm.va_end";
5384 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
5385 const fn_type = try o.builder.fnType(.void, &.{.ptr}, .normal);
5386 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));
5387 };
5388 const args: [1]*llvm.Value = .{list};
5389 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
5390 return null;
5284 const llvm_fn_ty = try o.builder.fnType(.void, &.{.ptr}, .normal);
5285 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5286 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
5287
5288 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5289 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5290 llvm_fn_ty.toLlvm(&o.builder),
5291 llvm_fn,
5292 &args,
5293 args.len,
5294 .Fast,
5295 .Auto,
5296 "",
5297 ), &self.wip);
5298 return .none;
53915299 }
53925300
5393 fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5301 fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
53945302 const o = self.dg.object;
53955303 const mod = o.module;
53965304 const va_list_ty = self.typeOfIndex(inst);
5397 const llvm_va_list_ty = (try o.lowerType(va_list_ty)).toLlvm(&o.builder);
5305 const llvm_va_list_ty = try o.lowerType(va_list_ty);
53985306
5399 const result_alignment = va_list_ty.abiAlignment(mod);
5307 const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
54005308 const list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
54015309
54025310 const llvm_fn_name = "llvm.va_start";
5403 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
5404 const fn_type = try o.builder.fnType(.void, &.{.ptr}, .normal);
5405 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));
5406 };
5407 const args: [1]*llvm.Value = .{list};
5408 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
5311 const llvm_fn_ty = try o.builder.fnType(.void, &.{.ptr}, .normal);
5312 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5313 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
54095314
5410 if (isByRef(va_list_ty, mod)) {
5411 return list;
5412 } else {
5413 const loaded = self.builder.buildLoad(llvm_va_list_ty, list, "");
5414 loaded.setAlignment(result_alignment);
5415 return loaded;
5416 }
5315 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5316 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5317 llvm_fn_ty.toLlvm(&o.builder),
5318 llvm_fn,
5319 &args,
5320 args.len,
5321 .Fast,
5322 .Auto,
5323 "",
5324 ), &self.wip);
5325
5326 return if (isByRef(va_list_ty, mod))
5327 list
5328 else
5329 try self.wip.load(.normal, llvm_va_list_ty, list, result_alignment, "");
54175330 }
54185331
5419 fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*llvm.Value {
5332 fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !Builder.Value {
54205333 self.builder.setFastMath(want_fast_math);
54215334
54225335 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -5427,7 +5340,7 @@ pub const FuncGen = struct {
54275340 return self.cmp(lhs, rhs, operand_ty, op);
54285341 }
54295342
5430 fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
5343 fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
54315344 self.builder.setFastMath(want_fast_math);
54325345
54335346 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -5441,21 +5354,30 @@ pub const FuncGen = struct {
54415354 return self.cmp(lhs, rhs, vec_ty, cmp_op);
54425355 }
54435356
5444 fn airCmpLtErrorsLen(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5357 fn airCmpLtErrorsLen(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5358 const o = self.dg.object;
54455359 const un_op = self.air.instructions.items(.data)[inst].un_op;
54465360 const operand = try self.resolveInst(un_op);
54475361 const llvm_fn = try self.getCmpLtErrorsLenFunction();
5448 const args: [1]*llvm.Value = .{operand};
5449 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
5362 const args: [1]*llvm.Value = .{operand.toLlvm(&self.wip)};
5363 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(
5364 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
5365 llvm_fn.toLlvm(&o.builder),
5366 &args,
5367 args.len,
5368 .Fast,
5369 .Auto,
5370 "",
5371 ), &self.wip);
54505372 }
54515373
54525374 fn cmp(
54535375 self: *FuncGen,
5454 lhs: *llvm.Value,
5455 rhs: *llvm.Value,
5376 lhs: Builder.Value,
5377 rhs: Builder.Value,
54565378 operand_ty: Type,
54575379 op: math.CompareOperator,
5458 ) Allocator.Error!*llvm.Value {
5380 ) Allocator.Error!Builder.Value {
54595381 const o = self.dg.object;
54605382 const mod = o.module;
54615383 const scalar_ty = operand_ty.scalarType(mod);
......@@ -5472,50 +5394,48 @@ pub const FuncGen = struct {
54725394 // We need to emit instructions to check for equality/inequality
54735395 // of optionals that are not pointers.
54745396 const is_by_ref = isByRef(scalar_ty, mod);
5475 const opt_llvm_ty = (try o.lowerType(scalar_ty)).toLlvm(&o.builder);
5476 const lhs_non_null = try self.optIsNonNull(opt_llvm_ty, lhs, is_by_ref);
5477 const rhs_non_null = try self.optIsNonNull(opt_llvm_ty, rhs, is_by_ref);
5397 const opt_llvm_ty = try o.lowerType(scalar_ty);
5398 const lhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, lhs, is_by_ref);
5399 const rhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, rhs, is_by_ref);
54785400 const llvm_i2 = try o.builder.intType(2);
5479 const lhs_non_null_i2 = self.builder.buildZExt(lhs_non_null, llvm_i2.toLlvm(&o.builder), "");
5480 const rhs_non_null_i2 = self.builder.buildZExt(rhs_non_null, llvm_i2.toLlvm(&o.builder), "");
5481 const lhs_shifted = self.builder.buildShl(lhs_non_null_i2, (try o.builder.intConst(llvm_i2, 1)).toLlvm(&o.builder), "");
5482 const lhs_rhs_ored = self.builder.buildOr(lhs_shifted, rhs_non_null_i2, "");
5483 const both_null_block = try self.wip.block("BothNull");
5484 const mixed_block = try self.wip.block("Mixed");
5485 const both_pl_block = try self.wip.block("BothNonNull");
5486 const end_block = try self.wip.block("End");
5487 const llvm_switch = self.builder.buildSwitch(lhs_rhs_ored, mixed_block.toLlvm(&self.wip), 2);
5488 const llvm_i2_00 = try o.builder.intConst(llvm_i2, 0b00);
5489 const llvm_i2_11 = try o.builder.intConst(llvm_i2, 0b11);
5490 llvm_switch.addCase(llvm_i2_00.toLlvm(&o.builder), both_null_block.toLlvm(&self.wip));
5491 llvm_switch.addCase(llvm_i2_11.toLlvm(&o.builder), both_pl_block.toLlvm(&self.wip));
5401 const lhs_non_null_i2 = try self.wip.cast(.zext, lhs_non_null, llvm_i2, "");
5402 const rhs_non_null_i2 = try self.wip.cast(.zext, rhs_non_null, llvm_i2, "");
5403 const lhs_shifted = try self.wip.bin(.shl, lhs_non_null_i2, try o.builder.intValue(llvm_i2, 1), "");
5404 const lhs_rhs_ored = try self.wip.bin(.@"or", lhs_shifted, rhs_non_null_i2, "");
5405 const both_null_block = try self.wip.block(1, "BothNull");
5406 const mixed_block = try self.wip.block(1, "Mixed");
5407 const both_pl_block = try self.wip.block(1, "BothNonNull");
5408 const end_block = try self.wip.block(3, "End");
5409 var wip_switch = try self.wip.@"switch"(lhs_rhs_ored, mixed_block, 2);
5410 defer wip_switch.finish(&self.wip);
5411 try wip_switch.addCase(
5412 try o.builder.intConst(llvm_i2, 0b00),
5413 both_null_block,
5414 &self.wip,
5415 );
5416 try wip_switch.addCase(
5417 try o.builder.intConst(llvm_i2, 0b11),
5418 both_pl_block,
5419 &self.wip,
5420 );
54925421
54935422 self.wip.cursor = .{ .block = both_null_block };
5494 self.builder.positionBuilderAtEnd(both_null_block.toLlvm(&self.wip));
5495 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
5423 _ = try self.wip.br(end_block);
54965424
54975425 self.wip.cursor = .{ .block = mixed_block };
5498 self.builder.positionBuilderAtEnd(mixed_block.toLlvm(&self.wip));
5499 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
5426 _ = try self.wip.br(end_block);
55005427
55015428 self.wip.cursor = .{ .block = both_pl_block };
5502 self.builder.positionBuilderAtEnd(both_pl_block.toLlvm(&self.wip));
55035429 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty, true);
55045430 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true);
55055431 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);
5506 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
5507 const both_pl_block_end = self.builder.getInsertBlock();
5432 _ = try self.wip.br(end_block);
5433 const both_pl_block_end = self.wip.cursor.block;
55085434
55095435 self.wip.cursor = .{ .block = end_block };
5510 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));
5511 const incoming_blocks: [3]*llvm.BasicBlock = .{
5512 both_null_block.toLlvm(&self.wip),
5513 mixed_block.toLlvm(&self.wip),
5514 both_pl_block_end,
5515 };
5516 const llvm_i1_0 = Builder.Constant.false.toLlvm(&o.builder);
5517 const llvm_i1_1 = Builder.Constant.true.toLlvm(&o.builder);
5518 const incoming_values: [3]*llvm.Value = .{
5436 const llvm_i1_0 = try o.builder.intValue(.i1, 0);
5437 const llvm_i1_1 = try o.builder.intValue(.i1, 1);
5438 const incoming_values: [3]Builder.Value = .{
55195439 switch (op) {
55205440 .eq => llvm_i1_1,
55215441 .neq => llvm_i1_0,
......@@ -5529,31 +5449,30 @@ pub const FuncGen = struct {
55295449 payload_cmp,
55305450 };
55315451
5532 const phi_node = self.builder.buildPhi(Builder.Type.i1.toLlvm(&o.builder), "");
5533 comptime assert(incoming_values.len == incoming_blocks.len);
5534 phi_node.addIncoming(
5452 const phi = try self.wip.phi(.i1, "");
5453 try phi.finish(
55355454 &incoming_values,
5536 &incoming_blocks,
5537 incoming_values.len,
5455 &.{ both_null_block, mixed_block, both_pl_block_end },
5456 &self.wip,
55385457 );
5539 return phi_node;
5458 return phi.toValue();
55405459 },
55415460 .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }),
55425461 else => unreachable,
55435462 };
55445463 const is_signed = int_ty.isSignedInt(mod);
5545 const operation: llvm.IntPredicate = switch (op) {
5546 .eq => .EQ,
5547 .neq => .NE,
5548 .lt => if (is_signed) llvm.IntPredicate.SLT else .ULT,
5549 .lte => if (is_signed) llvm.IntPredicate.SLE else .ULE,
5550 .gt => if (is_signed) llvm.IntPredicate.SGT else .UGT,
5551 .gte => if (is_signed) llvm.IntPredicate.SGE else .UGE,
5464 const cond: Builder.IntegerCondition = switch (op) {
5465 .eq => .eq,
5466 .neq => .ne,
5467 .lt => if (is_signed) .slt else .ult,
5468 .lte => if (is_signed) .sle else .ule,
5469 .gt => if (is_signed) .sgt else .ugt,
5470 .gte => if (is_signed) .sge else .uge,
55525471 };
5553 return self.builder.buildICmp(operation, lhs, rhs, "");
5472 return self.wip.icmp(cond, lhs, rhs, "");
55545473 }
55555474
5556 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5475 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
55575476 const o = self.dg.object;
55585477 const mod = o.module;
55595478 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -5563,13 +5482,15 @@ pub const FuncGen = struct {
55635482
55645483 if (inst_ty.isNoReturn(mod)) {
55655484 try self.genBody(body);
5566 return null;
5485 return .none;
55675486 }
55685487
5569 var breaks: BreakList = .{};
5570 defer breaks.deinit(self.gpa);
5488 const have_block_result = inst_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod);
55715489
5572 const parent_bb = try self.wip.block("Block");
5490 var breaks: BreakList = if (have_block_result) .{ .list = .{} } else .{ .len = 0 };
5491 defer if (have_block_result) breaks.list.deinit(self.gpa);
5492
5493 const parent_bb = try self.wip.block(0, "Block");
55735494 try self.blocks.putNoClobber(self.gpa, inst, .{
55745495 .parent_bb = parent_bb,
55755496 .breaks = &breaks,
......@@ -5579,35 +5500,32 @@ pub const FuncGen = struct {
55795500 try self.genBody(body);
55805501
55815502 self.wip.cursor = .{ .block = parent_bb };
5582 self.builder.positionBuilderAtEnd(parent_bb.toLlvm(&self.wip));
55835503
55845504 // Create a phi node only if the block returns a value.
5585 const is_body = inst_ty.zigTypeTag(mod) == .Fn;
5586 if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;
5587
5588 const raw_llvm_ty = (try o.lowerType(inst_ty)).toLlvm(&o.builder);
5589
5590 const llvm_ty = ty: {
5591 // If the zig tag type is a function, this represents an actual function body; not
5592 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
5593 // of function pointers, however the phi makes it a runtime value and therefore
5594 // the LLVM type has to be wrapped in a pointer.
5595 if (is_body or isByRef(inst_ty, mod)) {
5596 break :ty Builder.Type.ptr.toLlvm(&o.builder);
5597 }
5598 break :ty raw_llvm_ty;
5599 };
5505 if (have_block_result) {
5506 const raw_llvm_ty = try o.lowerType(inst_ty);
5507 const llvm_ty: Builder.Type = ty: {
5508 // If the zig tag type is a function, this represents an actual function body; not
5509 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
5510 // of function pointers, however the phi makes it a runtime value and therefore
5511 // the LLVM type has to be wrapped in a pointer.
5512 if (inst_ty.zigTypeTag(mod) == .Fn or isByRef(inst_ty, mod)) {
5513 break :ty .ptr;
5514 }
5515 break :ty raw_llvm_ty;
5516 };
56005517
5601 const phi_node = self.builder.buildPhi(llvm_ty, "");
5602 phi_node.addIncoming(
5603 breaks.items(.val).ptr,
5604 breaks.items(.bb).ptr,
5605 @intCast(breaks.len),
5606 );
5607 return phi_node;
5518 parent_bb.ptr(&self.wip).incoming = @intCast(breaks.list.len);
5519 const phi = try self.wip.phi(llvm_ty, "");
5520 try phi.finish(breaks.list.items(.val), breaks.list.items(.bb), &self.wip);
5521 return phi.toValue();
5522 } else {
5523 parent_bb.ptr(&self.wip).incoming = @intCast(breaks.len);
5524 return .none;
5525 }
56085526 }
56095527
5610 fn airBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5528 fn airBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
56115529 const o = self.dg.object;
56125530 const branch = self.air.instructions.items(.data)[inst].br;
56135531 const block = self.blocks.get(branch.block_inst).?;
......@@ -5615,44 +5533,39 @@ pub const FuncGen = struct {
56155533 // Add the values to the lists only if the break provides a value.
56165534 const operand_ty = self.typeOf(branch.operand);
56175535 const mod = o.module;
5618 if (operand_ty.hasRuntimeBitsIgnoreComptime(mod) or operand_ty.zigTypeTag(mod) == .Fn) {
5536 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
56195537 const val = try self.resolveInst(branch.operand);
56205538
56215539 // For the phi node, we need the basic blocks and the values of the
56225540 // break instructions.
5623 try block.breaks.append(self.gpa, .{
5624 .bb = self.builder.getInsertBlock(),
5625 .val = val,
5626 });
5627 }
5628 _ = self.builder.buildBr(block.parent_bb.toLlvm(&self.wip));
5629 return null;
5541 try block.breaks.list.append(self.gpa, .{ .bb = self.wip.cursor.block, .val = val });
5542 } else block.breaks.len += 1;
5543 _ = try self.wip.br(block.parent_bb);
5544 return .none;
56305545 }
56315546
5632 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5547 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
56335548 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
56345549 const cond = try self.resolveInst(pl_op.operand);
56355550 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
56365551 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
56375552 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
56385553
5639 const then_block = try self.wip.block("Then");
5640 const else_block = try self.wip.block("Else");
5641 _ = self.builder.buildCondBr(cond, then_block.toLlvm(&self.wip), else_block.toLlvm(&self.wip));
5554 const then_block = try self.wip.block(1, "Then");
5555 const else_block = try self.wip.block(1, "Else");
5556 _ = try self.wip.brCond(cond, then_block, else_block);
56425557
56435558 self.wip.cursor = .{ .block = then_block };
5644 self.builder.positionBuilderAtEnd(then_block.toLlvm(&self.wip));
56455559 try self.genBody(then_body);
56465560
56475561 self.wip.cursor = .{ .block = else_block };
5648 self.builder.positionBuilderAtEnd(else_block.toLlvm(&self.wip));
56495562 try self.genBody(else_body);
56505563
56515564 // No need to reset the insert cursor since this instruction is noreturn.
5652 return null;
5565 return .none;
56535566 }
56545567
5655 fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
5568 fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
56565569 const o = self.dg.object;
56575570 const mod = o.module;
56585571 const inst = body_tail[0];
......@@ -5667,7 +5580,7 @@ pub const FuncGen = struct {
56675580 return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused);
56685581 }
56695582
5670 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5583 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
56715584 const o = self.dg.object;
56725585 const mod = o.module;
56735586 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -5681,139 +5594,149 @@ pub const FuncGen = struct {
56815594
56825595 fn lowerTry(
56835596 fg: *FuncGen,
5684 err_union: *llvm.Value,
5597 err_union: Builder.Value,
56855598 body: []const Air.Inst.Index,
56865599 err_union_ty: Type,
56875600 operand_is_ptr: bool,
56885601 can_elide_load: bool,
56895602 is_unused: bool,
5690 ) !?*llvm.Value {
5603 ) !Builder.Value {
56915604 const o = fg.dg.object;
56925605 const mod = o.module;
56935606 const payload_ty = err_union_ty.errorUnionPayload(mod);
56945607 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod);
5695 const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder);
5608 const err_union_llvm_ty = try o.lowerType(err_union_ty);
56965609
56975610 if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
5698 const is_err = err: {
5699 const err_set_ty = Builder.Type.err_int.toLlvm(&o.builder);
5700 const zero = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder);
5611 const loaded = loaded: {
57015612 if (!payload_has_bits) {
57025613 // TODO add alignment to this load
5703 const loaded = if (operand_is_ptr)
5704 fg.builder.buildLoad(err_set_ty, err_union, "")
5614 break :loaded if (operand_is_ptr)
5615 try fg.wip.load(.normal, Builder.Type.err_int, err_union, .default, "")
57055616 else
57065617 err_union;
5707 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
57085618 }
57095619 const err_field_index = errUnionErrorOffset(payload_ty, mod);
57105620 if (operand_is_ptr or isByRef(err_union_ty, mod)) {
5711 const err_field_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, err_field_index, "");
5621 const err_field_ptr =
5622 try fg.wip.gepStruct(err_union_llvm_ty, err_union, err_field_index, "");
57125623 // TODO add alignment to this load
5713 const loaded = fg.builder.buildLoad(err_set_ty, err_field_ptr, "");
5714 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
5624 break :loaded try fg.wip.load(
5625 .normal,
5626 Builder.Type.err_int,
5627 err_field_ptr,
5628 .default,
5629 "",
5630 );
57155631 }
5716 const loaded = fg.builder.buildExtractValue(err_union, err_field_index, "");
5717 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
5632 break :loaded try fg.wip.extractValue(err_union, &.{err_field_index}, "");
57185633 };
5634 const zero = try o.builder.intValue(Builder.Type.err_int, 0);
5635 const is_err = try fg.wip.icmp(.ne, loaded, zero, "");
57195636
5720 const return_block = try fg.wip.block("TryRet");
5721 const continue_block = try fg.wip.block("TryCont");
5722 _ = fg.builder.buildCondBr(is_err, return_block.toLlvm(&fg.wip), continue_block.toLlvm(&fg.wip));
5637 const return_block = try fg.wip.block(1, "TryRet");
5638 const continue_block = try fg.wip.block(1, "TryCont");
5639 _ = try fg.wip.brCond(is_err, return_block, continue_block);
57235640
57245641 fg.wip.cursor = .{ .block = return_block };
5725 fg.builder.positionBuilderAtEnd(return_block.toLlvm(&fg.wip));
57265642 try fg.genBody(body);
57275643
57285644 fg.wip.cursor = .{ .block = continue_block };
5729 fg.builder.positionBuilderAtEnd(continue_block.toLlvm(&fg.wip));
5730 }
5731 if (is_unused) {
5732 return null;
5733 }
5734 if (!payload_has_bits) {
5735 return if (operand_is_ptr) err_union else null;
57365645 }
5646 if (is_unused) return .none;
5647 if (!payload_has_bits) return if (operand_is_ptr) err_union else .none;
57375648 const offset = errUnionPayloadOffset(payload_ty, mod);
57385649 if (operand_is_ptr) {
5739 return fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
5650 return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");
57405651 } else if (isByRef(err_union_ty, mod)) {
5741 const payload_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
5652 const payload_ptr = try fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");
5653 const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod));
57425654 if (isByRef(payload_ty, mod)) {
57435655 if (can_elide_load)
57445656 return payload_ptr;
57455657
5746 return fg.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(mod), false);
5658 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
57475659 }
5748 const load_inst = fg.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, "");
5749 load_inst.setAlignment(payload_ty.abiAlignment(mod));
5750 return load_inst;
5660 const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
5661 return fg.wip.load(.normal, load_ty, payload_ptr, payload_alignment, "");
57515662 }
5752 return fg.builder.buildExtractValue(err_union, offset, "");
5663 return fg.wip.extractValue(err_union, &.{offset}, "");
57535664 }
57545665
5755 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5666 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
57565667 const o = self.dg.object;
57575668 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
57585669 const cond = try self.resolveInst(pl_op.operand);
57595670 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
5760 const else_block = try self.wip.block("Else");
5761 const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder);
5762 const cond_int = if (cond.typeOf().getTypeKind() == .Pointer)
5763 self.builder.buildPtrToInt(cond, llvm_usize, "")
5671 const else_block = try self.wip.block(1, "Default");
5672 const llvm_usize = try o.lowerType(Type.usize);
5673 const cond_int = if (cond.typeOfWip(&self.wip).isPointer(&o.builder))
5674 try self.wip.cast(.ptrtoint, cond, llvm_usize, "")
57645675 else
57655676 cond;
5766 const llvm_switch = self.builder.buildSwitch(cond_int, else_block.toLlvm(&self.wip), switch_br.data.cases_len);
57675677
57685678 var extra_index: usize = switch_br.end;
57695679 var case_i: u32 = 0;
5680 var llvm_cases_len: u32 = 0;
5681 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
5682 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
5683 const items: []const Air.Inst.Ref =
5684 @ptrCast(self.air.extra[case.end..][0..case.data.items_len]);
5685 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
5686 extra_index = case.end + case.data.items_len + case_body.len;
57705687
5688 llvm_cases_len += @intCast(items.len);
5689 }
5690
5691 var wip_switch = try self.wip.@"switch"(cond_int, else_block, llvm_cases_len);
5692 defer wip_switch.finish(&self.wip);
5693
5694 extra_index = switch_br.end;
5695 case_i = 0;
57715696 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
57725697 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
5773 const items: []const Air.Inst.Ref = @ptrCast(self.air.extra[case.end..][0..case.data.items_len]);
5698 const items: []const Air.Inst.Ref =
5699 @ptrCast(self.air.extra[case.end..][0..case.data.items_len]);
57745700 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
57755701 extra_index = case.end + case.data.items_len + case_body.len;
57765702
5777 const case_block = try self.wip.block("Case");
5703 const case_block = try self.wip.block(@intCast(items.len), "Case");
57785704
57795705 for (items) |item| {
5780 const llvm_item = try self.resolveInst(item);
5781 const llvm_int_item = if (llvm_item.typeOf().getTypeKind() == .Pointer)
5782 llvm_item.constPtrToInt(llvm_usize)
5706 const llvm_item = (try self.resolveInst(item)).toConst().?;
5707 const llvm_int_item = if (llvm_item.typeOf(&o.builder).isPointer(&o.builder))
5708 try o.builder.castConst(.ptrtoint, llvm_item, llvm_usize)
57835709 else
57845710 llvm_item;
5785 llvm_switch.addCase(llvm_int_item, case_block.toLlvm(&self.wip));
5711 try wip_switch.addCase(llvm_int_item, case_block, &self.wip);
57865712 }
57875713
57885714 self.wip.cursor = .{ .block = case_block };
5789 self.builder.positionBuilderAtEnd(case_block.toLlvm(&self.wip));
57905715 try self.genBody(case_body);
57915716 }
57925717
57935718 self.wip.cursor = .{ .block = else_block };
5794 self.builder.positionBuilderAtEnd(else_block.toLlvm(&self.wip));
57955719 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
57965720 if (else_body.len != 0) {
57975721 try self.genBody(else_body);
57985722 } else {
5799 _ = self.builder.buildUnreachable();
5723 _ = try self.wip.@"unreachable"();
58005724 }
58015725
58025726 // No need to reset the insert cursor since this instruction is noreturn.
5803 return null;
5727 return .none;
58045728 }
58055729
5806 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5730 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
58075731 const o = self.dg.object;
58085732 const mod = o.module;
58095733 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
58105734 const loop = self.air.extraData(Air.Block, ty_pl.payload);
58115735 const body = self.air.extra[loop.end..][0..loop.data.body_len];
5812 const loop_block = try self.wip.block("Loop");
5813 _ = self.builder.buildBr(loop_block.toLlvm(&self.wip));
5736 const loop_block = try self.wip.block(2, "Loop");
5737 _ = try self.wip.br(loop_block);
58145738
58155739 self.wip.cursor = .{ .block = loop_block };
5816 self.builder.positionBuilderAtEnd(loop_block.toLlvm(&self.wip));
58175740 try self.genBody(body);
58185741
58195742 // TODO instead of this logic, change AIR to have the property that
......@@ -5823,35 +5746,30 @@ pub const FuncGen = struct {
58235746 // be while(true) instead of for(body), which will eliminate 1 branch on
58245747 // a hot path.
58255748 if (body.len == 0 or !self.typeOfIndex(body[body.len - 1]).isNoReturn(mod)) {
5826 _ = self.builder.buildBr(loop_block.toLlvm(&self.wip));
5749 _ = try self.wip.br(loop_block);
58275750 }
5828 return null;
5751 return .none;
58295752 }
58305753
5831 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5754 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
58325755 const o = self.dg.object;
58335756 const mod = o.module;
58345757 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
58355758 const operand_ty = self.typeOf(ty_op.operand);
58365759 const array_ty = operand_ty.childType(mod);
58375760 const llvm_usize = try o.lowerType(Type.usize);
5838 const len = (try o.builder.intConst(llvm_usize, array_ty.arrayLen(mod))).toLlvm(&o.builder);
5839 const slice_llvm_ty = (try o.lowerType(self.typeOfIndex(inst))).toLlvm(&o.builder);
5761 const len = try o.builder.intValue(llvm_usize, array_ty.arrayLen(mod));
5762 const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
58405763 const operand = try self.resolveInst(ty_op.operand);
5841 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) {
5842 const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), operand, 0, "");
5843 return self.builder.buildInsertValue(partial, len, 1, "");
5844 }
5845 const indices: [2]*llvm.Value = .{
5846 (try o.builder.intConst(llvm_usize, 0)).toLlvm(&o.builder),
5847 } ** 2;
5848 const array_llvm_ty = (try o.lowerType(array_ty)).toLlvm(&o.builder);
5849 const ptr = self.builder.buildInBoundsGEP(array_llvm_ty, operand, &indices, indices.len, "");
5850 const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), ptr, 0, "");
5851 return self.builder.buildInsertValue(partial, len, 1, "");
5764 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))
5765 return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, "");
5766 const ptr = try self.wip.gep(.inbounds, try o.lowerType(array_ty), operand, &.{
5767 try o.builder.intValue(llvm_usize, 0), try o.builder.intValue(llvm_usize, 0),
5768 }, "");
5769 return self.wip.buildAggregate(slice_llvm_ty, &.{ ptr, len }, "");
58525770 }
58535771
5854 fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5772 fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
58555773 const o = self.dg.object;
58565774 const mod = o.module;
58575775 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -5865,23 +5783,21 @@ pub const FuncGen = struct {
58655783 const dest_llvm_ty = try o.lowerType(dest_ty);
58665784 const target = mod.getTarget();
58675785
5868 if (intrinsicsAllowed(dest_scalar_ty, target)) {
5869 if (operand_scalar_ty.isSignedInt(mod)) {
5870 return self.builder.buildSIToFP(operand, dest_llvm_ty.toLlvm(&o.builder), "");
5871 } else {
5872 return self.builder.buildUIToFP(operand, dest_llvm_ty.toLlvm(&o.builder), "");
5873 }
5874 }
5786 if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv(
5787 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5788 operand,
5789 dest_llvm_ty,
5790 "",
5791 );
58755792
58765793 const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(mod)));
58775794 const rt_int_ty = try o.builder.intType(rt_int_bits);
5878 var extended = e: {
5879 if (operand_scalar_ty.isSignedInt(mod)) {
5880 break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty.toLlvm(&o.builder), "");
5881 } else {
5882 break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty.toLlvm(&o.builder), "");
5883 }
5884 };
5795 var extended = try self.wip.conv(
5796 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5797 operand,
5798 rt_int_ty,
5799 "",
5800 );
58855801 const dest_bits = dest_scalar_ty.floatBits(target);
58865802 const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);
58875803 const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);
......@@ -5897,16 +5813,23 @@ pub const FuncGen = struct {
58975813 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
58985814 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.
58995815 param_type = try o.builder.vectorType(.normal, 2, .i64);
5900 extended = self.builder.buildBitCast(extended, param_type.toLlvm(&o.builder), "");
5816 extended = try self.wip.cast(.bitcast, extended, param_type, "");
59015817 }
59025818
59035819 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);
5904 const params = [1]*llvm.Value{extended};
5905
5906 return self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");
5820 const params = [1]*llvm.Value{extended.toLlvm(&self.wip)};
5821 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
5822 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
5823 libc_fn.toLlvm(&o.builder),
5824 &params,
5825 params.len,
5826 .C,
5827 .Auto,
5828 "",
5829 ), &self.wip);
59075830 }
59085831
5909 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
5832 fn airIntFromFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
59105833 self.builder.setFastMath(want_fast_math);
59115834
59125835 const o = self.dg.object;
......@@ -5924,11 +5847,12 @@ pub const FuncGen = struct {
59245847
59255848 if (intrinsicsAllowed(operand_scalar_ty, target)) {
59265849 // TODO set fast math flag
5927 if (dest_scalar_ty.isSignedInt(mod)) {
5928 return self.builder.buildFPToSI(operand, dest_llvm_ty.toLlvm(&o.builder), "");
5929 } else {
5930 return self.builder.buildFPToUI(operand, dest_llvm_ty.toLlvm(&o.builder), "");
5931 }
5850 return self.wip.conv(
5851 if (dest_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5852 operand,
5853 dest_llvm_ty,
5854 "",
5855 );
59325856 }
59335857
59345858 const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(mod)));
......@@ -5953,66 +5877,69 @@ pub const FuncGen = struct {
59535877
59545878 const operand_llvm_ty = try o.lowerType(operand_ty);
59555879 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);
5956 const params = [1]*llvm.Value{operand};
5957
5958 var result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");
5880 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
5881 var result = (try self.wip.unimplemented(libc_ret_ty, "")).finish(self.builder.buildCall(
5882 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
5883 libc_fn.toLlvm(&o.builder),
5884 &params,
5885 params.len,
5886 .C,
5887 .Auto,
5888 "",
5889 ), &self.wip);
59595890
5960 if (libc_ret_ty != ret_ty) result = self.builder.buildBitCast(result, ret_ty.toLlvm(&o.builder), "");
5961 if (ret_ty != dest_llvm_ty) result = self.builder.buildTrunc(result, dest_llvm_ty.toLlvm(&o.builder), "");
5891 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
5892 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
59625893 return result;
59635894 }
59645895
5965 fn sliceOrArrayPtr(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value {
5896 fn sliceOrArrayPtr(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value {
59665897 const o = fg.dg.object;
59675898 const mod = o.module;
5968 if (ty.isSlice(mod)) {
5969 return fg.builder.buildExtractValue(ptr, 0, "");
5970 } else {
5971 return ptr;
5972 }
5899 return if (ty.isSlice(mod)) fg.wip.extractValue(ptr, &.{0}, "") else ptr;
59735900 }
59745901
5975 fn sliceOrArrayLenInBytes(fg: *FuncGen, ptr: *llvm.Value, ty: Type) Allocator.Error!*llvm.Value {
5902 fn sliceOrArrayLenInBytes(fg: *FuncGen, ptr: Builder.Value, ty: Type) Allocator.Error!Builder.Value {
59765903 const o = fg.dg.object;
59775904 const mod = o.module;
59785905 const llvm_usize = try o.lowerType(Type.usize);
59795906 switch (ty.ptrSize(mod)) {
59805907 .Slice => {
5981 const len = fg.builder.buildExtractValue(ptr, 1, "");
5908 const len = try fg.wip.extractValue(ptr, &.{1}, "");
59825909 const elem_ty = ty.childType(mod);
59835910 const abi_size = elem_ty.abiSize(mod);
59845911 if (abi_size == 1) return len;
5985 const abi_size_llvm_val = try o.builder.intConst(llvm_usize, abi_size);
5986 return fg.builder.buildMul(len, abi_size_llvm_val.toLlvm(&o.builder), "");
5912 const abi_size_llvm_val = try o.builder.intValue(llvm_usize, abi_size);
5913 return fg.wip.bin(.@"mul nuw", len, abi_size_llvm_val, "");
59875914 },
59885915 .One => {
59895916 const array_ty = ty.childType(mod);
59905917 const elem_ty = array_ty.childType(mod);
59915918 const abi_size = elem_ty.abiSize(mod);
5992 return (try o.builder.intConst(llvm_usize, array_ty.arrayLen(mod) * abi_size)).toLlvm(&o.builder);
5919 return o.builder.intValue(llvm_usize, array_ty.arrayLen(mod) * abi_size);
59935920 },
59945921 .Many, .C => unreachable,
59955922 }
59965923 }
59975924
5998 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
5925 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: u32) !Builder.Value {
59995926 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
60005927 const operand = try self.resolveInst(ty_op.operand);
6001 return self.builder.buildExtractValue(operand, index, "");
5928 return self.wip.extractValue(operand, &.{index}, "");
60025929 }
60035930
6004 fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
5931 fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !Builder.Value {
60055932 const o = self.dg.object;
60065933 const mod = o.module;
60075934 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
60085935 const slice_ptr = try self.resolveInst(ty_op.operand);
60095936 const slice_ptr_ty = self.typeOf(ty_op.operand);
6010 const slice_llvm_ty = (try o.lowerPtrElemTy(slice_ptr_ty.childType(mod))).toLlvm(&o.builder);
5937 const slice_llvm_ty = try o.lowerPtrElemTy(slice_ptr_ty.childType(mod));
60115938
6012 return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, "");
5939 return self.wip.gepStruct(slice_llvm_ty, slice_ptr, index, "");
60135940 }
60145941
6015 fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
5942 fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
60165943 const o = self.dg.object;
60175944 const mod = o.module;
60185945 const inst = body_tail[0];
......@@ -6021,21 +5948,21 @@ pub const FuncGen = struct {
60215948 const slice = try self.resolveInst(bin_op.lhs);
60225949 const index = try self.resolveInst(bin_op.rhs);
60235950 const elem_ty = slice_ty.childType(mod);
6024 const llvm_elem_ty = (try o.lowerPtrElemTy(elem_ty)).toLlvm(&o.builder);
6025 const base_ptr = self.builder.buildExtractValue(slice, 0, "");
6026 const indices: [1]*llvm.Value = .{index};
6027 const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5951 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);
5952 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
5953 const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
60285954 if (isByRef(elem_ty, mod)) {
60295955 if (self.canElideLoad(body_tail))
60305956 return ptr;
60315957
6032 return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false);
5958 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
5959 return self.loadByRef(ptr, elem_ty, elem_alignment, false);
60335960 }
60345961
60355962 return self.load(ptr, slice_ty);
60365963 }
60375964
6038 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5965 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
60395966 const o = self.dg.object;
60405967 const mod = o.module;
60415968 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -6044,13 +5971,12 @@ pub const FuncGen = struct {
60445971
60455972 const slice = try self.resolveInst(bin_op.lhs);
60465973 const index = try self.resolveInst(bin_op.rhs);
6047 const llvm_elem_ty = (try o.lowerPtrElemTy(slice_ty.childType(mod))).toLlvm(&o.builder);
6048 const base_ptr = self.builder.buildExtractValue(slice, 0, "");
6049 const indices: [1]*llvm.Value = .{index};
6050 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5974 const llvm_elem_ty = try o.lowerPtrElemTy(slice_ty.childType(mod));
5975 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
5976 return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
60515977 }
60525978
6053 fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
5979 fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
60545980 const o = self.dg.object;
60555981 const mod = o.module;
60565982 const inst = body_tail[0];
......@@ -6059,21 +5985,20 @@ pub const FuncGen = struct {
60595985 const array_ty = self.typeOf(bin_op.lhs);
60605986 const array_llvm_val = try self.resolveInst(bin_op.lhs);
60615987 const rhs = try self.resolveInst(bin_op.rhs);
6062 const array_llvm_ty = (try o.lowerType(array_ty)).toLlvm(&o.builder);
5988 const array_llvm_ty = try o.lowerType(array_ty);
60635989 const elem_ty = array_ty.childType(mod);
60645990 if (isByRef(array_ty, mod)) {
6065 const indices: [2]*llvm.Value = .{
6066 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
6067 rhs,
5991 const indices: [2]Builder.Value = .{
5992 try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs,
60685993 };
60695994 if (isByRef(elem_ty, mod)) {
6070 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");
6071 if (canElideLoad(self, body_tail))
6072 return elem_ptr;
6073
6074 return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(mod), false);
5995 const elem_ptr =
5996 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
5997 if (canElideLoad(self, body_tail)) return elem_ptr;
5998 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
5999 return self.loadByRef(elem_ptr, elem_ty, elem_alignment, false);
60756000 } else {
6076 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
6001 const elem_llvm_ty = try o.lowerType(elem_ty);
60776002 if (Air.refToIndex(bin_op.lhs)) |lhs_index| {
60786003 if (self.air.instructions.items(.tag)[lhs_index] == .load) {
60796004 const load_data = self.air.instructions.items(.data)[lhs_index];
......@@ -6081,66 +6006,70 @@ pub const FuncGen = struct {
60816006 if (Air.refToIndex(load_ptr)) |load_ptr_index| {
60826007 const load_ptr_tag = self.air.instructions.items(.tag)[load_ptr_index];
60836008 switch (load_ptr_tag) {
6084 .struct_field_ptr, .struct_field_ptr_index_0, .struct_field_ptr_index_1, .struct_field_ptr_index_2, .struct_field_ptr_index_3 => {
6009 .struct_field_ptr,
6010 .struct_field_ptr_index_0,
6011 .struct_field_ptr_index_1,
6012 .struct_field_ptr_index_2,
6013 .struct_field_ptr_index_3,
6014 => {
60856015 const load_ptr_inst = try self.resolveInst(load_ptr);
6086 const gep = self.builder.buildInBoundsGEP(array_llvm_ty, load_ptr_inst, &indices, indices.len, "");
6087 return self.builder.buildLoad(elem_llvm_ty, gep, "");
6016 const gep = try self.wip.gep(
6017 .inbounds,
6018 array_llvm_ty,
6019 load_ptr_inst,
6020 &indices,
6021 "",
6022 );
6023 return self.wip.load(.normal, elem_llvm_ty, gep, .default, "");
60886024 },
60896025 else => {},
60906026 }
60916027 }
60926028 }
60936029 }
6094 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");
6095 return self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");
6030 const elem_ptr =
6031 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
6032 return self.wip.load(.normal, elem_llvm_ty, elem_ptr, .default, "");
60966033 }
60976034 }
60986035
60996036 // This branch can be reached for vectors, which are always by-value.
6100 return self.builder.buildExtractElement(array_llvm_val, rhs, "");
6037 return self.wip.extractElement(array_llvm_val, rhs, "");
61016038 }
61026039
6103 fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
6040 fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
61046041 const o = self.dg.object;
61056042 const mod = o.module;
61066043 const inst = body_tail[0];
61076044 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
61086045 const ptr_ty = self.typeOf(bin_op.lhs);
61096046 const elem_ty = ptr_ty.childType(mod);
6110 const llvm_elem_ty = (try o.lowerPtrElemTy(elem_ty)).toLlvm(&o.builder);
6047 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);
61116048 const base_ptr = try self.resolveInst(bin_op.lhs);
61126049 const rhs = try self.resolveInst(bin_op.rhs);
61136050 // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch
6114 const ptr = if (ptr_ty.isSinglePointer(mod)) ptr: {
6051 const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, if (ptr_ty.isSinglePointer(mod))
61156052 // If this is a single-item pointer to an array, we need another index in the GEP.
6116 const indices: [2]*llvm.Value = .{
6117 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
6118 rhs,
6119 };
6120 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
6121 } else ptr: {
6122 const indices: [1]*llvm.Value = .{rhs};
6123 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
6124 };
6053 &.{ try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs }
6054 else
6055 &.{rhs}, "");
61256056 if (isByRef(elem_ty, mod)) {
6126 if (self.canElideLoad(body_tail))
6127 return ptr;
6128
6129 return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false);
6057 if (self.canElideLoad(body_tail)) return ptr;
6058 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
6059 return self.loadByRef(ptr, elem_ty, elem_alignment, false);
61306060 }
61316061
61326062 return self.load(ptr, ptr_ty);
61336063 }
61346064
6135 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6065 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
61366066 const o = self.dg.object;
61376067 const mod = o.module;
61386068 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
61396069 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
61406070 const ptr_ty = self.typeOf(bin_op.lhs);
61416071 const elem_ty = ptr_ty.childType(mod);
6142 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod))
6143 return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder);
6072 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return (try o.lowerPtrToVoid(ptr_ty)).toValue();
61446073
61456074 const base_ptr = try self.resolveInst(bin_op.lhs);
61466075 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -6148,21 +6077,15 @@ pub const FuncGen = struct {
61486077 const elem_ptr = self.air.getRefType(ty_pl.ty);
61496078 if (elem_ptr.ptrInfo(mod).flags.vector_index != .none) return base_ptr;
61506079
6151 const llvm_elem_ty = (try o.lowerPtrElemTy(elem_ty)).toLlvm(&o.builder);
6152 if (ptr_ty.isSinglePointer(mod)) {
6080 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);
6081 return try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, if (ptr_ty.isSinglePointer(mod))
61536082 // If this is a single-item pointer to an array, we need another index in the GEP.
6154 const indices: [2]*llvm.Value = .{
6155 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
6156 rhs,
6157 };
6158 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
6159 } else {
6160 const indices: [1]*llvm.Value = .{rhs};
6161 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
6162 }
6083 &.{ try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs }
6084 else
6085 &.{rhs}, "");
61636086 }
61646087
6165 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6088 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
61666089 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
61676090 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
61686091 const struct_ptr = try self.resolveInst(struct_field.struct_operand);
......@@ -6174,14 +6097,14 @@ pub const FuncGen = struct {
61746097 self: *FuncGen,
61756098 inst: Air.Inst.Index,
61766099 field_index: u32,
6177 ) !?*llvm.Value {
6100 ) !Builder.Value {
61786101 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
61796102 const struct_ptr = try self.resolveInst(ty_op.operand);
61806103 const struct_ptr_ty = self.typeOf(ty_op.operand);
61816104 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);
61826105 }
61836106
6184 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
6107 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
61856108 const o = self.dg.object;
61866109 const mod = o.module;
61876110 const inst = body_tail[0];
......@@ -6191,9 +6114,7 @@ pub const FuncGen = struct {
61916114 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
61926115 const field_index = struct_field.field_index;
61936116 const field_ty = struct_ty.structFieldType(field_index, mod);
6194 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6195 return null;
6196 }
6117 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
61976118
61986119 if (!isByRef(struct_ty, mod)) {
61996120 assert(!isByRef(field_ty, mod));
......@@ -6203,39 +6124,44 @@ pub const FuncGen = struct {
62036124 const struct_obj = mod.typeToStruct(struct_ty).?;
62046125 const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index);
62056126 const containing_int = struct_llvm_val;
6206 const shift_amt = containing_int.typeOf().constInt(bit_offset, .False);
6207 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
6208 const elem_llvm_ty = (try o.lowerType(field_ty)).toLlvm(&o.builder);
6127 const shift_amt =
6128 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
6129 const shifted_value = try self.wip.bin(.lshr, containing_int, shift_amt, "");
6130 const elem_llvm_ty = try o.lowerType(field_ty);
62096131 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {
6210 const same_size_int = (try o.builder.intType(@intCast(field_ty.bitSize(mod)))).toLlvm(&o.builder);
6211 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
6212 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
6132 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6133 const truncated_int =
6134 try self.wip.cast(.trunc, shifted_value, same_size_int, "");
6135 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
62136136 } else if (field_ty.isPtrAtRuntime(mod)) {
6214 const same_size_int = (try o.builder.intType(@intCast(field_ty.bitSize(mod)))).toLlvm(&o.builder);
6215 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
6216 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");
6137 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6138 const truncated_int =
6139 try self.wip.cast(.trunc, shifted_value, same_size_int, "");
6140 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
62176141 }
6218 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");
6142 return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
62196143 },
62206144 else => {
62216145 const llvm_field_index = llvmField(struct_ty, field_index, mod).?.index;
6222 return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, "");
6146 return self.wip.extractValue(struct_llvm_val, &.{llvm_field_index}, "");
62236147 },
62246148 },
62256149 .Union => {
62266150 assert(struct_ty.containerLayout(mod) == .Packed);
62276151 const containing_int = struct_llvm_val;
6228 const elem_llvm_ty = (try o.lowerType(field_ty)).toLlvm(&o.builder);
6152 const elem_llvm_ty = try o.lowerType(field_ty);
62296153 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {
6230 const same_size_int = (try o.builder.intType(@intCast(field_ty.bitSize(mod)))).toLlvm(&o.builder);
6231 const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, "");
6232 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
6154 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6155 const truncated_int =
6156 try self.wip.cast(.trunc, containing_int, same_size_int, "");
6157 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
62336158 } else if (field_ty.isPtrAtRuntime(mod)) {
6234 const same_size_int = (try o.builder.intType(@intCast(field_ty.bitSize(mod)))).toLlvm(&o.builder);
6235 const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, "");
6236 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");
6159 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6160 const truncated_int =
6161 try self.wip.cast(.trunc, containing_int, same_size_int, "");
6162 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
62376163 }
6238 return self.builder.buildTrunc(containing_int, elem_llvm_ty, "");
6164 return self.wip.cast(.trunc, containing_int, elem_llvm_ty, "");
62396165 },
62406166 else => unreachable,
62416167 }
......@@ -6245,8 +6171,9 @@ pub const FuncGen = struct {
62456171 .Struct => {
62466172 assert(struct_ty.containerLayout(mod) != .Packed);
62476173 const llvm_field = llvmField(struct_ty, field_index, mod).?;
6248 const struct_llvm_ty = (try o.lowerType(struct_ty)).toLlvm(&o.builder);
6249 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field.index, "");
6174 const struct_llvm_ty = try o.lowerType(struct_ty);
6175 const field_ptr =
6176 try self.wip.gepStruct(struct_llvm_ty, struct_llvm_val, llvm_field.index, "");
62506177 const field_ptr_ty = try mod.ptrType(.{
62516178 .child = llvm_field.ty.toIntern(),
62526179 .flags = .{
......@@ -6258,31 +6185,32 @@ pub const FuncGen = struct {
62586185 return field_ptr;
62596186
62606187 assert(llvm_field.alignment != 0);
6261 return self.loadByRef(field_ptr, field_ty, llvm_field.alignment, false);
6188 const field_alignment = Builder.Alignment.fromByteUnits(llvm_field.alignment);
6189 return self.loadByRef(field_ptr, field_ty, field_alignment, false);
62626190 } else {
62636191 return self.load(field_ptr, field_ptr_ty);
62646192 }
62656193 },
62666194 .Union => {
6267 const union_llvm_ty = (try o.lowerType(struct_ty)).toLlvm(&o.builder);
6195 const union_llvm_ty = try o.lowerType(struct_ty);
62686196 const layout = struct_ty.unionGetLayout(mod);
62696197 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
6270 const field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_llvm_val, payload_index, "");
6271 const llvm_field_ty = (try o.lowerType(field_ty)).toLlvm(&o.builder);
6198 const field_ptr =
6199 try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, "");
6200 const llvm_field_ty = try o.lowerType(field_ty);
6201 const payload_alignment = Builder.Alignment.fromByteUnits(layout.payload_align);
62726202 if (isByRef(field_ty, mod)) {
6273 if (canElideLoad(self, body_tail))
6274 return field_ptr;
6275
6276 return self.loadByRef(field_ptr, field_ty, layout.payload_align, false);
6203 if (canElideLoad(self, body_tail)) return field_ptr;
6204 return self.loadByRef(field_ptr, field_ty, payload_alignment, false);
62776205 } else {
6278 return self.builder.buildLoad(llvm_field_ty, field_ptr, "");
6206 return self.wip.load(.normal, llvm_field_ty, field_ptr, payload_alignment, "");
62796207 }
62806208 },
62816209 else => unreachable,
62826210 }
62836211 }
62846212
6285 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6213 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
62866214 const o = self.dg.object;
62876215 const mod = o.module;
62886216 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -6292,33 +6220,36 @@ pub const FuncGen = struct {
62926220
62936221 const parent_ty = self.air.getRefType(ty_pl.ty).childType(mod);
62946222 const field_offset = parent_ty.structFieldOffset(extra.field_index, mod);
6223 if (field_offset == 0) return field_ptr;
62956224
6296 const res_ty = (try o.lowerType(self.air.getRefType(ty_pl.ty))).toLlvm(&o.builder);
6297 if (field_offset == 0) {
6298 return field_ptr;
6299 }
6225 const res_ty = try o.lowerType(self.air.getRefType(ty_pl.ty));
63006226 const llvm_usize = try o.lowerType(Type.usize);
63016227
6302 const field_ptr_int = self.builder.buildPtrToInt(field_ptr, llvm_usize.toLlvm(&o.builder), "");
6303 const base_ptr_int = self.builder.buildNUWSub(field_ptr_int, (try o.builder.intConst(llvm_usize, field_offset)).toLlvm(&o.builder), "");
6304 return self.builder.buildIntToPtr(base_ptr_int, res_ty, "");
6228 const field_ptr_int = try self.wip.cast(.ptrtoint, field_ptr, llvm_usize, "");
6229 const base_ptr_int = try self.wip.bin(
6230 .@"sub nuw",
6231 field_ptr_int,
6232 try o.builder.intValue(llvm_usize, field_offset),
6233 "",
6234 );
6235 return self.wip.cast(.inttoptr, base_ptr_int, res_ty, "");
63056236 }
63066237
6307 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6238 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
63086239 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
63096240 const operand = try self.resolveInst(ty_op.operand);
63106241
6311 return self.builder.buildNot(operand, "");
6242 return self.wip.not(operand, "");
63126243 }
63136244
6314 fn airUnreach(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {
6245 fn airUnreach(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
63156246 _ = inst;
6316 _ = self.builder.buildUnreachable();
6317 return null;
6247 _ = try self.wip.@"unreachable"();
6248 return .none;
63186249 }
63196250
6320 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {
6321 const di_scope = self.di_scope orelse return null;
6251 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6252 const di_scope = self.di_scope orelse return .none;
63226253 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
63236254 self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1);
63246255 self.prev_dbg_column = @intCast(dbg_stmt.column + 1);
......@@ -6327,12 +6258,12 @@ pub const FuncGen = struct {
63276258 else
63286259 null;
63296260 self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);
6330 return null;
6261 return .none;
63316262 }
63326263
6333 fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6264 fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
63346265 const o = self.dg.object;
6335 const dib = o.di_builder orelse return null;
6266 const dib = o.di_builder orelse return .none;
63366267 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
63376268
63386269 const mod = o.module;
......@@ -6385,12 +6316,12 @@ pub const FuncGen = struct {
63856316 const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);
63866317 self.di_scope = lexical_block.toScope();
63876318 self.base_line = decl.src_line;
6388 return null;
6319 return .none;
63896320 }
63906321
6391 fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6322 fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
63926323 const o = self.dg.object;
6393 if (o.di_builder == null) return null;
6324 if (o.di_builder == null) return .none;
63946325 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
63956326
63966327 const mod = o.module;
......@@ -6400,30 +6331,30 @@ pub const FuncGen = struct {
64006331 const old = self.dbg_inlined.pop();
64016332 self.di_scope = old.scope;
64026333 self.base_line = old.base_line;
6403 return null;
6334 return .none;
64046335 }
64056336
6406 fn airDbgBlockBegin(self: *FuncGen) !?*llvm.Value {
6337 fn airDbgBlockBegin(self: *FuncGen) !Builder.Value {
64076338 const o = self.dg.object;
6408 const dib = o.di_builder orelse return null;
6339 const dib = o.di_builder orelse return .none;
64096340 const old_scope = self.di_scope.?;
64106341 try self.dbg_block_stack.append(self.gpa, old_scope);
64116342 const lexical_block = dib.createLexicalBlock(old_scope, self.di_file.?, self.prev_dbg_line, self.prev_dbg_column);
64126343 self.di_scope = lexical_block.toScope();
6413 return null;
6344 return .none;
64146345 }
64156346
6416 fn airDbgBlockEnd(self: *FuncGen) !?*llvm.Value {
6347 fn airDbgBlockEnd(self: *FuncGen) !Builder.Value {
64176348 const o = self.dg.object;
6418 if (o.di_builder == null) return null;
6349 if (o.di_builder == null) return .none;
64196350 self.di_scope = self.dbg_block_stack.pop();
6420 return null;
6351 return .none;
64216352 }
64226353
6423 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6354 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
64246355 const o = self.dg.object;
64256356 const mod = o.module;
6426 const dib = o.di_builder orelse return null;
6357 const dib = o.di_builder orelse return .none;
64276358 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
64286359 const operand = try self.resolveInst(pl_op.operand);
64296360 const name = self.air.nullTerminatedString(pl_op.payload);
......@@ -6443,22 +6374,20 @@ pub const FuncGen = struct {
64436374 else
64446375 null;
64456376 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
6446 const insert_block = self.builder.getInsertBlock();
6447 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
6448 return null;
6377 const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
6378 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
6379 return .none;
64496380 }
64506381
6451 fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6382 fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
64526383 const o = self.dg.object;
6453 const dib = o.di_builder orelse return null;
6384 const dib = o.di_builder orelse return .none;
64546385 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
64556386 const operand = try self.resolveInst(pl_op.operand);
64566387 const operand_ty = self.typeOf(pl_op.operand);
64576388 const name = self.air.nullTerminatedString(pl_op.payload);
64586389
6459 if (needDbgVarWorkaround(o)) {
6460 return null;
6461 }
6390 if (needDbgVarWorkaround(o)) return .none;
64626391
64636392 const di_local_var = dib.createAutoVariable(
64646393 self.di_scope.?,
......@@ -6474,23 +6403,22 @@ pub const FuncGen = struct {
64746403 else
64756404 null;
64766405 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
6477 const insert_block = self.builder.getInsertBlock();
6406 const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
64786407 const mod = o.module;
64796408 if (isByRef(operand_ty, mod)) {
6480 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
6409 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
64816410 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
6482 const alignment = operand_ty.abiAlignment(mod);
6483 const alloca = try self.buildAlloca(operand.typeOf(), alignment);
6484 const store_inst = self.builder.buildStore(operand, alloca);
6485 store_inst.setAlignment(alignment);
6486 _ = dib.insertDeclareAtEnd(alloca, di_local_var, debug_loc, insert_block);
6411 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
6412 const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
6413 _ = try self.wip.store(.normal, operand, alloca, alignment);
6414 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
64876415 } else {
6488 _ = dib.insertDbgValueIntrinsicAtEnd(operand, di_local_var, debug_loc, insert_block);
6416 _ = dib.insertDbgValueIntrinsicAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
64896417 }
6490 return null;
6418 return .none;
64916419 }
64926420
6493 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6421 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
64946422 // Eventually, the Zig compiler needs to be reworked to have inline
64956423 // assembly go through the same parsing code regardless of backend, and
64966424 // have LLVM-flavored inline assembly be *output* from that assembler.
......@@ -6523,11 +6451,11 @@ pub const FuncGen = struct {
65236451 const llvm_ret_indirect = try arena.alloc(bool, max_return_count);
65246452
65256453 const max_param_count = inputs.len + outputs.len;
6526 const llvm_param_types = try arena.alloc(*llvm.Type, max_param_count);
6454 const llvm_param_types = try arena.alloc(Builder.Type, max_param_count);
65276455 const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);
65286456 // This stores whether we need to add an elementtype attribute and
65296457 // if so, the element type itself.
6530 const llvm_param_attrs = try arena.alloc(?*llvm.Type, max_param_count);
6458 const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);
65316459 const mod = o.module;
65326460 const target = mod.getTarget();
65336461
......@@ -6564,9 +6492,9 @@ pub const FuncGen = struct {
65646492 // Pass the result by reference as an indirect output (e.g. "=*m")
65656493 llvm_constraints.appendAssumeCapacity('*');
65666494
6567 llvm_param_values[llvm_param_i] = output_inst;
6568 llvm_param_types[llvm_param_i] = output_inst.typeOf();
6569 llvm_param_attrs[llvm_param_i] = elem_llvm_ty.toLlvm(&o.builder);
6495 llvm_param_values[llvm_param_i] = output_inst.toLlvm(&self.wip);
6496 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
6497 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
65706498 llvm_param_i += 1;
65716499 } else {
65726500 // Pass the result directly (e.g. "=r")
......@@ -6614,27 +6542,26 @@ pub const FuncGen = struct {
66146542 if (isByRef(arg_ty, mod)) {
66156543 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
66166544 if (constraintAllowsMemory(constraint)) {
6617 llvm_param_values[llvm_param_i] = arg_llvm_value;
6618 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();
6545 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6546 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
66196547 } else {
6620 const alignment = arg_ty.abiAlignment(mod);
6621 const arg_llvm_ty = (try o.lowerType(arg_ty)).toLlvm(&o.builder);
6622 const load_inst = self.builder.buildLoad(arg_llvm_ty, arg_llvm_value, "");
6623 load_inst.setAlignment(alignment);
6624 llvm_param_values[llvm_param_i] = load_inst;
6548 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6549 const arg_llvm_ty = try o.lowerType(arg_ty);
6550 const load_inst =
6551 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
6552 llvm_param_values[llvm_param_i] = load_inst.toLlvm(&self.wip);
66256553 llvm_param_types[llvm_param_i] = arg_llvm_ty;
66266554 }
66276555 } else {
66286556 if (constraintAllowsRegister(constraint)) {
6629 llvm_param_values[llvm_param_i] = arg_llvm_value;
6630 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();
6557 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6558 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
66316559 } else {
6632 const alignment = arg_ty.abiAlignment(mod);
6633 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOf(), alignment);
6634 const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);
6635 store_inst.setAlignment(alignment);
6636 llvm_param_values[llvm_param_i] = arg_ptr;
6637 llvm_param_types[llvm_param_i] = arg_ptr.typeOf();
6560 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6561 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
6562 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
6563 llvm_param_values[llvm_param_i] = arg_ptr.toLlvm(&self.wip);
6564 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
66386565 }
66396566 }
66406567
......@@ -6658,12 +6585,12 @@ pub const FuncGen = struct {
66586585 // In the case of indirect inputs, LLVM requires the callsite to have
66596586 // an elementtype(<ty>) attribute.
66606587 if (constraint[0] == '*') {
6661 llvm_param_attrs[llvm_param_i] = (if (llvm_elem_ty != .none)
6588 llvm_param_attrs[llvm_param_i] = if (llvm_elem_ty != .none)
66626589 llvm_elem_ty
66636590 else
6664 try o.lowerPtrElemTy(arg_ty.childType(mod))).toLlvm(&o.builder);
6591 try o.lowerPtrElemTy(arg_ty.childType(mod));
66656592 } else {
6666 llvm_param_attrs[llvm_param_i] = null;
6593 llvm_param_attrs[llvm_param_i] = .none;
66676594 }
66686595
66696596 llvm_param_i += 1;
......@@ -6786,14 +6713,9 @@ pub const FuncGen = struct {
67866713 else => try o.builder.structType(.normal, llvm_ret_types),
67876714 };
67886715
6789 const llvm_fn_ty = llvm.functionType(
6790 ret_llvm_ty.toLlvm(&o.builder),
6791 llvm_param_types.ptr,
6792 @intCast(param_count),
6793 .False,
6794 );
6716 const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);
67956717 const asm_fn = llvm.getInlineAsm(
6796 llvm_fn_ty,
6718 llvm_fn_ty.toLlvm(&o.builder),
67976719 rendered_template.items.ptr,
67986720 rendered_template.items.len,
67996721 llvm_constraints.items.ptr,
......@@ -6803,18 +6725,18 @@ pub const FuncGen = struct {
68036725 .ATT,
68046726 .False,
68056727 );
6806 const call = self.builder.buildCall(
6807 llvm_fn_ty,
6728 const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCall(
6729 llvm_fn_ty.toLlvm(&o.builder),
68086730 asm_fn,
68096731 llvm_param_values.ptr,
68106732 @intCast(param_count),
68116733 .C,
68126734 .Auto,
68136735 "",
6814 );
6736 ), &self.wip);
68156737 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
6816 if (llvm_elem_ty) |llvm_ty| {
6817 llvm.setCallElemTypeAttr(call, i, llvm_ty);
6738 if (llvm_elem_ty != .none) {
6739 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
68186740 }
68196741 }
68206742
......@@ -6823,16 +6745,17 @@ pub const FuncGen = struct {
68236745 for (outputs, 0..) |output, i| {
68246746 if (llvm_ret_indirect[i]) continue;
68256747
6826 const output_value = if (return_count > 1) b: {
6827 break :b self.builder.buildExtractValue(call, @intCast(llvm_ret_i), "");
6828 } else call;
6748 const output_value = if (return_count > 1)
6749 try self.wip.extractValue(call, &[_]u32{@intCast(llvm_ret_i)}, "")
6750 else
6751 call;
68296752
68306753 if (output != .none) {
68316754 const output_ptr = try self.resolveInst(output);
68326755 const output_ptr_ty = self.typeOf(output);
68336756
6834 const store_inst = self.builder.buildStore(output_value, output_ptr);
6835 store_inst.setAlignment(output_ptr_ty.ptrAlignment(mod));
6757 const alignment = Builder.Alignment.fromByteUnits(output_ptr_ty.ptrAlignment(mod));
6758 _ = try self.wip.store(.normal, output_value, output_ptr, alignment);
68366759 } else {
68376760 ret_val = output_value;
68386761 }
......@@ -6846,8 +6769,8 @@ pub const FuncGen = struct {
68466769 self: *FuncGen,
68476770 inst: Air.Inst.Index,
68486771 operand_is_ptr: bool,
6849 pred: llvm.IntPredicate,
6850 ) !?*llvm.Value {
6772 cond: Builder.IntegerCondition,
6773 ) !Builder.Value {
68516774 const o = self.dg.object;
68526775 const mod = o.module;
68536776 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -6858,45 +6781,40 @@ pub const FuncGen = struct {
68586781 const payload_ty = optional_ty.optionalChild(mod);
68596782 if (optional_ty.optionalReprIsPayload(mod)) {
68606783 const loaded = if (operand_is_ptr)
6861 self.builder.buildLoad(optional_llvm_ty.toLlvm(&o.builder), operand, "")
6784 try self.wip.load(.normal, optional_llvm_ty, operand, .default, "")
68626785 else
68636786 operand;
68646787 if (payload_ty.isSlice(mod)) {
6865 const slice_ptr = self.builder.buildExtractValue(loaded, 0, "");
6788 const slice_ptr = try self.wip.extractValue(loaded, &.{0}, "");
68666789 const ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(
68676790 payload_ty.ptrAddressSpace(mod),
68686791 mod.getTarget(),
68696792 ));
6870 return self.builder.buildICmp(pred, slice_ptr, (try o.builder.nullConst(ptr_ty)).toLlvm(&o.builder), "");
6793 return self.wip.icmp(cond, slice_ptr, try o.builder.nullValue(ptr_ty), "");
68716794 }
6872 return self.builder.buildICmp(pred, loaded, (try o.builder.zeroInitConst(optional_llvm_ty)).toLlvm(&o.builder), "");
6795 return self.wip.icmp(cond, loaded, try o.builder.zeroInitValue(optional_llvm_ty), "");
68736796 }
68746797
68756798 comptime assert(optional_layout_version == 3);
68766799
68776800 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
68786801 const loaded = if (operand_is_ptr)
6879 self.builder.buildLoad(optional_llvm_ty.toLlvm(&o.builder), operand, "")
6802 try self.wip.load(.normal, optional_llvm_ty, operand, .default, "")
68806803 else
68816804 operand;
6882 return self.builder.buildICmp(pred, loaded, (try o.builder.intConst(.i8, 0)).toLlvm(&o.builder), "");
6805 return self.wip.icmp(cond, loaded, try o.builder.intValue(.i8, 0), "");
68836806 }
68846807
68856808 const is_by_ref = operand_is_ptr or isByRef(optional_ty, mod);
6886 const non_null_bit = try self.optIsNonNull(optional_llvm_ty.toLlvm(&o.builder), operand, is_by_ref);
6887 if (pred == .EQ) {
6888 return self.builder.buildNot(non_null_bit, "");
6889 } else {
6890 return non_null_bit;
6891 }
6809 return self.optCmpNull(cond, optional_llvm_ty, operand, is_by_ref);
68926810 }
68936811
68946812 fn airIsErr(
68956813 self: *FuncGen,
68966814 inst: Air.Inst.Index,
6897 op: llvm.IntPredicate,
6815 cond: Builder.IntegerCondition,
68986816 operand_is_ptr: bool,
6899 ) !?*llvm.Value {
6817 ) !Builder.Value {
69006818 const o = self.dg.object;
69016819 const mod = o.module;
69026820 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -6904,39 +6822,37 @@ pub const FuncGen = struct {
69046822 const operand_ty = self.typeOf(un_op);
69056823 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;
69066824 const payload_ty = err_union_ty.errorUnionPayload(mod);
6907 const zero = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder);
6825 const zero = try o.builder.intValue(Builder.Type.err_int, 0);
69086826
69096827 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
6910 const val: Builder.Constant = switch (op) {
6911 .EQ => .true, // 0 == 0
6912 .NE => .false, // 0 != 0
6828 const val: Builder.Constant = switch (cond) {
6829 .eq => .true, // 0 == 0
6830 .ne => .false, // 0 != 0
69136831 else => unreachable,
69146832 };
6915 return val.toLlvm(&o.builder);
6833 return val.toValue();
69166834 }
69176835
69186836 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
69196837 const loaded = if (operand_is_ptr)
6920 self.builder.buildLoad((try o.lowerType(err_union_ty)).toLlvm(&o.builder), operand, "")
6838 try self.wip.load(.normal, try o.lowerType(err_union_ty), operand, .default, "")
69216839 else
69226840 operand;
6923 return self.builder.buildICmp(op, loaded, zero, "");
6841 return self.wip.icmp(cond, loaded, zero, "");
69246842 }
69256843
69266844 const err_field_index = errUnionErrorOffset(payload_ty, mod);
69276845
6928 if (operand_is_ptr or isByRef(err_union_ty, mod)) {
6929 const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder);
6930 const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, "");
6931 const loaded = self.builder.buildLoad(Builder.Type.err_int.toLlvm(&o.builder), err_field_ptr, "");
6932 return self.builder.buildICmp(op, loaded, zero, "");
6933 }
6934
6935 const loaded = self.builder.buildExtractValue(operand, err_field_index, "");
6936 return self.builder.buildICmp(op, loaded, zero, "");
6846 const loaded = if (operand_is_ptr or isByRef(err_union_ty, mod)) loaded: {
6847 const err_union_llvm_ty = try o.lowerType(err_union_ty);
6848 const err_field_ptr =
6849 try self.wip.gepStruct(err_union_llvm_ty, operand, err_field_index, "");
6850 break :loaded try self.wip.load(.normal, Builder.Type.err_int, err_field_ptr, .default, "");
6851 } else try self.wip.extractValue(operand, &.{err_field_index}, "");
6852 return self.wip.icmp(cond, loaded, zero, "");
69376853 }
69386854
6939 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6855 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
69406856 const o = self.dg.object;
69416857 const mod = o.module;
69426858 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -6952,11 +6868,10 @@ pub const FuncGen = struct {
69526868 // The payload and the optional are the same value.
69536869 return operand;
69546870 }
6955 const optional_llvm_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);
6956 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
6871 return self.wip.gepStruct(try o.lowerType(optional_ty), operand, 0, "");
69576872 }
69586873
6959 fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6874 fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
69606875 comptime assert(optional_layout_version == 3);
69616876
69626877 const o = self.dg.object;
......@@ -6965,10 +6880,10 @@ pub const FuncGen = struct {
69656880 const operand = try self.resolveInst(ty_op.operand);
69666881 const optional_ty = self.typeOf(ty_op.operand).childType(mod);
69676882 const payload_ty = optional_ty.optionalChild(mod);
6968 const non_null_bit = (try o.builder.intConst(.i8, 1)).toLlvm(&o.builder);
6883 const non_null_bit = try o.builder.intValue(.i8, 1);
69696884 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
69706885 // We have a pointer to a i8. We need to set it to 1 and then return the same pointer.
6971 _ = self.builder.buildStore(non_null_bit, operand);
6886 _ = try self.wip.store(.normal, non_null_bit, operand, .default);
69726887 return operand;
69736888 }
69746889 if (optional_ty.optionalReprIsPayload(mod)) {
......@@ -6978,19 +6893,18 @@ pub const FuncGen = struct {
69786893 }
69796894
69806895 // First set the non-null bit.
6981 const optional_llvm_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);
6982 const non_null_ptr = self.builder.buildStructGEP(optional_llvm_ty, operand, 1, "");
6896 const optional_llvm_ty = try o.lowerType(optional_ty);
6897 const non_null_ptr = try self.wip.gepStruct(optional_llvm_ty, operand, 1, "");
69836898 // TODO set alignment on this store
6984 _ = self.builder.buildStore(non_null_bit, non_null_ptr);
6899 _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default);
69856900
69866901 // Then return the payload pointer (only if it's used).
6987 if (self.liveness.isUnused(inst))
6988 return null;
6902 if (self.liveness.isUnused(inst)) return .none;
69896903
6990 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
6904 return self.wip.gepStruct(optional_llvm_ty, operand, 0, "");
69916905 }
69926906
6993 fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
6907 fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
69946908 const o = self.dg.object;
69956909 const mod = o.module;
69966910 const inst = body_tail[0];
......@@ -6998,14 +6912,14 @@ pub const FuncGen = struct {
69986912 const operand = try self.resolveInst(ty_op.operand);
69996913 const optional_ty = self.typeOf(ty_op.operand);
70006914 const payload_ty = self.typeOfIndex(inst);
7001 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;
6915 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
70026916
70036917 if (optional_ty.optionalReprIsPayload(mod)) {
70046918 // Payload value is the same as the optional value.
70056919 return operand;
70066920 }
70076921
7008 const opt_llvm_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);
6922 const opt_llvm_ty = try o.lowerType(optional_ty);
70096923 const can_elide_load = if (isByRef(payload_ty, mod)) self.canElideLoad(body_tail) else false;
70106924 return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, can_elide_load);
70116925 }
......@@ -7014,7 +6928,7 @@ pub const FuncGen = struct {
70146928 self: *FuncGen,
70156929 body_tail: []const Air.Inst.Index,
70166930 operand_is_ptr: bool,
7017 ) !?*llvm.Value {
6931 ) !Builder.Value {
70186932 const o = self.dg.object;
70196933 const mod = o.module;
70206934 const inst = body_tail[0];
......@@ -7026,32 +6940,30 @@ pub const FuncGen = struct {
70266940 const payload_ty = if (operand_is_ptr) result_ty.childType(mod) else result_ty;
70276941
70286942 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
7029 return if (operand_is_ptr) operand else null;
6943 return if (operand_is_ptr) operand else .none;
70306944 }
70316945 const offset = errUnionPayloadOffset(payload_ty, mod);
7032 const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder);
6946 const err_union_llvm_ty = try o.lowerType(err_union_ty);
70336947 if (operand_is_ptr) {
7034 return self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
6948 return self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
70356949 } else if (isByRef(err_union_ty, mod)) {
7036 const payload_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
6950 const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod));
6951 const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
70376952 if (isByRef(payload_ty, mod)) {
7038 if (self.canElideLoad(body_tail))
7039 return payload_ptr;
7040
7041 return self.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(mod), false);
6953 if (self.canElideLoad(body_tail)) return payload_ptr;
6954 return self.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
70426955 }
7043 const load_inst = self.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, "");
7044 load_inst.setAlignment(payload_ty.abiAlignment(mod));
7045 return load_inst;
6956 const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
6957 return self.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
70466958 }
7047 return self.builder.buildExtractValue(operand, offset, "");
6959 return self.wip.extractValue(operand, &.{offset}, "");
70486960 }
70496961
70506962 fn airErrUnionErr(
70516963 self: *FuncGen,
70526964 inst: Air.Inst.Index,
70536965 operand_is_ptr: bool,
7054 ) !?*llvm.Value {
6966 ) !Builder.Value {
70556967 const o = self.dg.object;
70566968 const mod = o.module;
70576969 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -7062,30 +6974,28 @@ pub const FuncGen = struct {
70626974 if (operand_is_ptr) {
70636975 return operand;
70646976 } else {
7065 return (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder);
6977 return o.builder.intValue(Builder.Type.err_int, 0);
70666978 }
70676979 }
70686980
7069 const err_set_llvm_ty = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder);
7070
70716981 const payload_ty = err_union_ty.errorUnionPayload(mod);
70726982 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
70736983 if (!operand_is_ptr) return operand;
7074 return self.builder.buildLoad(err_set_llvm_ty, operand, "");
6984 return self.wip.load(.normal, Builder.Type.err_int, operand, .default, "");
70756985 }
70766986
70776987 const offset = errUnionErrorOffset(payload_ty, mod);
70786988
70796989 if (operand_is_ptr or isByRef(err_union_ty, mod)) {
7080 const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder);
7081 const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
7082 return self.builder.buildLoad(err_set_llvm_ty, err_field_ptr, "");
6990 const err_union_llvm_ty = try o.lowerType(err_union_ty);
6991 const err_field_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
6992 return self.wip.load(.normal, Builder.Type.err_int, err_field_ptr, .default, "");
70836993 }
70846994
7085 return self.builder.buildExtractValue(operand, offset, "");
6995 return self.wip.extractValue(operand, &.{offset}, "");
70866996 }
70876997
7088 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6998 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
70896999 const o = self.dg.object;
70907000 const mod = o.module;
70917001 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -7093,49 +7003,49 @@ pub const FuncGen = struct {
70937003 const err_union_ty = self.typeOf(ty_op.operand).childType(mod);
70947004
70957005 const payload_ty = err_union_ty.errorUnionPayload(mod);
7096 const non_error_val = try o.lowerValue((try mod.intValue(Type.err_int, 0)).toIntern());
7006 const non_error_val = try o.builder.intValue(Builder.Type.err_int, 0);
70977007 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
7098 _ = self.builder.buildStore(non_error_val.toLlvm(&o.builder), operand);
7008 _ = try self.wip.store(.normal, non_error_val, operand, .default);
70997009 return operand;
71007010 }
7101 const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder);
7011 const err_union_llvm_ty = try o.lowerType(err_union_ty);
71027012 {
7013 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
71037014 const error_offset = errUnionErrorOffset(payload_ty, mod);
71047015 // First set the non-error value.
7105 const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, "");
7106 const store_inst = self.builder.buildStore(non_error_val.toLlvm(&o.builder), non_null_ptr);
7107 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));
7016 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");
7017 _ = try self.wip.store(.normal, non_error_val, non_null_ptr, error_alignment);
71087018 }
71097019 // Then return the payload pointer (only if it is used).
7110 if (self.liveness.isUnused(inst))
7111 return null;
7020 if (self.liveness.isUnused(inst)) return .none;
71127021
71137022 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
7114 return self.builder.buildStructGEP(err_union_llvm_ty, operand, payload_offset, "");
7023 return self.wip.gepStruct(err_union_llvm_ty, operand, payload_offset, "");
71157024 }
71167025
7117 fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !?*llvm.Value {
7118 return self.err_ret_trace.?;
7026 fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !Builder.Value {
7027 assert(self.err_ret_trace != .none);
7028 return self.err_ret_trace;
71197029 }
71207030
7121 fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7031 fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
71227032 const un_op = self.air.instructions.items(.data)[inst].un_op;
7123 const operand = try self.resolveInst(un_op);
7124 self.err_ret_trace = operand;
7125 return null;
7033 self.err_ret_trace = try self.resolveInst(un_op);
7034 return .none;
71267035 }
71277036
7128 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7037 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
71297038 const o = self.dg.object;
71307039 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
7131 //const struct_ty = try self.resolveInst(ty_pl.ty);
71327040 const struct_ty = self.air.getRefType(ty_pl.ty);
71337041 const field_index = ty_pl.payload;
71347042
71357043 const mod = o.module;
71367044 const llvm_field = llvmField(struct_ty, field_index, mod).?;
7137 const struct_llvm_ty = (try o.lowerType(struct_ty)).toLlvm(&o.builder);
7138 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field.index, "");
7045 const struct_llvm_ty = try o.lowerType(struct_ty);
7046 assert(self.err_ret_trace != .none);
7047 const field_ptr =
7048 try self.wip.gepStruct(struct_llvm_ty, self.err_ret_trace, llvm_field.index, "");
71397049 const field_ptr_ty = try mod.ptrType(.{
71407050 .child = llvm_field.ty.toIntern(),
71417051 .flags = .{
......@@ -7145,34 +7055,32 @@ pub const FuncGen = struct {
71457055 return self.load(field_ptr, field_ptr_ty);
71467056 }
71477057
7148 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7058 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
71497059 const o = self.dg.object;
71507060 const mod = o.module;
71517061 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
71527062 const payload_ty = self.typeOf(ty_op.operand);
7153 const non_null_bit = (try o.builder.intConst(.i8, 1)).toLlvm(&o.builder);
7063 const non_null_bit = try o.builder.intValue(.i8, 1);
71547064 comptime assert(optional_layout_version == 3);
71557065 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return non_null_bit;
71567066 const operand = try self.resolveInst(ty_op.operand);
71577067 const optional_ty = self.typeOfIndex(inst);
7158 if (optional_ty.optionalReprIsPayload(mod)) {
7159 return operand;
7160 }
7161 const llvm_optional_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);
7068 if (optional_ty.optionalReprIsPayload(mod)) return operand;
7069 const llvm_optional_ty = try o.lowerType(optional_ty);
71627070 if (isByRef(optional_ty, mod)) {
7163 const optional_ptr = try self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(mod));
7164 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");
7071 const alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
7072 const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment);
7073 const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, "");
71657074 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
7166 try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
7167 const non_null_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 1, "");
7168 _ = self.builder.buildStore(non_null_bit, non_null_ptr);
7075 try self.store(payload_ptr, payload_ptr_ty, operand, .none);
7076 const non_null_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 1, "");
7077 _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default);
71697078 return optional_ptr;
71707079 }
7171 const partial = self.builder.buildInsertValue(llvm_optional_ty.getUndef(), operand, 0, "");
7172 return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
7080 return self.wip.buildAggregate(llvm_optional_ty, &.{ operand, non_null_bit }, "");
71737081 }
71747082
7175 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7083 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
71767084 const o = self.dg.object;
71777085 const mod = o.module;
71787086 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -7182,46 +7090,47 @@ pub const FuncGen = struct {
71827090 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
71837091 return operand;
71847092 }
7185 const ok_err_code = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder);
7186 const err_un_llvm_ty = (try o.lowerType(err_un_ty)).toLlvm(&o.builder);
7093 const ok_err_code = try o.builder.intValue(Builder.Type.err_int, 0);
7094 const err_un_llvm_ty = try o.lowerType(err_un_ty);
71877095
71887096 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
71897097 const error_offset = errUnionErrorOffset(payload_ty, mod);
71907098 if (isByRef(err_un_ty, mod)) {
7191 const result_ptr = try self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod));
7192 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
7193 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
7194 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));
7195 const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");
7099 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
7100 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7101 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
7102 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
7103 _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment);
7104 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
71967105 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
7197 try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
7106 try self.store(payload_ptr, payload_ptr_ty, operand, .none);
71987107 return result_ptr;
71997108 }
7200
7201 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, error_offset, "");
7202 return self.builder.buildInsertValue(partial, operand, payload_offset, "");
7109 var fields: [2]Builder.Value = undefined;
7110 fields[payload_offset] = operand;
7111 fields[error_offset] = ok_err_code;
7112 return self.wip.buildAggregate(err_un_llvm_ty, &fields, "");
72037113 }
72047114
7205 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7115 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
72067116 const o = self.dg.object;
72077117 const mod = o.module;
72087118 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
72097119 const err_un_ty = self.typeOfIndex(inst);
72107120 const payload_ty = err_un_ty.errorUnionPayload(mod);
72117121 const operand = try self.resolveInst(ty_op.operand);
7212 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
7213 return operand;
7214 }
7215 const err_un_llvm_ty = (try o.lowerType(err_un_ty)).toLlvm(&o.builder);
7122 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return operand;
7123 const err_un_llvm_ty = try o.lowerType(err_un_ty);
72167124
72177125 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
72187126 const error_offset = errUnionErrorOffset(payload_ty, mod);
72197127 if (isByRef(err_un_ty, mod)) {
7220 const result_ptr = try self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod));
7221 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
7222 const store_inst = self.builder.buildStore(operand, err_ptr);
7223 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));
7224 const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");
7128 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
7129 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7130 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
7131 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
7132 _ = try self.wip.store(.normal, operand, err_ptr, error_alignment);
7133 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
72257134 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
72267135 // TODO store undef to payload_ptr
72277136 _ = payload_ptr;
......@@ -7229,12 +7138,12 @@ pub const FuncGen = struct {
72297138 return result_ptr;
72307139 }
72317140
7232 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), operand, error_offset, "");
72337141 // TODO set payload bytes to undef
7234 return partial;
7142 const undef = try o.builder.undefValue(err_un_llvm_ty);
7143 return self.wip.insertValue(undef, operand, &.{error_offset}, "");
72357144 }
72367145
7237 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7146 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
72387147 const o = self.dg.object;
72397148 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
72407149 const index = pl_op.payload;
......@@ -7242,10 +7151,18 @@ pub const FuncGen = struct {
72427151 const args: [1]*llvm.Value = .{
72437152 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
72447153 };
7245 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
7154 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
7155 (try o.builder.fnType(.i32, &.{.i32}, .normal)).toLlvm(&o.builder),
7156 llvm_fn,
7157 &args,
7158 args.len,
7159 .Fast,
7160 .Auto,
7161 "",
7162 ), &self.wip);
72467163 }
72477164
7248 fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7165 fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
72497166 const o = self.dg.object;
72507167 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
72517168 const index = pl_op.payload;
......@@ -7253,12 +7170,20 @@ pub const FuncGen = struct {
72537170 const llvm_fn = try self.getIntrinsic("llvm.wasm.memory.grow", &.{.i32});
72547171 const args: [2]*llvm.Value = .{
72557172 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
7256 operand,
7173 operand.toLlvm(&self.wip),
72577174 };
7258 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
7175 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
7176 (try o.builder.fnType(.i32, &.{ .i32, .i32 }, .normal)).toLlvm(&o.builder),
7177 llvm_fn,
7178 &args,
7179 args.len,
7180 .Fast,
7181 .Auto,
7182 "",
7183 ), &self.wip);
72597184 }
72607185
7261 fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7186 fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
72627187 const o = self.dg.object;
72637188 const mod = o.module;
72647189 const data = self.air.instructions.items(.data)[inst].vector_store_elem;
......@@ -7269,19 +7194,20 @@ pub const FuncGen = struct {
72697194 const index = try self.resolveInst(extra.lhs);
72707195 const operand = try self.resolveInst(extra.rhs);
72717196
7272 const loaded_vector = blk: {
7273 const elem_llvm_ty = (try o.lowerType(vector_ptr_ty.childType(mod))).toLlvm(&o.builder);
7274 const load_inst = self.builder.buildLoad(elem_llvm_ty, vector_ptr, "");
7275 load_inst.setAlignment(vector_ptr_ty.ptrAlignment(mod));
7276 load_inst.setVolatile(llvm.Bool.fromBool(vector_ptr_ty.isVolatilePtr(mod)));
7277 break :blk load_inst;
7197 const kind: Builder.MemoryAccessKind = switch (vector_ptr_ty.isVolatilePtr(mod)) {
7198 false => .normal,
7199 true => .@"volatile",
72787200 };
7279 const modified_vector = self.builder.buildInsertElement(loaded_vector, operand, index, "");
7280 try self.store(vector_ptr, vector_ptr_ty, modified_vector, .NotAtomic);
7281 return null;
7201 const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod));
7202 const alignment = Builder.Alignment.fromByteUnits(vector_ptr_ty.ptrAlignment(mod));
7203 const loaded = try self.wip.load(kind, elem_llvm_ty, vector_ptr, alignment, "");
7204
7205 const new_vector = try self.wip.insertElement(loaded, operand, index, "");
7206 _ = try self.store(vector_ptr, vector_ptr_ty, new_vector, .none);
7207 return .none;
72827208 }
72837209
7284 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7210 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
72857211 const o = self.dg.object;
72867212 const mod = o.module;
72877213 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7290,11 +7216,13 @@ pub const FuncGen = struct {
72907216 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);
72917217
72927218 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmin, scalar_ty, 2, .{ lhs, rhs });
7293 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMin(lhs, rhs, "");
7294 return self.builder.buildUMin(lhs, rhs, "");
7219 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7220 .@"llvm.smin."
7221 else
7222 .@"llvm.umin.", lhs, rhs, "");
72957223 }
72967224
7297 fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7225 fn airMax(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
72987226 const o = self.dg.object;
72997227 const mod = o.module;
73007228 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7303,26 +7231,23 @@ pub const FuncGen = struct {
73037231 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);
73047232
73057233 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmax, scalar_ty, 2, .{ lhs, rhs });
7306 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMax(lhs, rhs, "");
7307 return self.builder.buildUMax(lhs, rhs, "");
7234 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7235 .@"llvm.smax."
7236 else
7237 .@"llvm.umax.", lhs, rhs, "");
73087238 }
73097239
7310 fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7240 fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
73117241 const o = self.dg.object;
73127242 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
73137243 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
73147244 const ptr = try self.resolveInst(bin_op.lhs);
73157245 const len = try self.resolveInst(bin_op.rhs);
73167246 const inst_ty = self.typeOfIndex(inst);
7317 const llvm_slice_ty = (try o.lowerType(inst_ty)).toLlvm(&o.builder);
7318
7319 // In case of slicing a global, the result type looks something like `{ i8*, i64 }`
7320 // but `ptr` is pointing to the global directly.
7321 const partial = self.builder.buildInsertValue(llvm_slice_ty.getUndef(), ptr, 0, "");
7322 return self.builder.buildInsertValue(partial, len, 1, "");
7247 return self.wip.buildAggregate(try o.lowerType(inst_ty), &.{ ptr, len }, "");
73237248 }
73247249
7325 fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7250 fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
73267251 self.builder.setFastMath(want_fast_math);
73277252
73287253 const o = self.dg.object;
......@@ -7334,8 +7259,7 @@ pub const FuncGen = struct {
73347259 const scalar_ty = inst_ty.scalarType(mod);
73357260
73367261 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.add, inst_ty, 2, .{ lhs, rhs });
7337 if (scalar_ty.isSignedInt(mod)) return self.builder.buildNSWAdd(lhs, rhs, "");
7338 return self.builder.buildNUWAdd(lhs, rhs, "");
7262 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"add nsw" else .@"add nuw", lhs, rhs, "");
73397263 }
73407264
73417265 fn airSafeArithmetic(
......@@ -7343,7 +7267,7 @@ pub const FuncGen = struct {
73437267 inst: Air.Inst.Index,
73447268 signed_intrinsic: []const u8,
73457269 unsigned_intrinsic: []const u8,
7346 ) !?*llvm.Value {
7270 ) !Builder.Value {
73477271 const o = fg.dg.object;
73487272 const mod = o.module;
73497273
......@@ -7358,44 +7282,51 @@ pub const FuncGen = struct {
73587282 true => signed_intrinsic,
73597283 false => unsigned_intrinsic,
73607284 };
7361 const llvm_fn = try fg.getIntrinsic(intrinsic_name, &.{try o.lowerType(inst_ty)});
7362 const result_struct = fg.builder.buildCall(
7363 llvm_fn.globalGetValueType(),
7285 const llvm_inst_ty = try o.lowerType(inst_ty);
7286 const llvm_ret_ty = try o.builder.structType(.normal, &.{
7287 llvm_inst_ty,
7288 try llvm_inst_ty.changeScalar(.i1, &o.builder),
7289 });
7290 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_inst_ty, llvm_inst_ty }, .normal);
7291 const llvm_fn = try fg.getIntrinsic(intrinsic_name, &.{llvm_inst_ty});
7292 const result_struct = (try fg.wip.unimplemented(llvm_ret_ty, "")).finish(fg.builder.buildCall(
7293 llvm_fn_ty.toLlvm(&o.builder),
73647294 llvm_fn,
7365 &[_]*llvm.Value{ lhs, rhs },
7295 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },
73667296 2,
73677297 .Fast,
73687298 .Auto,
73697299 "",
7370 );
7371 const overflow_bit = fg.builder.buildExtractValue(result_struct, 1, "");
7300 ), &fg.wip);
7301 const overflow_bit = try fg.wip.extractValue(result_struct, &.{1}, "");
73727302 const scalar_overflow_bit = switch (is_scalar) {
73737303 true => overflow_bit,
7374 false => fg.builder.buildOrReduce(overflow_bit),
7304 false => (try fg.wip.unimplemented(.i1, "")).finish(
7305 fg.builder.buildOrReduce(overflow_bit.toLlvm(&fg.wip)),
7306 &fg.wip,
7307 ),
73757308 };
73767309
7377 const fail_block = try fg.wip.block("OverflowFail");
7378 const ok_block = try fg.wip.block("OverflowOk");
7379 _ = fg.builder.buildCondBr(scalar_overflow_bit, fail_block.toLlvm(&fg.wip), ok_block.toLlvm(&fg.wip));
7310 const fail_block = try fg.wip.block(1, "OverflowFail");
7311 const ok_block = try fg.wip.block(1, "OverflowOk");
7312 _ = try fg.wip.brCond(scalar_overflow_bit, fail_block, ok_block);
73807313
73817314 fg.wip.cursor = .{ .block = fail_block };
7382 fg.builder.positionBuilderAtEnd(fail_block.toLlvm(&fg.wip));
73837315 try fg.buildSimplePanic(.integer_overflow);
73847316
73857317 fg.wip.cursor = .{ .block = ok_block };
7386 fg.builder.positionBuilderAtEnd(ok_block.toLlvm(&fg.wip));
7387 return fg.builder.buildExtractValue(result_struct, 0, "");
7318 return fg.wip.extractValue(result_struct, &.{0}, "");
73887319 }
73897320
7390 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7321 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
73917322 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
73927323 const lhs = try self.resolveInst(bin_op.lhs);
73937324 const rhs = try self.resolveInst(bin_op.rhs);
73947325
7395 return self.builder.buildAdd(lhs, rhs, "");
7326 return self.wip.bin(.add, lhs, rhs, "");
73967327 }
73977328
7398 fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7329 fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
73997330 const o = self.dg.object;
74007331 const mod = o.module;
74017332 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7405,12 +7336,13 @@ pub const FuncGen = struct {
74057336 const scalar_ty = inst_ty.scalarType(mod);
74067337
74077338 if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});
7408 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSAddSat(lhs, rhs, "");
7409
7410 return self.builder.buildUAddSat(lhs, rhs, "");
7339 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7340 .@"llvm.sadd.sat."
7341 else
7342 .@"llvm.uadd.sat.", lhs, rhs, "");
74117343 }
74127344
7413 fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7345 fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
74147346 self.builder.setFastMath(want_fast_math);
74157347
74167348 const o = self.dg.object;
......@@ -7422,19 +7354,18 @@ pub const FuncGen = struct {
74227354 const scalar_ty = inst_ty.scalarType(mod);
74237355
74247356 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.sub, inst_ty, 2, .{ lhs, rhs });
7425 if (scalar_ty.isSignedInt(mod)) return self.builder.buildNSWSub(lhs, rhs, "");
7426 return self.builder.buildNUWSub(lhs, rhs, "");
7357 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"sub nsw" else .@"sub nuw", lhs, rhs, "");
74277358 }
74287359
7429 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7360 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
74307361 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
74317362 const lhs = try self.resolveInst(bin_op.lhs);
74327363 const rhs = try self.resolveInst(bin_op.rhs);
74337364
7434 return self.builder.buildSub(lhs, rhs, "");
7365 return self.wip.bin(.sub, lhs, rhs, "");
74357366 }
74367367
7437 fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7368 fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
74387369 const o = self.dg.object;
74397370 const mod = o.module;
74407371 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7444,11 +7375,13 @@ pub const FuncGen = struct {
74447375 const scalar_ty = inst_ty.scalarType(mod);
74457376
74467377 if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
7447 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSSubSat(lhs, rhs, "");
7448 return self.builder.buildUSubSat(lhs, rhs, "");
7378 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7379 .@"llvm.ssub.sat."
7380 else
7381 .@"llvm.usub.sat.", lhs, rhs, "");
74497382 }
74507383
7451 fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7384 fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
74527385 self.builder.setFastMath(want_fast_math);
74537386
74547387 const o = self.dg.object;
......@@ -7460,19 +7393,18 @@ pub const FuncGen = struct {
74607393 const scalar_ty = inst_ty.scalarType(mod);
74617394
74627395 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.mul, inst_ty, 2, .{ lhs, rhs });
7463 if (scalar_ty.isSignedInt(mod)) return self.builder.buildNSWMul(lhs, rhs, "");
7464 return self.builder.buildNUWMul(lhs, rhs, "");
7396 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"mul nsw" else .@"mul nuw", lhs, rhs, "");
74657397 }
74667398
7467 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7399 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
74687400 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
74697401 const lhs = try self.resolveInst(bin_op.lhs);
74707402 const rhs = try self.resolveInst(bin_op.rhs);
74717403
7472 return self.builder.buildMul(lhs, rhs, "");
7404 return self.wip.bin(.mul, lhs, rhs, "");
74737405 }
74747406
7475 fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7407 fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
74767408 const o = self.dg.object;
74777409 const mod = o.module;
74787410 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7482,11 +7414,13 @@ pub const FuncGen = struct {
74827414 const scalar_ty = inst_ty.scalarType(mod);
74837415
74847416 if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
7485 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMulFixSat(lhs, rhs, "");
7486 return self.builder.buildUMulFixSat(lhs, rhs, "");
7417 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7418 .@"llvm.smul.fix.sat."
7419 else
7420 .@"llvm.umul.fix.sat.", lhs, rhs, "");
74877421 }
74887422
7489 fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7423 fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
74907424 self.builder.setFastMath(want_fast_math);
74917425
74927426 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7497,7 +7431,7 @@ pub const FuncGen = struct {
74977431 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
74987432 }
74997433
7500 fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7434 fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
75017435 self.builder.setFastMath(want_fast_math);
75027436
75037437 const o = self.dg.object;
......@@ -7512,11 +7446,10 @@ pub const FuncGen = struct {
75127446 const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
75137447 return self.buildFloatOp(.trunc, inst_ty, 1, .{result});
75147448 }
7515 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSDiv(lhs, rhs, "");
7516 return self.builder.buildUDiv(lhs, rhs, "");
7449 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .sdiv else .udiv, lhs, rhs, "");
75177450 }
75187451
7519 fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7452 fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
75207453 self.builder.setFastMath(want_fast_math);
75217454
75227455 const o = self.dg.object;
......@@ -7533,24 +7466,24 @@ pub const FuncGen = struct {
75337466 }
75347467 if (scalar_ty.isSignedInt(mod)) {
75357468 const inst_llvm_ty = try o.lowerType(inst_ty);
7536 const bit_size_minus_one = try o.builder.splatConst(inst_llvm_ty, try o.builder.intConst(
7469 const bit_size_minus_one = try o.builder.splatValue(inst_llvm_ty, try o.builder.intConst(
75377470 inst_llvm_ty.scalarType(&o.builder),
75387471 inst_llvm_ty.scalarBits(&o.builder) - 1,
75397472 ));
75407473
7541 const div = self.builder.buildSDiv(lhs, rhs, "");
7542 const rem = self.builder.buildSRem(lhs, rhs, "");
7543 const div_sign = self.builder.buildXor(lhs, rhs, "");
7544 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one.toLlvm(&o.builder), "");
7545 const zero = try o.builder.zeroInitConst(inst_llvm_ty);
7546 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero.toLlvm(&o.builder), "");
7547 const correction = self.builder.buildSelect(rem_nonzero, div_sign_mask, zero.toLlvm(&o.builder), "");
7548 return self.builder.buildNSWAdd(div, correction, "");
7474 const div = try self.wip.bin(.sdiv, lhs, rhs, "");
7475 const rem = try self.wip.bin(.srem, lhs, rhs, "");
7476 const div_sign = try self.wip.bin(.xor, lhs, rhs, "");
7477 const div_sign_mask = try self.wip.bin(.ashr, div_sign, bit_size_minus_one, "");
7478 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7479 const rem_nonzero = try self.wip.icmp(.ne, rem, zero, "");
7480 const correction = try self.wip.select(rem_nonzero, div_sign_mask, zero, "");
7481 return self.wip.bin(.@"add nsw", div, correction, "");
75497482 }
7550 return self.builder.buildUDiv(lhs, rhs, "");
7483 return self.wip.bin(.udiv, lhs, rhs, "");
75517484 }
75527485
7553 fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7486 fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
75547487 self.builder.setFastMath(want_fast_math);
75557488
75567489 const o = self.dg.object;
......@@ -7562,11 +7495,13 @@ pub const FuncGen = struct {
75627495 const scalar_ty = inst_ty.scalarType(mod);
75637496
75647497 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
7565 if (scalar_ty.isSignedInt(mod)) return self.builder.buildExactSDiv(lhs, rhs, "");
7566 return self.builder.buildExactUDiv(lhs, rhs, "");
7498 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7499 .@"sdiv exact"
7500 else
7501 .@"udiv exact", lhs, rhs, "");
75677502 }
75687503
7569 fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7504 fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
75707505 self.builder.setFastMath(want_fast_math);
75717506
75727507 const o = self.dg.object;
......@@ -7578,11 +7513,13 @@ pub const FuncGen = struct {
75787513 const scalar_ty = inst_ty.scalarType(mod);
75797514
75807515 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
7581 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSRem(lhs, rhs, "");
7582 return self.builder.buildURem(lhs, rhs, "");
7516 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7517 .srem
7518 else
7519 .urem, lhs, rhs, "");
75837520 }
75847521
7585 fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7522 fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
75867523 self.builder.setFastMath(want_fast_math);
75877524
75887525 const o = self.dg.object;
......@@ -7598,29 +7535,29 @@ pub const FuncGen = struct {
75987535 const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
75997536 const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });
76007537 const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs });
7601 const zero = try o.builder.zeroInitConst(inst_llvm_ty);
7602 const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero.toLlvm(&o.builder) });
7603 return self.builder.buildSelect(ltz, c, a, "");
7538 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7539 const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero });
7540 return self.wip.select(ltz, c, a, "");
76047541 }
76057542 if (scalar_ty.isSignedInt(mod)) {
7606 const bit_size_minus_one = try o.builder.splatConst(inst_llvm_ty, try o.builder.intConst(
7543 const bit_size_minus_one = try o.builder.splatValue(inst_llvm_ty, try o.builder.intConst(
76077544 inst_llvm_ty.scalarType(&o.builder),
76087545 inst_llvm_ty.scalarBits(&o.builder) - 1,
76097546 ));
76107547
7611 const rem = self.builder.buildSRem(lhs, rhs, "");
7612 const div_sign = self.builder.buildXor(lhs, rhs, "");
7613 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one.toLlvm(&o.builder), "");
7614 const rhs_masked = self.builder.buildAnd(rhs, div_sign_mask, "");
7615 const zero = try o.builder.zeroInitConst(inst_llvm_ty);
7616 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero.toLlvm(&o.builder), "");
7617 const correction = self.builder.buildSelect(rem_nonzero, rhs_masked, zero.toLlvm(&o.builder), "");
7618 return self.builder.buildNSWAdd(rem, correction, "");
7548 const rem = try self.wip.bin(.srem, lhs, rhs, "");
7549 const div_sign = try self.wip.bin(.xor, lhs, rhs, "");
7550 const div_sign_mask = try self.wip.bin(.ashr, div_sign, bit_size_minus_one, "");
7551 const rhs_masked = try self.wip.bin(.@"and", rhs, div_sign_mask, "");
7552 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7553 const rem_nonzero = try self.wip.icmp(.ne, rem, zero, "");
7554 const correction = try self.wip.select(rem_nonzero, rhs_masked, zero, "");
7555 return self.wip.bin(.@"add nsw", rem, correction, "");
76197556 }
7620 return self.builder.buildURem(lhs, rhs, "");
7557 return self.wip.bin(.urem, lhs, rhs, "");
76217558 }
76227559
7623 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7560 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
76247561 const o = self.dg.object;
76257562 const mod = o.module;
76267563 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -7628,55 +7565,39 @@ pub const FuncGen = struct {
76287565 const ptr = try self.resolveInst(bin_op.lhs);
76297566 const offset = try self.resolveInst(bin_op.rhs);
76307567 const ptr_ty = self.typeOf(bin_op.lhs);
7631 const llvm_elem_ty = (try o.lowerPtrElemTy(ptr_ty.childType(mod))).toLlvm(&o.builder);
7568 const llvm_elem_ty = try o.lowerPtrElemTy(ptr_ty.childType(mod));
76327569 switch (ptr_ty.ptrSize(mod)) {
7633 .One => {
7634 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7635 const indices: [2]*llvm.Value = .{
7636 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
7637 offset,
7638 };
7639 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
7640 },
7641 .C, .Many => {
7642 const indices: [1]*llvm.Value = .{offset};
7643 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
7644 },
7570 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7571 .One => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{
7572 try o.builder.intValue(try o.lowerType(Type.usize), 0), offset,
7573 }, ""),
7574 .C, .Many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{offset}, ""),
76457575 .Slice => {
7646 const base = self.builder.buildExtractValue(ptr, 0, "");
7647 const indices: [1]*llvm.Value = .{offset};
7648 return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
7576 const base = try self.wip.extractValue(ptr, &.{0}, "");
7577 return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{offset}, "");
76497578 },
76507579 }
76517580 }
76527581
7653 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7582 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
76547583 const o = self.dg.object;
76557584 const mod = o.module;
76567585 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
76577586 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
76587587 const ptr = try self.resolveInst(bin_op.lhs);
76597588 const offset = try self.resolveInst(bin_op.rhs);
7660 const negative_offset = self.builder.buildNeg(offset, "");
7589 const negative_offset = try self.wip.neg(offset, "");
76617590 const ptr_ty = self.typeOf(bin_op.lhs);
7662 const llvm_elem_ty = (try o.lowerPtrElemTy(ptr_ty.childType(mod))).toLlvm(&o.builder);
7591 const llvm_elem_ty = try o.lowerPtrElemTy(ptr_ty.childType(mod));
76637592 switch (ptr_ty.ptrSize(mod)) {
7664 .One => {
7665 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7666 const indices: [2]*llvm.Value = .{
7667 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
7668 negative_offset,
7669 };
7670 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
7671 },
7672 .C, .Many => {
7673 const indices: [1]*llvm.Value = .{negative_offset};
7674 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
7675 },
7593 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7594 .One => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{
7595 try o.builder.intValue(try o.lowerType(Type.usize), 0), negative_offset,
7596 }, ""),
7597 .C, .Many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{negative_offset}, ""),
76767598 .Slice => {
7677 const base = self.builder.buildExtractValue(ptr, 0, "");
7678 const indices: [1]*llvm.Value = .{negative_offset};
7679 return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
7599 const base = try self.wip.extractValue(ptr, &.{0}, "");
7600 return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{negative_offset}, "");
76807601 },
76817602 }
76827603 }
......@@ -7686,7 +7607,7 @@ pub const FuncGen = struct {
76867607 inst: Air.Inst.Index,
76877608 signed_intrinsic: []const u8,
76887609 unsigned_intrinsic: []const u8,
7689 ) !?*llvm.Value {
7610 ) !Builder.Value {
76907611 const o = self.dg.object;
76917612 const mod = o.module;
76927613 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -7701,59 +7622,91 @@ pub const FuncGen = struct {
77017622
77027623 const intrinsic_name = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic;
77037624
7704 const llvm_dest_ty = (try o.lowerType(dest_ty)).toLlvm(&o.builder);
7625 const llvm_dest_ty = try o.lowerType(dest_ty);
7626 const llvm_lhs_ty = try o.lowerType(lhs_ty);
77057627
7706 const llvm_fn = try self.getIntrinsic(intrinsic_name, &.{try o.lowerType(lhs_ty)});
7707 const result_struct = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &[_]*llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, "");
7628 const llvm_fn = try self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty});
7629 const llvm_ret_ty = try o.builder.structType(
7630 .normal,
7631 &.{ llvm_lhs_ty, try llvm_lhs_ty.changeScalar(.i1, &o.builder) },
7632 );
7633 const llvm_fn_ty = try o.builder.fnType(llvm_ret_ty, &.{ llvm_lhs_ty, llvm_lhs_ty }, .normal);
7634 const result_struct = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(
7635 self.builder.buildCall(
7636 llvm_fn_ty.toLlvm(&o.builder),
7637 llvm_fn,
7638 &[_]*llvm.Value{ lhs.toLlvm(&self.wip), rhs.toLlvm(&self.wip) },
7639 2,
7640 .Fast,
7641 .Auto,
7642 "",
7643 ),
7644 &self.wip,
7645 );
77087646
7709 const result = self.builder.buildExtractValue(result_struct, 0, "");
7710 const overflow_bit = self.builder.buildExtractValue(result_struct, 1, "");
7647 const result = try self.wip.extractValue(result_struct, &.{0}, "");
7648 const overflow_bit = try self.wip.extractValue(result_struct, &.{1}, "");
77117649
77127650 const result_index = llvmField(dest_ty, 0, mod).?.index;
77137651 const overflow_index = llvmField(dest_ty, 1, mod).?.index;
77147652
77157653 if (isByRef(dest_ty, mod)) {
7716 const result_alignment = dest_ty.abiAlignment(mod);
7654 const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
77177655 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
77187656 {
7719 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
7720 const store_inst = self.builder.buildStore(result, field_ptr);
7721 store_inst.setAlignment(result_alignment);
7657 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
7658 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);
77227659 }
77237660 {
7724 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");
7725 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);
7726 store_inst.setAlignment(1);
7661 const overflow_alignment = comptime Builder.Alignment.fromByteUnits(1);
7662 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");
7663 _ = try self.wip.store(.normal, overflow_bit, field_ptr, overflow_alignment);
77277664 }
77287665
77297666 return alloca_inst;
77307667 }
77317668
7732 const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");
7733 return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");
7669 var fields: [2]Builder.Value = undefined;
7670 fields[result_index] = result;
7671 fields[overflow_index] = overflow_bit;
7672 return self.wip.buildAggregate(llvm_dest_ty, &fields, "");
77347673 }
77357674
77367675 fn buildElementwiseCall(
77377676 self: *FuncGen,
7738 llvm_fn: *llvm.Value,
7739 args_vectors: []const *llvm.Value,
7740 result_vector: *llvm.Value,
7677 llvm_fn: Builder.Function.Index,
7678 args_vectors: []const Builder.Value,
7679 result_vector: Builder.Value,
77417680 vector_len: usize,
7742 ) !*llvm.Value {
7681 ) !Builder.Value {
77437682 const o = self.dg.object;
77447683 assert(args_vectors.len <= 3);
77457684
7685 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
7686 const llvm_scalar_ty = llvm_fn_ty.functionReturn(&o.builder);
7687
77467688 var i: usize = 0;
77477689 var result = result_vector;
77487690 while (i < vector_len) : (i += 1) {
7749 const index_i32 = (try o.builder.intConst(.i32, i)).toLlvm(&o.builder);
7691 const index_i32 = try o.builder.intValue(.i32, i);
77507692
77517693 var args: [3]*llvm.Value = undefined;
7752 for (args_vectors, 0..) |arg_vector, k| {
7753 args[k] = self.builder.buildExtractElement(arg_vector, index_i32, "");
7694 for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {
7695 arg_elem.* = (try self.wip.extractElement(arg_vector, index_i32, "")).toLlvm(&self.wip);
77547696 }
7755 const result_elem = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, @intCast(args_vectors.len), .C, .Auto, "");
7756 result = self.builder.buildInsertElement(result, result_elem, index_i32, "");
7697 const result_elem = (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
7698 self.builder.buildCall(
7699 llvm_fn_ty.toLlvm(&o.builder),
7700 llvm_fn.toLlvm(&o.builder),
7701 &args,
7702 @intCast(args_vectors.len),
7703 .C,
7704 .Auto,
7705 "",
7706 ),
7707 &self.wip,
7708 );
7709 result = try self.wip.insertElement(result, result_elem, index_i32, "");
77577710 }
77587711 return result;
77597712 }
......@@ -7763,29 +7716,29 @@ pub const FuncGen = struct {
77637716 fn_name: Builder.String,
77647717 param_types: []const Builder.Type,
77657718 return_type: Builder.Type,
7766 ) Allocator.Error!*llvm.Value {
7719 ) Allocator.Error!Builder.Function.Index {
77677720 const o = self.dg.object;
7768 const slice = fn_name.toSlice(&o.builder).?;
7769 return o.llvm_module.getNamedFunction(slice) orelse b: {
7770 const alias = o.llvm_module.getNamedGlobalAlias(slice.ptr, slice.len);
7771 break :b if (alias) |a| a.getAliasee() else null;
7772 } orelse b: {
7773 const fn_type = try o.builder.fnType(return_type, param_types, .normal);
7774 const f = o.llvm_module.addFunction(slice, fn_type.toLlvm(&o.builder));
7775
7776 var global = Builder.Global{
7777 .type = fn_type,
7778 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
7779 };
7780 var function = Builder.Function{
7781 .global = @enumFromInt(o.builder.globals.count()),
7782 };
7721 if (o.builder.getGlobal(fn_name)) |global| return switch (global.ptrConst(&o.builder).kind) {
7722 .alias => |alias| alias.getAliasee(&o.builder).ptrConst(&o.builder).kind.function,
7723 .function => |function| function,
7724 else => unreachable,
7725 };
77837726
7784 try o.builder.llvm.globals.append(self.gpa, f);
7785 _ = try o.builder.addGlobal(fn_name, global);
7786 try o.builder.functions.append(self.gpa, function);
7787 break :b f;
7727 const fn_type = try o.builder.fnType(return_type, param_types, .normal);
7728 const f = o.llvm_module.addFunction(fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
7729
7730 var global = Builder.Global{
7731 .type = fn_type,
7732 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
7733 };
7734 var function = Builder.Function{
7735 .global = @enumFromInt(o.builder.globals.count()),
77887736 };
7737
7738 try o.builder.llvm.globals.append(self.gpa, f);
7739 _ = try o.builder.addGlobal(fn_name, global);
7740 try o.builder.functions.append(self.gpa, function);
7741 return global.kind.function;
77897742 }
77907743
77917744 /// Creates a floating point comparison by lowering to the appropriate
......@@ -7794,8 +7747,8 @@ pub const FuncGen = struct {
77947747 self: *FuncGen,
77957748 pred: math.CompareOperator,
77967749 ty: Type,
7797 params: [2]*llvm.Value,
7798 ) !*llvm.Value {
7750 params: [2]Builder.Value,
7751 ) !Builder.Value {
77997752 const o = self.dg.object;
78007753 const mod = o.module;
78017754 const target = o.module.getTarget();
......@@ -7803,15 +7756,15 @@ pub const FuncGen = struct {
78037756 const scalar_llvm_ty = try o.lowerType(scalar_ty);
78047757
78057758 if (intrinsicsAllowed(scalar_ty, target)) {
7806 const llvm_predicate: llvm.RealPredicate = switch (pred) {
7807 .eq => .OEQ,
7808 .neq => .UNE,
7809 .lt => .OLT,
7810 .lte => .OLE,
7811 .gt => .OGT,
7812 .gte => .OGE,
7759 const cond: Builder.FloatCondition = switch (pred) {
7760 .eq => .oeq,
7761 .neq => .une,
7762 .lt => .olt,
7763 .lte => .ole,
7764 .gt => .ogt,
7765 .gte => .oge,
78137766 };
7814 return self.builder.buildFCmp(llvm_predicate, params[0], params[1], "");
7767 return self.wip.fcmp(cond, params[0], params[1], "");
78157768 }
78167769
78177770 const float_bits = scalar_ty.floatBits(target);
......@@ -7832,29 +7785,42 @@ pub const FuncGen = struct {
78327785 .i32,
78337786 );
78347787
7835 const zero = (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder);
7836 const int_pred: llvm.IntPredicate = switch (pred) {
7837 .eq => .EQ,
7838 .neq => .NE,
7839 .lt => .SLT,
7840 .lte => .SLE,
7841 .gt => .SGT,
7842 .gte => .SGE,
7788 const zero = try o.builder.intConst(.i32, 0);
7789 const int_cond: Builder.IntegerCondition = switch (pred) {
7790 .eq => .eq,
7791 .neq => .ne,
7792 .lt => .slt,
7793 .lte => .sle,
7794 .gt => .sgt,
7795 .gte => .sge,
78437796 };
78447797
78457798 if (ty.zigTypeTag(mod) == .Vector) {
78467799 const vec_len = ty.vectorLen(mod);
7847 const vector_result_ty = (try o.builder.vectorType(.normal, vec_len, .i32)).toLlvm(&o.builder);
7800 const vector_result_ty = try o.builder.vectorType(.normal, vec_len, .i32);
78487801
7849 var result = vector_result_ty.getUndef();
7850 result = try self.buildElementwiseCall(libc_fn, &params, result, vec_len);
7802 const init = try o.builder.poisonValue(vector_result_ty);
7803 const result = try self.buildElementwiseCall(libc_fn, &params, init, vec_len);
78517804
7852 const zero_vector = self.builder.buildVectorSplat(vec_len, zero, "");
7853 return self.builder.buildICmp(int_pred, result, zero_vector, "");
7805 const zero_vector = try o.builder.splatValue(vector_result_ty, zero);
7806 return self.wip.icmp(int_cond, result, zero_vector, "");
78547807 }
78557808
7856 const result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");
7857 return self.builder.buildICmp(int_pred, result, zero, "");
7809 const llvm_fn_ty = libc_fn.typeOf(&o.builder);
7810 const llvm_params = [2]*llvm.Value{ params[0].toLlvm(&self.wip), params[1].toLlvm(&self.wip) };
7811 const result = (try self.wip.unimplemented(
7812 llvm_fn_ty.functionReturn(&o.builder),
7813 "",
7814 )).finish(self.builder.buildCall(
7815 libc_fn.typeOf(&o.builder).toLlvm(&o.builder),
7816 libc_fn.toLlvm(&o.builder),
7817 &llvm_params,
7818 llvm_params.len,
7819 .C,
7820 .Auto,
7821 "",
7822 ), &self.wip);
7823 return self.wip.icmp(int_cond, result, zero.toValue(), "");
78587824 }
78597825
78607826 const FloatOp = enum {
......@@ -7896,26 +7862,25 @@ pub const FuncGen = struct {
78967862 comptime op: FloatOp,
78977863 ty: Type,
78987864 comptime params_len: usize,
7899 params: [params_len]*llvm.Value,
7900 ) !*llvm.Value {
7865 params: [params_len]Builder.Value,
7866 ) !Builder.Value {
79017867 const o = self.dg.object;
79027868 const mod = o.module;
79037869 const target = mod.getTarget();
79047870 const scalar_ty = ty.scalarType(mod);
79057871 const llvm_ty = try o.lowerType(ty);
7906 const scalar_llvm_ty = try o.lowerType(scalar_ty);
79077872
79087873 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);
79097874 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
79107875 // Some operations are dedicated LLVM instructions, not available as intrinsics
7911 .neg => return self.builder.buildFNeg(params[0], ""),
7912 .add => return self.builder.buildFAdd(params[0], params[1], ""),
7913 .sub => return self.builder.buildFSub(params[0], params[1], ""),
7914 .mul => return self.builder.buildFMul(params[0], params[1], ""),
7915 .div => return self.builder.buildFDiv(params[0], params[1], ""),
7916 .fmod => return self.builder.buildFRem(params[0], params[1], ""),
7917 .fmax => return self.builder.buildMaxNum(params[0], params[1], ""),
7918 .fmin => return self.builder.buildMinNum(params[0], params[1], ""),
7876 .neg => return self.wip.un(.fneg, params[0], ""),
7877 .add => return self.wip.bin(.fadd, params[0], params[1], ""),
7878 .sub => return self.wip.bin(.fsub, params[0], params[1], ""),
7879 .mul => return self.wip.bin(.fmul, params[0], params[1], ""),
7880 .div => return self.wip.bin(.fdiv, params[0], params[1], ""),
7881 .fmod => return self.wip.bin(.frem, params[0], params[1], ""),
7882 .fmax => return self.wip.bin(.@"llvm.maxnum.", params[0], params[1], ""),
7883 .fmin => return self.wip.bin(.@"llvm.minnum.", params[0], params[1], ""),
79197884 else => .{ .intrinsic = "llvm." ++ @tagName(op) },
79207885 } else b: {
79217886 const float_bits = scalar_ty.floatBits(target);
......@@ -7924,19 +7889,14 @@ pub const FuncGen = struct {
79247889 // In this case we can generate a softfloat negation by XORing the
79257890 // bits with a constant.
79267891 const int_ty = try o.builder.intType(@intCast(float_bits));
7927 const one = try o.builder.intConst(int_ty, 1);
7928 const shift_amt = try o.builder.intConst(int_ty, float_bits - 1);
7929 const sign_mask = try o.builder.binConst(.shl, one, shift_amt);
7930 const result = if (ty.zigTypeTag(mod) == .Vector) blk: {
7931 const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(mod), sign_mask.toLlvm(&o.builder), "");
7932 const cast_ty = try o.builder.vectorType(.normal, ty.vectorLen(mod), int_ty);
7933 const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty.toLlvm(&o.builder), "");
7934 break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, "");
7935 } else blk: {
7936 const bitcasted_operand = self.builder.buildBitCast(params[0], int_ty.toLlvm(&o.builder), "");
7937 break :blk self.builder.buildXor(bitcasted_operand, sign_mask.toLlvm(&o.builder), "");
7938 };
7939 return self.builder.buildBitCast(result, llvm_ty.toLlvm(&o.builder), "");
7892 const cast_ty = try llvm_ty.changeScalar(int_ty, &o.builder);
7893 const sign_mask = try o.builder.splatValue(
7894 cast_ty,
7895 try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)),
7896 );
7897 const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, "");
7898 const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, "");
7899 return self.wip.cast(.bitcast, result, llvm_ty, "");
79407900 },
79417901 .add, .sub, .div, .mul => .{ .libc = try o.builder.fmt("__{s}{s}f3", .{
79427902 @tagName(op), compilerRtFloatAbbrev(float_bits),
......@@ -7965,26 +7925,42 @@ pub const FuncGen = struct {
79657925 };
79667926 };
79677927
7968 const llvm_fn: *llvm.Value = switch (strat) {
7928 const llvm_fn = switch (strat) {
79697929 .intrinsic => |fn_name| try self.getIntrinsic(fn_name, &.{llvm_ty}),
79707930 .libc => |fn_name| b: {
7931 const scalar_llvm_ty = llvm_ty.scalarType(&o.builder);
79717932 const libc_fn = try self.getLibcFunction(
79727933 fn_name,
79737934 ([1]Builder.Type{scalar_llvm_ty} ** 3)[0..params.len],
79747935 scalar_llvm_ty,
79757936 );
79767937 if (ty.zigTypeTag(mod) == .Vector) {
7977 const result = llvm_ty.toLlvm(&o.builder).getUndef();
7938 const result = try o.builder.poisonValue(llvm_ty);
79787939 return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod));
79797940 }
79807941
7981 break :b libc_fn;
7942 break :b libc_fn.toLlvm(&o.builder);
79827943 },
79837944 };
7984 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params_len, .C, .Auto, "");
7945 const llvm_fn_ty = try o.builder.fnType(
7946 llvm_ty,
7947 ([1]Builder.Type{llvm_ty} ** 3)[0..params.len],
7948 .normal,
7949 );
7950 var llvm_params: [params_len]*llvm.Value = undefined;
7951 for (&llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(&self.wip);
7952 return (try self.wip.unimplemented(llvm_ty, "")).finish(self.builder.buildCall(
7953 llvm_fn_ty.toLlvm(&o.builder),
7954 llvm_fn,
7955 &llvm_params,
7956 params_len,
7957 .C,
7958 .Auto,
7959 "",
7960 ), &self.wip);
79857961 }
79867962
7987 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7963 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
79887964 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
79897965 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
79907966
......@@ -7996,7 +7972,7 @@ pub const FuncGen = struct {
79967972 return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend });
79977973 }
79987974
7999 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7975 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
80007976 const o = self.dg.object;
80017977 const mod = o.module;
80027978 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -8006,72 +7982,67 @@ pub const FuncGen = struct {
80067982 const rhs = try self.resolveInst(extra.rhs);
80077983
80087984 const lhs_ty = self.typeOf(extra.lhs);
8009 const rhs_ty = self.typeOf(extra.rhs);
80107985 const lhs_scalar_ty = lhs_ty.scalarType(mod);
8011 const rhs_scalar_ty = rhs_ty.scalarType(mod);
80127986
80137987 const dest_ty = self.typeOfIndex(inst);
8014 const llvm_dest_ty = (try o.lowerType(dest_ty)).toLlvm(&o.builder);
7988 const llvm_dest_ty = try o.lowerType(dest_ty);
80157989
8016 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod))
8017 self.builder.buildZExt(rhs, (try o.lowerType(lhs_ty)).toLlvm(&o.builder), "")
8018 else
8019 rhs;
7990 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
80207991
8021 const result = self.builder.buildShl(lhs, casted_rhs, "");
8022 const reconstructed = if (lhs_scalar_ty.isSignedInt(mod))
8023 self.builder.buildAShr(result, casted_rhs, "")
7992 const result = try self.wip.bin(.shl, lhs, casted_rhs, "");
7993 const reconstructed = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
7994 .ashr
80247995 else
8025 self.builder.buildLShr(result, casted_rhs, "");
7996 .lshr, result, casted_rhs, "");
80267997
8027 const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, "");
7998 const overflow_bit = try self.wip.icmp(.ne, lhs, reconstructed, "");
80287999
80298000 const result_index = llvmField(dest_ty, 0, mod).?.index;
80308001 const overflow_index = llvmField(dest_ty, 1, mod).?.index;
80318002
80328003 if (isByRef(dest_ty, mod)) {
8033 const result_alignment = dest_ty.abiAlignment(mod);
8004 const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
80348005 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
80358006 {
8036 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
8037 const store_inst = self.builder.buildStore(result, field_ptr);
8038 store_inst.setAlignment(result_alignment);
8007 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
8008 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);
80398009 }
80408010 {
8041 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");
8042 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);
8043 store_inst.setAlignment(1);
8011 const field_alignment = comptime Builder.Alignment.fromByteUnits(1);
8012 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");
8013 _ = try self.wip.store(.normal, overflow_bit, field_ptr, field_alignment);
80448014 }
8045
80468015 return alloca_inst;
80478016 }
80488017
8049 const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");
8050 return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");
8018 var fields: [2]Builder.Value = undefined;
8019 fields[result_index] = result;
8020 fields[overflow_index] = overflow_bit;
8021 return self.wip.buildAggregate(llvm_dest_ty, &fields, "");
80518022 }
80528023
8053 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8024 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
80548025 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
80558026 const lhs = try self.resolveInst(bin_op.lhs);
80568027 const rhs = try self.resolveInst(bin_op.rhs);
8057 return self.builder.buildAnd(lhs, rhs, "");
8028 return self.wip.bin(.@"and", lhs, rhs, "");
80588029 }
80598030
8060 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8031 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
80618032 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
80628033 const lhs = try self.resolveInst(bin_op.lhs);
80638034 const rhs = try self.resolveInst(bin_op.rhs);
8064 return self.builder.buildOr(lhs, rhs, "");
8035 return self.wip.bin(.@"or", lhs, rhs, "");
80658036 }
80668037
8067 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8038 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
80688039 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
80698040 const lhs = try self.resolveInst(bin_op.lhs);
80708041 const rhs = try self.resolveInst(bin_op.rhs);
8071 return self.builder.buildXor(lhs, rhs, "");
8042 return self.wip.bin(.xor, lhs, rhs, "");
80728043 }
80738044
8074 fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8045 fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
80758046 const o = self.dg.object;
80768047 const mod = o.module;
80778048 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -8080,39 +8051,29 @@ pub const FuncGen = struct {
80808051 const rhs = try self.resolveInst(bin_op.rhs);
80818052
80828053 const lhs_ty = self.typeOf(bin_op.lhs);
8083 const rhs_ty = self.typeOf(bin_op.rhs);
80848054 const lhs_scalar_ty = lhs_ty.scalarType(mod);
8085 const rhs_scalar_ty = rhs_ty.scalarType(mod);
80868055
8087 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod))
8088 self.builder.buildZExt(rhs, (try o.lowerType(lhs_ty)).toLlvm(&o.builder), "")
8056 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
8057 return self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
8058 .@"shl nsw"
80898059 else
8090 rhs;
8091 if (lhs_scalar_ty.isSignedInt(mod)) return self.builder.buildNSWShl(lhs, casted_rhs, "");
8092 return self.builder.buildNUWShl(lhs, casted_rhs, "");
8060 .@"shl nuw", lhs, casted_rhs, "");
80938061 }
80948062
8095 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8063 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
80968064 const o = self.dg.object;
8097 const mod = o.module;
80988065 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
80998066
81008067 const lhs = try self.resolveInst(bin_op.lhs);
81018068 const rhs = try self.resolveInst(bin_op.rhs);
81028069
81038070 const lhs_type = self.typeOf(bin_op.lhs);
8104 const rhs_type = self.typeOf(bin_op.rhs);
8105 const lhs_scalar_ty = lhs_type.scalarType(mod);
8106 const rhs_scalar_ty = rhs_type.scalarType(mod);
81078071
8108 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod))
8109 self.builder.buildZExt(rhs, (try o.lowerType(lhs_type)).toLlvm(&o.builder), "")
8110 else
8111 rhs;
8112 return self.builder.buildShl(lhs, casted_rhs, "");
8072 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_type), "");
8073 return self.wip.bin(.shl, lhs, casted_rhs, "");
81138074 }
81148075
8115 fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8076 fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
81168077 const o = self.dg.object;
81178078 const mod = o.module;
81188079 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -8121,42 +8082,36 @@ pub const FuncGen = struct {
81218082 const rhs = try self.resolveInst(bin_op.rhs);
81228083
81238084 const lhs_ty = self.typeOf(bin_op.lhs);
8124 const rhs_ty = self.typeOf(bin_op.rhs);
81258085 const lhs_scalar_ty = lhs_ty.scalarType(mod);
8126 const rhs_scalar_ty = rhs_ty.scalarType(mod);
81278086 const lhs_bits = lhs_scalar_ty.bitSize(mod);
81288087
8129 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_bits)
8130 self.builder.buildZExt(rhs, lhs.typeOf(), "")
8131 else
8132 rhs;
8088 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
81338089
8134 const result = if (lhs_scalar_ty.isSignedInt(mod))
8135 self.builder.buildSShlSat(lhs, casted_rhs, "")
8090 const result = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
8091 .@"llvm.sshl.sat."
81368092 else
8137 self.builder.buildUShlSat(lhs, casted_rhs, "");
8093 .@"llvm.ushl.sat.", lhs, casted_rhs, "");
81388094
81398095 // LLVM langref says "If b is (statically or dynamically) equal to or
81408096 // larger than the integer bit width of the arguments, the result is a
81418097 // poison value."
81428098 // However Zig semantics says that saturating shift left can never produce
81438099 // undefined; instead it saturates.
8144 const lhs_scalar_llvm_ty = try o.lowerType(lhs_scalar_ty);
8145 const bits = (try o.builder.intConst(lhs_scalar_llvm_ty, lhs_bits)).toLlvm(&o.builder);
8146 const lhs_max = (try o.builder.intConst(lhs_scalar_llvm_ty, -1)).toLlvm(&o.builder);
8147 if (rhs_ty.zigTypeTag(mod) == .Vector) {
8148 const vec_len = rhs_ty.vectorLen(mod);
8149 const bits_vec = self.builder.buildVectorSplat(vec_len, bits, "");
8150 const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, "");
8151 const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, "");
8152 return self.builder.buildSelect(in_range, result, lhs_max_vec, "");
8153 } else {
8154 const in_range = self.builder.buildICmp(.ULT, rhs, bits, "");
8155 return self.builder.buildSelect(in_range, result, lhs_max, "");
8156 }
8100 const lhs_llvm_ty = try o.lowerType(lhs_ty);
8101 const lhs_scalar_llvm_ty = lhs_llvm_ty.scalarType(&o.builder);
8102 const bits = try o.builder.splatValue(
8103 lhs_llvm_ty,
8104 try o.builder.intConst(lhs_scalar_llvm_ty, lhs_bits),
8105 );
8106 const lhs_max = try o.builder.splatValue(
8107 lhs_llvm_ty,
8108 try o.builder.intConst(lhs_scalar_llvm_ty, -1),
8109 );
8110 const in_range = try self.wip.icmp(.ult, rhs, bits, "");
8111 return self.wip.select(in_range, result, lhs_max, "");
81578112 }
81588113
8159 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*llvm.Value {
8114 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !Builder.Value {
81608115 const o = self.dg.object;
81618116 const mod = o.module;
81628117 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -8165,63 +8120,41 @@ pub const FuncGen = struct {
81658120 const rhs = try self.resolveInst(bin_op.rhs);
81668121
81678122 const lhs_ty = self.typeOf(bin_op.lhs);
8168 const rhs_ty = self.typeOf(bin_op.rhs);
81698123 const lhs_scalar_ty = lhs_ty.scalarType(mod);
8170 const rhs_scalar_ty = rhs_ty.scalarType(mod);
81718124
8172 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod))
8173 self.builder.buildZExt(rhs, (try o.lowerType(lhs_ty)).toLlvm(&o.builder), "")
8174 else
8175 rhs;
8125 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
81768126 const is_signed_int = lhs_scalar_ty.isSignedInt(mod);
81778127
8178 if (is_exact) {
8179 if (is_signed_int) {
8180 return self.builder.buildAShrExact(lhs, casted_rhs, "");
8181 } else {
8182 return self.builder.buildLShrExact(lhs, casted_rhs, "");
8183 }
8184 } else {
8185 if (is_signed_int) {
8186 return self.builder.buildAShr(lhs, casted_rhs, "");
8187 } else {
8188 return self.builder.buildLShr(lhs, casted_rhs, "");
8189 }
8190 }
8128 return self.wip.bin(if (is_exact)
8129 if (is_signed_int) .@"ashr exact" else .@"lshr exact"
8130 else if (is_signed_int) .ashr else .lshr, lhs, casted_rhs, "");
81918131 }
81928132
8193 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8133 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
81948134 const o = self.dg.object;
81958135 const mod = o.module;
81968136 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
81978137 const dest_ty = self.typeOfIndex(inst);
8198 const dest_info = dest_ty.intInfo(mod);
8199 const dest_llvm_ty = (try o.lowerType(dest_ty)).toLlvm(&o.builder);
8138 const dest_llvm_ty = try o.lowerType(dest_ty);
82008139 const operand = try self.resolveInst(ty_op.operand);
82018140 const operand_ty = self.typeOf(ty_op.operand);
82028141 const operand_info = operand_ty.intInfo(mod);
82038142
8204 if (operand_info.bits < dest_info.bits) {
8205 switch (operand_info.signedness) {
8206 .signed => return self.builder.buildSExt(operand, dest_llvm_ty, ""),
8207 .unsigned => return self.builder.buildZExt(operand, dest_llvm_ty, ""),
8208 }
8209 } else if (operand_info.bits > dest_info.bits) {
8210 return self.builder.buildTrunc(operand, dest_llvm_ty, "");
8211 } else {
8212 return operand;
8213 }
8143 return self.wip.conv(switch (operand_info.signedness) {
8144 .signed => .signed,
8145 .unsigned => .unsigned,
8146 }, operand, dest_llvm_ty, "");
82148147 }
82158148
8216 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8149 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
82178150 const o = self.dg.object;
82188151 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
82198152 const operand = try self.resolveInst(ty_op.operand);
8220 const dest_llvm_ty = (try o.lowerType(self.typeOfIndex(inst))).toLlvm(&o.builder);
8221 return self.builder.buildTrunc(operand, dest_llvm_ty, "");
8153 const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
8154 return self.wip.cast(.trunc, operand, dest_llvm_ty, "");
82228155 }
82238156
8224 fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8157 fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
82258158 const o = self.dg.object;
82268159 const mod = o.module;
82278160 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -8233,8 +8166,7 @@ pub const FuncGen = struct {
82338166 const src_bits = operand_ty.floatBits(target);
82348167
82358168 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
8236 const dest_llvm_ty = (try o.lowerType(dest_ty)).toLlvm(&o.builder);
8237 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
8169 return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty), "");
82388170 } else {
82398171 const operand_llvm_ty = try o.lowerType(operand_ty);
82408172 const dest_llvm_ty = try o.lowerType(dest_ty);
......@@ -8243,14 +8175,21 @@ pub const FuncGen = struct {
82438175 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
82448176 });
82458177
8246 const params = [1]*llvm.Value{operand};
82478178 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8248
8249 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
8179 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
8180 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
8181 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
8182 llvm_fn.toLlvm(&o.builder),
8183 &params,
8184 params.len,
8185 .C,
8186 .Auto,
8187 "",
8188 ), &self.wip);
82508189 }
82518190 }
82528191
8253 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8192 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
82548193 const o = self.dg.object;
82558194 const mod = o.module;
82568195 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -8262,8 +8201,7 @@ pub const FuncGen = struct {
82628201 const src_bits = operand_ty.floatBits(target);
82638202
82648203 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
8265 const dest_llvm_ty = (try o.lowerType(dest_ty)).toLlvm(&o.builder);
8266 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
8204 return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty), "");
82678205 } else {
82688206 const operand_llvm_ty = try o.lowerType(operand_ty);
82698207 const dest_llvm_ty = try o.lowerType(dest_ty);
......@@ -8272,24 +8210,31 @@ pub const FuncGen = struct {
82728210 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
82738211 });
82748212
8275 const params = [1]*llvm.Value{operand};
82768213 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
8277
8278 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
8214 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
8215 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
8216 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
8217 llvm_fn.toLlvm(&o.builder),
8218 &params,
8219 params.len,
8220 .C,
8221 .Auto,
8222 "",
8223 ), &self.wip);
82798224 }
82808225 }
82818226
8282 fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8227 fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
82838228 const o = self.dg.object;
82848229 const un_op = self.air.instructions.items(.data)[inst].un_op;
82858230 const operand = try self.resolveInst(un_op);
82868231 const ptr_ty = self.typeOf(un_op);
8287 const operand_ptr = self.sliceOrArrayPtr(operand, ptr_ty);
8288 const dest_llvm_ty = (try o.lowerType(self.typeOfIndex(inst))).toLlvm(&o.builder);
8289 return self.builder.buildPtrToInt(operand_ptr, dest_llvm_ty, "");
8232 const operand_ptr = try self.sliceOrArrayPtr(operand, ptr_ty);
8233 const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
8234 return self.wip.cast(.ptrtoint, operand_ptr, dest_llvm_ty, "");
82908235 }
82918236
8292 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !*llvm.Value {
8237 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
82938238 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
82948239 const operand_ty = self.typeOf(ty_op.operand);
82958240 const inst_ty = self.typeOfIndex(inst);
......@@ -8297,26 +8242,26 @@ pub const FuncGen = struct {
82978242 return self.bitCast(operand, operand_ty, inst_ty);
82988243 }
82998244
8300 fn bitCast(self: *FuncGen, operand: *llvm.Value, operand_ty: Type, inst_ty: Type) !*llvm.Value {
8245 fn bitCast(self: *FuncGen, operand: Builder.Value, operand_ty: Type, inst_ty: Type) !Builder.Value {
83018246 const o = self.dg.object;
83028247 const mod = o.module;
83038248 const operand_is_ref = isByRef(operand_ty, mod);
83048249 const result_is_ref = isByRef(inst_ty, mod);
8305 const llvm_dest_ty = (try o.lowerType(inst_ty)).toLlvm(&o.builder);
8250 const llvm_dest_ty = try o.lowerType(inst_ty);
83068251
83078252 if (operand_is_ref and result_is_ref) {
83088253 // They are both pointers, so just return the same opaque pointer :)
83098254 return operand;
83108255 }
83118256
8312 if (llvm_dest_ty.getTypeKind() == .Integer and
8313 operand.typeOf().getTypeKind() == .Integer)
8257 if (llvm_dest_ty.isInteger(&o.builder) and
8258 operand.typeOfWip(&self.wip).isInteger(&o.builder))
83148259 {
8315 return self.builder.buildZExtOrBitCast(operand, llvm_dest_ty, "");
8260 return self.wip.conv(.unsigned, operand, llvm_dest_ty, "");
83168261 }
83178262
83188263 if (operand_ty.zigTypeTag(mod) == .Int and inst_ty.isPtrAtRuntime(mod)) {
8319 return self.builder.buildIntToPtr(operand, llvm_dest_ty, "");
8264 return self.wip.cast(.inttoptr, operand, llvm_dest_ty, "");
83208265 }
83218266
83228267 if (operand_ty.zigTypeTag(mod) == .Vector and inst_ty.zigTypeTag(mod) == .Array) {
......@@ -8324,108 +8269,97 @@ pub const FuncGen = struct {
83248269 if (!result_is_ref) {
83258270 return self.dg.todo("implement bitcast vector to non-ref array", .{});
83268271 }
8327 const array_ptr = try self.buildAlloca(llvm_dest_ty, null);
8272 const array_ptr = try self.buildAlloca(llvm_dest_ty, .default);
83288273 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
83298274 if (bitcast_ok) {
8330 const llvm_store = self.builder.buildStore(operand, array_ptr);
8331 llvm_store.setAlignment(inst_ty.abiAlignment(mod));
8275 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8276 _ = try self.wip.store(.normal, operand, array_ptr, alignment);
83328277 } else {
83338278 // If the ABI size of the element type is not evenly divisible by size in bits;
83348279 // a simple bitcast will not work, and we fall back to extractelement.
83358280 const llvm_usize = try o.lowerType(Type.usize);
8336 const zero = try o.builder.intConst(llvm_usize, 0);
8281 const usize_zero = try o.builder.intValue(llvm_usize, 0);
83378282 const vector_len = operand_ty.arrayLen(mod);
83388283 var i: u64 = 0;
83398284 while (i < vector_len) : (i += 1) {
8340 const index_usize = try o.builder.intConst(llvm_usize, i);
8341 const index_u32 = try o.builder.intConst(.i32, i);
8342 const indexes: [2]*llvm.Value = .{
8343 zero.toLlvm(&o.builder),
8344 index_usize.toLlvm(&o.builder),
8345 };
8346 const elem_ptr = self.builder.buildInBoundsGEP(llvm_dest_ty, array_ptr, &indexes, indexes.len, "");
8347 const elem = self.builder.buildExtractElement(operand, index_u32.toLlvm(&o.builder), "");
8348 _ = self.builder.buildStore(elem, elem_ptr);
8285 const elem_ptr = try self.wip.gep(.inbounds, llvm_dest_ty, array_ptr, &.{
8286 usize_zero, try o.builder.intValue(llvm_usize, i),
8287 }, "");
8288 const elem =
8289 try self.wip.extractElement(operand, try o.builder.intValue(.i32, i), "");
8290 _ = try self.wip.store(.normal, elem, elem_ptr, .default);
83498291 }
83508292 }
83518293 return array_ptr;
83528294 } else if (operand_ty.zigTypeTag(mod) == .Array and inst_ty.zigTypeTag(mod) == .Vector) {
83538295 const elem_ty = operand_ty.childType(mod);
8354 const llvm_vector_ty = (try o.lowerType(inst_ty)).toLlvm(&o.builder);
8355 if (!operand_is_ref) {
8356 return self.dg.todo("implement bitcast non-ref array to vector", .{});
8357 }
8296 const llvm_vector_ty = try o.lowerType(inst_ty);
8297 if (!operand_is_ref) return self.dg.todo("implement bitcast non-ref array to vector", .{});
83588298
83598299 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
83608300 if (bitcast_ok) {
8361 const vector = self.builder.buildLoad(llvm_vector_ty, operand, "");
83628301 // The array is aligned to the element's alignment, while the vector might have a completely
83638302 // different alignment. This means we need to enforce the alignment of this load.
8364 vector.setAlignment(elem_ty.abiAlignment(mod));
8365 return vector;
8303 const alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
8304 return self.wip.load(.normal, llvm_vector_ty, operand, alignment, "");
83668305 } else {
83678306 // If the ABI size of the element type is not evenly divisible by size in bits;
83688307 // a simple bitcast will not work, and we fall back to extractelement.
8369 const array_llvm_ty = (try o.lowerType(operand_ty)).toLlvm(&o.builder);
8370 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
8308 const array_llvm_ty = try o.lowerType(operand_ty);
8309 const elem_llvm_ty = try o.lowerType(elem_ty);
83718310 const llvm_usize = try o.lowerType(Type.usize);
8372 const zero = try o.builder.intConst(llvm_usize, 0);
8311 const usize_zero = try o.builder.intValue(llvm_usize, 0);
83738312 const vector_len = operand_ty.arrayLen(mod);
8374 var vector = llvm_vector_ty.getUndef();
8313 var vector = try o.builder.poisonValue(llvm_vector_ty);
83758314 var i: u64 = 0;
83768315 while (i < vector_len) : (i += 1) {
8377 const index_usize = try o.builder.intConst(llvm_usize, i);
8378 const index_u32 = try o.builder.intConst(.i32, i);
8379 const indexes: [2]*llvm.Value = .{
8380 zero.toLlvm(&o.builder),
8381 index_usize.toLlvm(&o.builder),
8382 };
8383 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, operand, &indexes, indexes.len, "");
8384 const elem = self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");
8385 vector = self.builder.buildInsertElement(vector, elem, index_u32.toLlvm(&o.builder), "");
8316 const elem_ptr = try self.wip.gep(.inbounds, array_llvm_ty, operand, &.{
8317 usize_zero, try o.builder.intValue(llvm_usize, i),
8318 }, "");
8319 const elem = try self.wip.load(.normal, elem_llvm_ty, elem_ptr, .default, "");
8320 vector =
8321 try self.wip.insertElement(vector, elem, try o.builder.intValue(.i32, i), "");
83868322 }
8387
83888323 return vector;
83898324 }
83908325 }
83918326
83928327 if (operand_is_ref) {
8393 const load_inst = self.builder.buildLoad(llvm_dest_ty, operand, "");
8394 load_inst.setAlignment(operand_ty.abiAlignment(mod));
8395 return load_inst;
8328 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
8329 return self.wip.load(.normal, llvm_dest_ty, operand, alignment, "");
83968330 }
83978331
83988332 if (result_is_ref) {
8399 const alignment = @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod));
8333 const alignment = Builder.Alignment.fromByteUnits(
8334 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8335 );
84008336 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8401 const store_inst = self.builder.buildStore(operand, result_ptr);
8402 store_inst.setAlignment(alignment);
8337 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
84038338 return result_ptr;
84048339 }
84058340
8406 if (llvm_dest_ty.getTypeKind() == .Struct) {
8341 if (llvm_dest_ty.isStruct(&o.builder)) {
84078342 // Both our operand and our result are values, not pointers,
84088343 // but LLVM won't let us bitcast struct values.
84098344 // Therefore, we store operand to alloca, then load for result.
8410 const alignment = @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod));
8345 const alignment = Builder.Alignment.fromByteUnits(
8346 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8347 );
84118348 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8412 const store_inst = self.builder.buildStore(operand, result_ptr);
8413 store_inst.setAlignment(alignment);
8414 const load_inst = self.builder.buildLoad(llvm_dest_ty, result_ptr, "");
8415 load_inst.setAlignment(alignment);
8416 return load_inst;
8349 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
8350 return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, "");
84178351 }
84188352
8419 return self.builder.buildBitCast(operand, llvm_dest_ty, "");
8353 return self.wip.cast(.bitcast, operand, llvm_dest_ty, "");
84208354 }
84218355
8422 fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8356 fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
84238357 const un_op = self.air.instructions.items(.data)[inst].un_op;
84248358 const operand = try self.resolveInst(un_op);
84258359 return operand;
84268360 }
84278361
8428 fn airArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8362 fn airArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
84298363 const o = self.dg.object;
84308364 const mod = o.module;
84318365 const arg_val = self.args[self.arg_index];
......@@ -8433,9 +8367,7 @@ pub const FuncGen = struct {
84338367
84348368 const inst_ty = self.typeOfIndex(inst);
84358369 if (o.di_builder) |dib| {
8436 if (needDbgVarWorkaround(o)) {
8437 return arg_val;
8438 }
8370 if (needDbgVarWorkaround(o)) return arg_val;
84398371
84408372 const src_index = self.air.instructions.items(.data)[inst].arg.src_index;
84418373 const func_index = self.dg.decl.getOwnedFunctionIndex();
......@@ -8450,62 +8382,64 @@ pub const FuncGen = struct {
84508382 try o.lowerDebugType(inst_ty, .full),
84518383 true, // always preserve
84528384 0, // flags
8453 self.arg_index, // includes +1 because 0 is return type
8385 @intCast(self.arg_index), // includes +1 because 0 is return type
84548386 );
84558387
84568388 const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);
8457 const insert_block = self.builder.getInsertBlock();
8389 const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
84588390 if (isByRef(inst_ty, mod)) {
8459 _ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block);
8391 _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
84608392 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
8461 const alignment = inst_ty.abiAlignment(mod);
8462 const alloca = try self.buildAlloca(arg_val.typeOf(), alignment);
8463 const store_inst = self.builder.buildStore(arg_val, alloca);
8464 store_inst.setAlignment(alignment);
8465 _ = dib.insertDeclareAtEnd(alloca, di_local_var, debug_loc, insert_block);
8393 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8394 const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
8395 _ = try self.wip.store(.normal, arg_val, alloca, alignment);
8396 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
84668397 } else {
8467 _ = dib.insertDbgValueIntrinsicAtEnd(arg_val, di_local_var, debug_loc, insert_block);
8398 _ = dib.insertDbgValueIntrinsicAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
84688399 }
84698400 }
84708401
84718402 return arg_val;
84728403 }
84738404
8474 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8405 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
84758406 const o = self.dg.object;
84768407 const mod = o.module;
84778408 const ptr_ty = self.typeOfIndex(inst);
84788409 const pointee_type = ptr_ty.childType(mod);
84798410 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod))
8480 return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder);
8411 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
84818412
8482 const pointee_llvm_ty = (try o.lowerType(pointee_type)).toLlvm(&o.builder);
8483 const alignment = ptr_ty.ptrAlignment(mod);
8413 const pointee_llvm_ty = try o.lowerType(pointee_type);
8414 const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
84848415 return self.buildAlloca(pointee_llvm_ty, alignment);
84858416 }
84868417
8487 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8418 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
84888419 const o = self.dg.object;
84898420 const mod = o.module;
84908421 const ptr_ty = self.typeOfIndex(inst);
84918422 const ret_ty = ptr_ty.childType(mod);
84928423 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod))
8493 return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder);
8494 if (self.ret_ptr) |ret_ptr| return ret_ptr;
8495 const ret_llvm_ty = (try o.lowerType(ret_ty)).toLlvm(&o.builder);
8496 return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(mod));
8424 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
8425 if (self.ret_ptr != .none) return self.ret_ptr;
8426 const ret_llvm_ty = try o.lowerType(ret_ty);
8427 const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8428 return self.buildAlloca(ret_llvm_ty, alignment);
84978429 }
84988430
84998431 /// Use this instead of builder.buildAlloca, because this function makes sure to
85008432 /// put the alloca instruction at the top of the function!
8501 fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type, alignment: ?c_uint) Allocator.Error!*llvm.Value {
8502 const o = self.dg.object;
8503 const mod = o.module;
8504 const target = mod.getTarget();
8505 return o.buildAllocaInner(&self.wip, self.builder, self.llvm_func, self.di_scope != null, llvm_ty, alignment, target);
8433 fn buildAlloca(
8434 self: *FuncGen,
8435 llvm_ty: Builder.Type,
8436 alignment: Builder.Alignment,
8437 ) Allocator.Error!Builder.Value {
8438 const target = self.dg.object.module.getTarget();
8439 return buildAllocaInner(&self.wip, self.di_scope != null, llvm_ty, alignment, target);
85068440 }
85078441
8508 fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value {
8442 fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !Builder.Value {
85098443 const o = self.dg.object;
85108444 const mod = o.module;
85118445 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -8519,23 +8453,29 @@ pub const FuncGen = struct {
85198453 // extra information to LLVM. However, safety makes the difference between using
85208454 // 0xaa or actual undefined for the fill byte.
85218455 const fill_byte = if (safety)
8522 (try o.builder.intConst(.i8, 0xaa)).toLlvm(&o.builder)
8456 try o.builder.intConst(.i8, 0xaa)
85238457 else
8524 Builder.Type.i8.toLlvm(&o.builder).getUndef();
8458 try o.builder.undefConst(.i8);
85258459 const operand_size = operand_ty.abiSize(mod);
85268460 const usize_ty = try o.lowerType(Type.usize);
8527 const len = (try o.builder.intConst(usize_ty, operand_size)).toLlvm(&o.builder);
8528 const dest_ptr_align = ptr_ty.ptrAlignment(mod);
8529 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr(mod));
8461 const len = try o.builder.intValue(usize_ty, operand_size);
8462 const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8463 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
8464 dest_ptr.toLlvm(&self.wip),
8465 fill_byte.toLlvm(&o.builder),
8466 len.toLlvm(&self.wip),
8467 @intCast(dest_ptr_align.toByteUnits() orelse 0),
8468 ptr_ty.isVolatilePtr(mod),
8469 ), &self.wip);
85308470 if (safety and mod.comp.bin_file.options.valgrind) {
85318471 try self.valgrindMarkUndef(dest_ptr, len);
85328472 }
8533 return null;
8473 return .none;
85348474 }
85358475
85368476 const src_operand = try self.resolveInst(bin_op.rhs);
8537 try self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic);
8538 return null;
8477 try self.store(dest_ptr, ptr_ty, src_operand, .none);
8478 return .none;
85398479 }
85408480
85418481 /// As an optimization, we want to avoid unnecessary copies of isByRef=true
......@@ -8560,7 +8500,7 @@ pub const FuncGen = struct {
85608500 return false;
85618501 }
85628502
8563 fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
8503 fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
85648504 const o = fg.dg.object;
85658505 const mod = o.module;
85668506 const inst = body_tail[0];
......@@ -8577,22 +8517,40 @@ pub const FuncGen = struct {
85778517 return fg.load(ptr, ptr_ty);
85788518 }
85798519
8580 fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8520 fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
85818521 _ = inst;
8522 const o = self.dg.object;
85828523 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});
8583 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .Cold, .Auto, "");
8584 _ = self.builder.buildUnreachable();
8585 return null;
8524 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8525 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
8526 llvm_fn,
8527 undefined,
8528 0,
8529 .Cold,
8530 .Auto,
8531 "",
8532 ), &self.wip);
8533 _ = try self.wip.@"unreachable"();
8534 return .none;
85868535 }
85878536
8588 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8537 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
85898538 _ = inst;
8539 const o = self.dg.object;
85908540 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});
8591 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .C, .Auto, "");
8592 return null;
8541 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8542 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
8543 llvm_fn,
8544 undefined,
8545 0,
8546 .C,
8547 .Auto,
8548 "",
8549 ), &self.wip);
8550 return .none;
85938551 }
85948552
8595 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8553 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
85968554 _ = inst;
85978555 const o = self.dg.object;
85988556 const mod = o.module;
......@@ -8600,18 +8558,26 @@ pub const FuncGen = struct {
86008558 const target = mod.getTarget();
86018559 if (!target_util.supportsReturnAddress(target)) {
86028560 // https://github.com/ziglang/zig/issues/11946
8603 return (try o.builder.intConst(llvm_usize, 0)).toLlvm(&o.builder);
8561 return o.builder.intValue(llvm_usize, 0);
86048562 }
86058563
86068564 const llvm_fn = try self.getIntrinsic("llvm.returnaddress", &.{});
86078565 const params = [_]*llvm.Value{
86088566 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
86098567 };
8610 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
8611 return self.builder.buildPtrToInt(ptr_val, llvm_usize.toLlvm(&o.builder), "");
8568 const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCall(
8569 (try o.builder.fnType(.ptr, &.{.i32}, .normal)).toLlvm(&o.builder),
8570 llvm_fn,
8571 &params,
8572 params.len,
8573 .Fast,
8574 .Auto,
8575 "",
8576 ), &self.wip);
8577 return self.wip.cast(.ptrtoint, ptr_val, llvm_usize, "");
86128578 }
86138579
8614 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8580 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
86158581 _ = inst;
86168582 const o = self.dg.object;
86178583 const llvm_fn_name = "llvm.frameaddress.p0";
......@@ -8619,24 +8585,34 @@ pub const FuncGen = struct {
86198585 const fn_type = try o.builder.fnType(.ptr, &.{.i32}, .normal);
86208586 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));
86218587 };
8588 const llvm_fn_ty = try o.builder.fnType(.ptr, &.{.i32}, .normal);
86228589
86238590 const params = [_]*llvm.Value{
86248591 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
86258592 };
8626 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
8627 const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder);
8628 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
8593 const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
8594 self.builder.buildCall(
8595 llvm_fn_ty.toLlvm(&o.builder),
8596 llvm_fn,
8597 &params,
8598 params.len,
8599 .Fast,
8600 .Auto,
8601 "",
8602 ),
8603 &self.wip,
8604 );
8605 return self.wip.cast(.ptrtoint, ptr_val, try o.lowerType(Type.usize), "");
86298606 }
86308607
8631 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8608 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
86328609 const atomic_order = self.air.instructions.items(.data)[inst].fence;
8633 const llvm_memory_order = toLlvmAtomicOrdering(atomic_order);
8634 const single_threaded = llvm.Bool.fromBool(self.single_threaded);
8635 _ = self.builder.buildFence(llvm_memory_order, single_threaded, "");
8636 return null;
8610 const ordering = toLlvmAtomicOrdering(atomic_order);
8611 _ = try self.wip.fence(self.sync_scope, ordering);
8612 return .none;
86378613 }
86388614
8639 fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !?*llvm.Value {
8615 fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !Builder.Value {
86408616 const o = self.dg.object;
86418617 const mod = o.module;
86428618 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -8645,47 +8621,51 @@ pub const FuncGen = struct {
86458621 var expected_value = try self.resolveInst(extra.expected_value);
86468622 var new_value = try self.resolveInst(extra.new_value);
86478623 const operand_ty = self.typeOf(extra.ptr).childType(mod);
8648 const abi_ty = try o.getAtomicAbiType(operand_ty, false);
8649 if (abi_ty != .none) {
8650 const llvm_abi_ty = abi_ty.toLlvm(&o.builder);
8624 const llvm_operand_ty = try o.lowerType(operand_ty);
8625 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, false);
8626 if (llvm_abi_ty != .none) {
86518627 // operand needs widening and truncating
8652 if (operand_ty.isSignedInt(mod)) {
8653 expected_value = self.builder.buildSExt(expected_value, llvm_abi_ty, "");
8654 new_value = self.builder.buildSExt(new_value, llvm_abi_ty, "");
8655 } else {
8656 expected_value = self.builder.buildZExt(expected_value, llvm_abi_ty, "");
8657 new_value = self.builder.buildZExt(new_value, llvm_abi_ty, "");
8658 }
8628 const signedness: Builder.Function.Instruction.Cast.Signedness =
8629 if (operand_ty.isSignedInt(mod)) .signed else .unsigned;
8630 expected_value = try self.wip.conv(signedness, expected_value, llvm_abi_ty, "");
8631 new_value = try self.wip.conv(signedness, new_value, llvm_abi_ty, "");
86598632 }
8660 const result = self.builder.buildAtomicCmpXchg(
8661 ptr,
8662 expected_value,
8663 new_value,
8664 toLlvmAtomicOrdering(extra.successOrder()),
8665 toLlvmAtomicOrdering(extra.failureOrder()),
8666 llvm.Bool.fromBool(self.single_threaded),
8633
8634 const llvm_result_ty = try o.builder.structType(.normal, &.{
8635 if (llvm_abi_ty != .none) llvm_abi_ty else llvm_operand_ty,
8636 .i1,
8637 });
8638 const result = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
8639 self.builder.buildAtomicCmpXchg(
8640 ptr.toLlvm(&self.wip),
8641 expected_value.toLlvm(&self.wip),
8642 new_value.toLlvm(&self.wip),
8643 @enumFromInt(@intFromEnum(toLlvmAtomicOrdering(extra.successOrder()))),
8644 @enumFromInt(@intFromEnum(toLlvmAtomicOrdering(extra.failureOrder()))),
8645 llvm.Bool.fromBool(self.sync_scope == .singlethread),
8646 ),
8647 &self.wip,
86678648 );
8668 result.setWeak(llvm.Bool.fromBool(is_weak));
8649 result.toLlvm(&self.wip).setWeak(llvm.Bool.fromBool(is_weak));
86698650
86708651 const optional_ty = self.typeOfIndex(inst);
86718652
8672 var payload = self.builder.buildExtractValue(result, 0, "");
8673 if (abi_ty != .none) {
8674 payload = self.builder.buildTrunc(payload, (try o.lowerType(operand_ty)).toLlvm(&o.builder), "");
8675 }
8676 const success_bit = self.builder.buildExtractValue(result, 1, "");
8653 var payload = try self.wip.extractValue(result, &.{0}, "");
8654 if (llvm_abi_ty != .none) payload = try self.wip.cast(.trunc, payload, llvm_operand_ty, "");
8655 const success_bit = try self.wip.extractValue(result, &.{1}, "");
86778656
86788657 if (optional_ty.optionalReprIsPayload(mod)) {
8679 return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, "");
8658 const zero = try o.builder.zeroInitValue(payload.typeOfWip(&self.wip));
8659 return self.wip.select(success_bit, zero, payload, "");
86808660 }
86818661
86828662 comptime assert(optional_layout_version == 3);
86838663
8684 const non_null_bit = self.builder.buildNot(success_bit, "");
8664 const non_null_bit = try self.wip.not(success_bit, "");
86858665 return buildOptional(self, optional_ty, payload, non_null_bit);
86868666 }
86878667
8688 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8668 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
86898669 const o = self.dg.object;
86908670 const mod = o.module;
86918671 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
......@@ -8698,121 +8678,146 @@ pub const FuncGen = struct {
86988678 const is_float = operand_ty.isRuntimeFloat();
86998679 const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float);
87008680 const ordering = toLlvmAtomicOrdering(extra.ordering());
8701 const single_threaded = llvm.Bool.fromBool(self.single_threaded);
8702 const abi_ty = try o.getAtomicAbiType(operand_ty, op == .Xchg);
8703 if (abi_ty != .none) {
8704 const llvm_abi_ty = abi_ty.toLlvm(&o.builder);
8681 const single_threaded = llvm.Bool.fromBool(self.sync_scope == .singlethread);
8682 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, op == .Xchg);
8683 const llvm_operand_ty = try o.lowerType(operand_ty);
8684 if (llvm_abi_ty != .none) {
87058685 // operand needs widening and truncating or bitcasting.
8706 const casted_operand = if (is_float)
8707 self.builder.buildBitCast(operand, llvm_abi_ty, "")
8708 else if (is_signed_int)
8709 self.builder.buildSExt(operand, llvm_abi_ty, "")
8710 else
8711 self.builder.buildZExt(operand, llvm_abi_ty, "");
8686 const casted_operand = try self.wip.cast(
8687 if (is_float) .bitcast else if (is_signed_int) .sext else .zext,
8688 @enumFromInt(@intFromEnum(operand)),
8689 llvm_abi_ty,
8690 "",
8691 );
87128692
8713 const uncasted_result = self.builder.buildAtomicRmw(
8714 op,
8715 ptr,
8716 casted_operand,
8717 ordering,
8718 single_threaded,
8693 const uncasted_result = (try self.wip.unimplemented(llvm_abi_ty, "")).finish(
8694 self.builder.buildAtomicRmw(
8695 op,
8696 ptr.toLlvm(&self.wip),
8697 casted_operand.toLlvm(&self.wip),
8698 @enumFromInt(@intFromEnum(ordering)),
8699 single_threaded,
8700 ),
8701 &self.wip,
87198702 );
8720 const operand_llvm_ty = (try o.lowerType(operand_ty)).toLlvm(&o.builder);
8703
87218704 if (is_float) {
8722 return self.builder.buildBitCast(uncasted_result, operand_llvm_ty, "");
8705 return self.wip.cast(.bitcast, uncasted_result, llvm_operand_ty, "");
87238706 } else {
8724 return self.builder.buildTrunc(uncasted_result, operand_llvm_ty, "");
8707 return self.wip.cast(.trunc, uncasted_result, llvm_operand_ty, "");
87258708 }
87268709 }
87278710
8728 if (operand.typeOf().getTypeKind() != .Pointer) {
8729 return self.builder.buildAtomicRmw(op, ptr, operand, ordering, single_threaded);
8711 if (!llvm_operand_ty.isPointer(&o.builder)) {
8712 return (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
8713 self.builder.buildAtomicRmw(
8714 op,
8715 ptr.toLlvm(&self.wip),
8716 operand.toLlvm(&self.wip),
8717 @enumFromInt(@intFromEnum(ordering)),
8718 single_threaded,
8719 ),
8720 &self.wip,
8721 );
87308722 }
87318723
87328724 // It's a pointer but we need to treat it as an int.
8733 const usize_llvm_ty = (try o.lowerType(Type.usize)).toLlvm(&o.builder);
8734 const casted_operand = self.builder.buildPtrToInt(operand, usize_llvm_ty, "");
8735 const uncasted_result = self.builder.buildAtomicRmw(
8736 op,
8737 ptr,
8738 casted_operand,
8739 ordering,
8740 single_threaded,
8725 const llvm_usize = try o.lowerType(Type.usize);
8726 const casted_operand = try self.wip.cast(.ptrtoint, operand, llvm_usize, "");
8727 const uncasted_result = (try self.wip.unimplemented(llvm_usize, "")).finish(
8728 self.builder.buildAtomicRmw(
8729 op,
8730 ptr.toLlvm(&self.wip),
8731 casted_operand.toLlvm(&self.wip),
8732 @enumFromInt(@intFromEnum(ordering)),
8733 single_threaded,
8734 ),
8735 &self.wip,
87418736 );
8742 const operand_llvm_ty = (try o.lowerType(operand_ty)).toLlvm(&o.builder);
8743 return self.builder.buildIntToPtr(uncasted_result, operand_llvm_ty, "");
8737 return self.wip.cast(.inttoptr, uncasted_result, llvm_operand_ty, "");
87448738 }
87458739
8746 fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8740 fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
87478741 const o = self.dg.object;
87488742 const mod = o.module;
87498743 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
87508744 const ptr = try self.resolveInst(atomic_load.ptr);
87518745 const ptr_ty = self.typeOf(atomic_load.ptr);
8752 const ptr_info = ptr_ty.ptrInfo(mod);
8753 const elem_ty = ptr_info.child.toType();
8754 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod))
8755 return null;
8746 const info = ptr_ty.ptrInfo(mod);
8747 const elem_ty = info.child.toType();
8748 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
87568749 const ordering = toLlvmAtomicOrdering(atomic_load.order);
8757 const abi_ty = try o.getAtomicAbiType(elem_ty, false);
8758 const ptr_alignment: u32 = @intCast(ptr_info.flags.alignment.toByteUnitsOptional() orelse
8759 ptr_info.child.toType().abiAlignment(mod));
8760 const ptr_volatile = llvm.Bool.fromBool(ptr_info.flags.is_volatile);
8761 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
8762
8763 if (abi_ty != .none) {
8764 const llvm_abi_ty = abi_ty.toLlvm(&o.builder);
8750 const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false);
8751 const ptr_alignment = Builder.Alignment.fromByteUnits(
8752 info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod),
8753 );
8754 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
8755 false => .normal,
8756 true => .@"volatile",
8757 };
8758 const elem_llvm_ty = try o.lowerType(elem_ty);
8759
8760 if (llvm_abi_ty != .none) {
87658761 // operand needs widening and truncating
8766 const load_inst = self.builder.buildLoad(llvm_abi_ty, ptr, "");
8767 load_inst.setAlignment(ptr_alignment);
8768 load_inst.setVolatile(ptr_volatile);
8769 load_inst.setOrdering(ordering);
8770 return self.builder.buildTrunc(load_inst, elem_llvm_ty, "");
8762 const loaded = try self.wip.loadAtomic(
8763 ptr_kind,
8764 llvm_abi_ty,
8765 ptr,
8766 self.sync_scope,
8767 ordering,
8768 ptr_alignment,
8769 "",
8770 );
8771 return self.wip.cast(.trunc, loaded, elem_llvm_ty, "");
87718772 }
8772 const load_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");
8773 load_inst.setAlignment(ptr_alignment);
8774 load_inst.setVolatile(ptr_volatile);
8775 load_inst.setOrdering(ordering);
8776 return load_inst;
8773 return self.wip.loadAtomic(
8774 ptr_kind,
8775 elem_llvm_ty,
8776 ptr,
8777 self.sync_scope,
8778 ordering,
8779 ptr_alignment,
8780 "",
8781 );
87778782 }
87788783
87798784 fn airAtomicStore(
87808785 self: *FuncGen,
87818786 inst: Air.Inst.Index,
8782 ordering: llvm.AtomicOrdering,
8783 ) !?*llvm.Value {
8787 ordering: Builder.AtomicOrdering,
8788 ) !Builder.Value {
87848789 const o = self.dg.object;
87858790 const mod = o.module;
87868791 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
87878792 const ptr_ty = self.typeOf(bin_op.lhs);
87888793 const operand_ty = ptr_ty.childType(mod);
8789 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return null;
8794 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return .none;
87908795 const ptr = try self.resolveInst(bin_op.lhs);
87918796 var element = try self.resolveInst(bin_op.rhs);
8792 const abi_ty = try o.getAtomicAbiType(operand_ty, false);
8797 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, false);
87938798
8794 if (abi_ty != .none) {
8795 const llvm_abi_ty = abi_ty.toLlvm(&o.builder);
8799 if (llvm_abi_ty != .none) {
87968800 // operand needs widening
8797 if (operand_ty.isSignedInt(mod)) {
8798 element = self.builder.buildSExt(element, llvm_abi_ty, "");
8799 } else {
8800 element = self.builder.buildZExt(element, llvm_abi_ty, "");
8801 }
8801 element = try self.wip.conv(
8802 if (operand_ty.isSignedInt(mod)) .signed else .unsigned,
8803 element,
8804 llvm_abi_ty,
8805 "",
8806 );
88028807 }
88038808 try self.store(ptr, ptr_ty, element, ordering);
8804 return null;
8809 return .none;
88058810 }
88068811
8807 fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value {
8812 fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !Builder.Value {
88088813 const o = self.dg.object;
88098814 const mod = o.module;
88108815 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
88118816 const dest_slice = try self.resolveInst(bin_op.lhs);
88128817 const ptr_ty = self.typeOf(bin_op.lhs);
88138818 const elem_ty = self.typeOf(bin_op.rhs);
8814 const dest_ptr_align = ptr_ty.ptrAlignment(mod);
8815 const dest_ptr = self.sliceOrArrayPtr(dest_slice, ptr_ty);
8819 const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8820 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty);
88168821 const is_volatile = ptr_ty.isVolatilePtr(mod);
88178822
88188823 // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless
......@@ -8829,20 +8834,26 @@ pub const FuncGen = struct {
88298834 // extra information to LLVM. However, safety makes the difference between using
88308835 // 0xaa or actual undefined for the fill byte.
88318836 const fill_byte = if (safety)
8832 (try o.builder.intConst(.i8, 0xaa)).toLlvm(&o.builder)
8837 try o.builder.intValue(.i8, 0xaa)
88338838 else
8834 Builder.Type.i8.toLlvm(&o.builder).getUndef();
8839 try o.builder.undefValue(.i8);
88358840 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
88368841 if (intrinsic_len0_traps) {
88378842 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
88388843 } else {
8839 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
8844 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
8845 dest_ptr.toLlvm(&self.wip),
8846 fill_byte.toLlvm(&self.wip),
8847 len.toLlvm(&self.wip),
8848 @intCast(dest_ptr_align.toByteUnits() orelse 0),
8849 is_volatile,
8850 ), &self.wip);
88408851 }
88418852
88428853 if (safety and mod.comp.bin_file.options.valgrind) {
88438854 try self.valgrindMarkUndef(dest_ptr, len);
88448855 }
8845 return null;
8856 return .none;
88468857 }
88478858
88488859 // Test if the element value is compile-time known to be a
......@@ -8850,18 +8861,21 @@ pub const FuncGen = struct {
88508861 // repeating byte pattern of 0 bytes. In such case, the memset
88518862 // intrinsic can be used.
88528863 if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| {
8853 const fill_byte = try self.resolveValue(.{
8854 .ty = Type.u8,
8855 .val = byte_val,
8856 });
8864 const fill_byte = try self.resolveValue(.{ .ty = Type.u8, .val = byte_val });
88578865 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
88588866
88598867 if (intrinsic_len0_traps) {
8860 try self.safeWasmMemset(dest_ptr, fill_byte.toLlvm(&o.builder), len, dest_ptr_align, is_volatile);
8868 try self.safeWasmMemset(dest_ptr, fill_byte.toValue(), len, dest_ptr_align, is_volatile);
88618869 } else {
8862 _ = self.builder.buildMemSet(dest_ptr, fill_byte.toLlvm(&o.builder), len, dest_ptr_align, is_volatile);
8870 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
8871 dest_ptr.toLlvm(&self.wip),
8872 fill_byte.toLlvm(&o.builder),
8873 len.toLlvm(&self.wip),
8874 @intCast(dest_ptr_align.toByteUnits() orelse 0),
8875 is_volatile,
8876 ), &self.wip);
88638877 }
8864 return null;
8878 return .none;
88658879 }
88668880 }
88678881
......@@ -8876,9 +8890,15 @@ pub const FuncGen = struct {
88768890 if (intrinsic_len0_traps) {
88778891 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
88788892 } else {
8879 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
8893 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
8894 dest_ptr.toLlvm(&self.wip),
8895 fill_byte.toLlvm(&self.wip),
8896 len.toLlvm(&self.wip),
8897 @intCast(dest_ptr_align.toByteUnits() orelse 0),
8898 is_volatile,
8899 ), &self.wip);
88808900 }
8881 return null;
8901 return .none;
88828902 }
88838903
88848904 // non-byte-sized element. lower with a loop. something like this:
......@@ -8886,96 +8906,92 @@ pub const FuncGen = struct {
88868906 // entry:
88878907 // ...
88888908 // %end_ptr = getelementptr %ptr, %len
8889 // br loop
8909 // br %loop
88908910 // loop:
88918911 // %it_ptr = phi body %next_ptr, entry %ptr
88928912 // %end = cmp eq %it_ptr, %end_ptr
8893 // cond_br %end body, end
8913 // br %end, %body, %end
88948914 // body:
88958915 // store %it_ptr, %value
88968916 // %next_ptr = getelementptr %it_ptr, 1
8897 // br loop
8917 // br %loop
88988918 // end:
88998919 // ...
8900 const entry_block = self.builder.getInsertBlock();
8901 const loop_block = try self.wip.block("InlineMemsetLoop");
8902 const body_block = try self.wip.block("InlineMemsetBody");
8903 const end_block = try self.wip.block("InlineMemsetEnd");
8920 const entry_block = self.wip.cursor.block;
8921 const loop_block = try self.wip.block(2, "InlineMemsetLoop");
8922 const body_block = try self.wip.block(1, "InlineMemsetBody");
8923 const end_block = try self.wip.block(1, "InlineMemsetEnd");
89048924
89058925 const usize_ty = try o.lowerType(Type.usize);
89068926 const len = switch (ptr_ty.ptrSize(mod)) {
8907 .Slice => self.builder.buildExtractValue(dest_slice, 1, ""),
8908 .One => (try o.builder.intConst(usize_ty, ptr_ty.childType(mod).arrayLen(mod))).toLlvm(&o.builder),
8927 .Slice => try self.wip.extractValue(dest_slice, &.{1}, ""),
8928 .One => try o.builder.intValue(usize_ty, ptr_ty.childType(mod).arrayLen(mod)),
89098929 .Many, .C => unreachable,
89108930 };
8911 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
8912 const len_gep = [_]*llvm.Value{len};
8913 const end_ptr = self.builder.buildInBoundsGEP(elem_llvm_ty, dest_ptr, &len_gep, len_gep.len, "");
8914 _ = self.builder.buildBr(loop_block.toLlvm(&self.wip));
8931 const elem_llvm_ty = try o.lowerType(elem_ty);
8932 const end_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, dest_ptr, &.{len}, "");
8933 _ = try self.wip.br(loop_block);
89158934
89168935 self.wip.cursor = .{ .block = loop_block };
8917 self.builder.positionBuilderAtEnd(loop_block.toLlvm(&self.wip));
8918 const it_ptr = self.builder.buildPhi(Builder.Type.ptr.toLlvm(&o.builder), "");
8919 const end = self.builder.buildICmp(.NE, it_ptr, end_ptr, "");
8920 _ = self.builder.buildCondBr(end, body_block.toLlvm(&self.wip), end_block.toLlvm(&self.wip));
8936 const it_ptr = try self.wip.phi(.ptr, "");
8937 const end = try self.wip.icmp(.ne, it_ptr.toValue(), end_ptr, "");
8938 _ = try self.wip.brCond(end, body_block, end_block);
89218939
89228940 self.wip.cursor = .{ .block = body_block };
8923 self.builder.positionBuilderAtEnd(body_block.toLlvm(&self.wip));
89248941 const elem_abi_alignment = elem_ty.abiAlignment(mod);
8925 const it_ptr_alignment = @min(elem_abi_alignment, dest_ptr_align);
8942 const it_ptr_alignment = Builder.Alignment.fromByteUnits(
8943 @min(elem_abi_alignment, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)),
8944 );
89268945 if (isByRef(elem_ty, mod)) {
8927 _ = self.builder.buildMemCpy(
8928 it_ptr,
8929 it_ptr_alignment,
8930 value,
8946 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
8947 it_ptr.toValue().toLlvm(&self.wip),
8948 @intCast(it_ptr_alignment.toByteUnits() orelse 0),
8949 value.toLlvm(&self.wip),
89318950 elem_abi_alignment,
89328951 (try o.builder.intConst(usize_ty, elem_abi_size)).toLlvm(&o.builder),
89338952 is_volatile,
8934 );
8935 } else {
8936 const store_inst = self.builder.buildStore(value, it_ptr);
8937 store_inst.setAlignment(it_ptr_alignment);
8938 store_inst.setVolatile(llvm.Bool.fromBool(is_volatile));
8939 }
8940 const one_gep = [_]*llvm.Value{
8941 (try o.builder.intConst(usize_ty, 1)).toLlvm(&o.builder),
8942 };
8943 const next_ptr = self.builder.buildInBoundsGEP(elem_llvm_ty, it_ptr, &one_gep, one_gep.len, "");
8944 _ = self.builder.buildBr(loop_block.toLlvm(&self.wip));
8953 ), &self.wip);
8954 } else _ = try self.wip.store(switch (is_volatile) {
8955 false => .normal,
8956 true => .@"volatile",
8957 }, value, it_ptr.toValue(), it_ptr_alignment);
8958 const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{
8959 try o.builder.intValue(usize_ty, 1),
8960 }, "");
8961 _ = try self.wip.br(loop_block);
89458962
89468963 self.wip.cursor = .{ .block = end_block };
8947 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));
8948
8949 const incoming_values: [2]*llvm.Value = .{ next_ptr, dest_ptr };
8950 const incoming_blocks: [2]*llvm.BasicBlock = .{ body_block.toLlvm(&self.wip), entry_block };
8951 it_ptr.addIncoming(&incoming_values, &incoming_blocks, 2);
8952
8953 return null;
8964 try it_ptr.finish(&.{ next_ptr, dest_ptr }, &.{ body_block, entry_block }, &self.wip);
8965 return .none;
89548966 }
89558967
89568968 fn safeWasmMemset(
89578969 self: *FuncGen,
8958 dest_ptr: *llvm.Value,
8959 fill_byte: *llvm.Value,
8960 len: *llvm.Value,
8961 dest_ptr_align: u32,
8970 dest_ptr: Builder.Value,
8971 fill_byte: Builder.Value,
8972 len: Builder.Value,
8973 dest_ptr_align: Builder.Alignment,
89628974 is_volatile: bool,
89638975 ) !void {
89648976 const o = self.dg.object;
89658977 const llvm_usize_ty = try o.lowerType(Type.usize);
8966 const cond = try self.cmp(len, (try o.builder.intConst(llvm_usize_ty, 0)).toLlvm(&o.builder), Type.usize, .neq);
8967 const memset_block = try self.wip.block("MemsetTrapSkip");
8968 const end_block = try self.wip.block("MemsetTrapEnd");
8969 _ = self.builder.buildCondBr(cond, memset_block.toLlvm(&self.wip), end_block.toLlvm(&self.wip));
8978 const cond = try self.cmp(len, try o.builder.intValue(llvm_usize_ty, 0), Type.usize, .neq);
8979 const memset_block = try self.wip.block(1, "MemsetTrapSkip");
8980 const end_block = try self.wip.block(2, "MemsetTrapEnd");
8981 _ = try self.wip.brCond(cond, memset_block, end_block);
89708982 self.wip.cursor = .{ .block = memset_block };
8971 self.builder.positionBuilderAtEnd(memset_block.toLlvm(&self.wip));
8972 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
8973 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
8983 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
8984 dest_ptr.toLlvm(&self.wip),
8985 fill_byte.toLlvm(&self.wip),
8986 len.toLlvm(&self.wip),
8987 @intCast(dest_ptr_align.toByteUnits() orelse 0),
8988 is_volatile,
8989 ), &self.wip);
8990 _ = try self.wip.br(end_block);
89748991 self.wip.cursor = .{ .block = end_block };
8975 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));
89768992 }
89778993
8978 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8994 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
89798995 const o = self.dg.object;
89808996 const mod = o.module;
89818997 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -8983,9 +8999,9 @@ pub const FuncGen = struct {
89838999 const dest_ptr_ty = self.typeOf(bin_op.lhs);
89849000 const src_slice = try self.resolveInst(bin_op.rhs);
89859001 const src_ptr_ty = self.typeOf(bin_op.rhs);
8986 const src_ptr = self.sliceOrArrayPtr(src_slice, src_ptr_ty);
9002 const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ptr_ty);
89879003 const len = try self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty);
8988 const dest_ptr = self.sliceOrArrayPtr(dest_slice, dest_ptr_ty);
9004 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ptr_ty);
89899005 const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod);
89909006
89919007 // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction.
......@@ -8997,86 +9013,81 @@ pub const FuncGen = struct {
89979013 std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and
89989014 dest_ptr_ty.isSlice(mod))
89999015 {
9000 const llvm_usize_ty = try o.lowerType(Type.usize);
9001 const cond = try self.cmp(len, (try o.builder.intConst(llvm_usize_ty, 0)).toLlvm(&o.builder), Type.usize, .neq);
9002 const memcpy_block = try self.wip.block("MemcpyTrapSkip");
9003 const end_block = try self.wip.block("MemcpyTrapEnd");
9004 _ = self.builder.buildCondBr(cond, memcpy_block.toLlvm(&self.wip), end_block.toLlvm(&self.wip));
9016 const zero_usize = try o.builder.intValue(try o.lowerType(Type.usize), 0);
9017 const cond = try self.cmp(len, zero_usize, Type.usize, .neq);
9018 const memcpy_block = try self.wip.block(1, "MemcpyTrapSkip");
9019 const end_block = try self.wip.block(2, "MemcpyTrapEnd");
9020 _ = try self.wip.brCond(cond, memcpy_block, end_block);
90059021 self.wip.cursor = .{ .block = memcpy_block };
9006 self.builder.positionBuilderAtEnd(memcpy_block.toLlvm(&self.wip));
9007 _ = self.builder.buildMemCpy(
9008 dest_ptr,
9022 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
9023 dest_ptr.toLlvm(&self.wip),
90099024 dest_ptr_ty.ptrAlignment(mod),
9010 src_ptr,
9025 src_ptr.toLlvm(&self.wip),
90119026 src_ptr_ty.ptrAlignment(mod),
9012 len,
9027 len.toLlvm(&self.wip),
90139028 is_volatile,
9014 );
9015 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
9029 ), &self.wip);
9030 _ = try self.wip.br(end_block);
90169031 self.wip.cursor = .{ .block = end_block };
9017 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));
9018 return null;
9032 return .none;
90199033 }
90209034
9021 _ = self.builder.buildMemCpy(
9022 dest_ptr,
9035 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
9036 dest_ptr.toLlvm(&self.wip),
90239037 dest_ptr_ty.ptrAlignment(mod),
9024 src_ptr,
9038 src_ptr.toLlvm(&self.wip),
90259039 src_ptr_ty.ptrAlignment(mod),
9026 len,
9040 len.toLlvm(&self.wip),
90279041 is_volatile,
9028 );
9029 return null;
9042 ), &self.wip);
9043 return .none;
90309044 }
90319045
9032 fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9046 fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
90339047 const o = self.dg.object;
90349048 const mod = o.module;
90359049 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
90369050 const un_ty = self.typeOf(bin_op.lhs).childType(mod);
90379051 const layout = un_ty.unionGetLayout(mod);
9038 if (layout.tag_size == 0) return null;
9052 if (layout.tag_size == 0) return .none;
90399053 const union_ptr = try self.resolveInst(bin_op.lhs);
90409054 const new_tag = try self.resolveInst(bin_op.rhs);
90419055 if (layout.payload_size == 0) {
90429056 // TODO alignment on this store
9043 _ = self.builder.buildStore(new_tag, union_ptr);
9044 return null;
9057 _ = try self.wip.store(.normal, new_tag, union_ptr, .default);
9058 return .none;
90459059 }
9046 const un_llvm_ty = (try o.lowerType(un_ty)).toLlvm(&o.builder);
90479060 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9048 const tag_field_ptr = self.builder.buildStructGEP(un_llvm_ty, union_ptr, tag_index, "");
9061 const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(un_ty), union_ptr, tag_index, "");
90499062 // TODO alignment on this store
9050 _ = self.builder.buildStore(new_tag, tag_field_ptr);
9051 return null;
9063 _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default);
9064 return .none;
90529065 }
90539066
9054 fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9067 fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
90559068 const o = self.dg.object;
90569069 const mod = o.module;
90579070 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
90589071 const un_ty = self.typeOf(ty_op.operand);
90599072 const layout = un_ty.unionGetLayout(mod);
9060 if (layout.tag_size == 0) return null;
9073 if (layout.tag_size == 0) return .none;
90619074 const union_handle = try self.resolveInst(ty_op.operand);
90629075 if (isByRef(un_ty, mod)) {
9063 const llvm_un_ty = (try o.lowerType(un_ty)).toLlvm(&o.builder);
9064 if (layout.payload_size == 0) {
9065 return self.builder.buildLoad(llvm_un_ty, union_handle, "");
9066 }
9076 const llvm_un_ty = try o.lowerType(un_ty);
9077 if (layout.payload_size == 0)
9078 return self.wip.load(.normal, llvm_un_ty, union_handle, .default, "");
90679079 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9068 const tag_field_ptr = self.builder.buildStructGEP(llvm_un_ty, union_handle, tag_index, "");
9069 return self.builder.buildLoad(llvm_un_ty.structGetTypeAtIndex(tag_index), tag_field_ptr, "");
9080 const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, "");
9081 const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index];
9082 return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, "");
90709083 } else {
9071 if (layout.payload_size == 0) {
9072 return union_handle;
9073 }
9084 if (layout.payload_size == 0) return union_handle;
90749085 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9075 return self.builder.buildExtractValue(union_handle, tag_index, "");
9086 return self.wip.extractValue(union_handle, &.{tag_index}, "");
90769087 }
90779088 }
90789089
9079 fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !?*llvm.Value {
9090 fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !Builder.Value {
90809091 const un_op = self.air.instructions.items(.data)[inst].un_op;
90819092 const operand = try self.resolveInst(un_op);
90829093 const operand_ty = self.typeOf(un_op);
......@@ -9084,7 +9095,7 @@ pub const FuncGen = struct {
90849095 return self.buildFloatOp(op, operand_ty, 1, .{operand});
90859096 }
90869097
9087 fn airNeg(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
9098 fn airNeg(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
90889099 self.builder.setFastMath(want_fast_math);
90899100
90909101 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -9094,57 +9105,64 @@ pub const FuncGen = struct {
90949105 return self.buildFloatOp(.neg, operand_ty, 1, .{operand});
90959106 }
90969107
9097 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
9108 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
90989109 const o = self.dg.object;
9099 const mod = o.module;
91009110 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
91019111 const operand_ty = self.typeOf(ty_op.operand);
91029112 const operand = try self.resolveInst(ty_op.operand);
91039113
9104 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{try o.lowerType(operand_ty)});
9114 const llvm_operand_ty = try o.lowerType(operand_ty);
9115 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{ llvm_operand_ty, .i1 }, .normal);
9116 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
91059117
9106 const params = [_]*llvm.Value{ operand, Builder.Constant.false.toLlvm(&o.builder) };
9107 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
9118 const params = [_]*llvm.Value{
9119 operand.toLlvm(&self.wip),
9120 Builder.Constant.false.toLlvm(&o.builder),
9121 };
9122 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9123 self.builder.buildCall(
9124 llvm_fn_ty.toLlvm(&o.builder),
9125 fn_val,
9126 &params,
9127 params.len,
9128 .C,
9129 .Auto,
9130 "",
9131 ),
9132 &self.wip,
9133 );
91089134 const result_ty = self.typeOfIndex(inst);
9109 const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder);
9110
9111 const bits = operand_ty.intInfo(mod).bits;
9112 const result_bits = result_ty.intInfo(mod).bits;
9113 if (bits > result_bits) {
9114 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
9115 } else if (bits < result_bits) {
9116 return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
9117 } else {
9118 return wrong_size_result;
9119 }
9135 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
91209136 }
91219137
9122 fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
9138 fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
91239139 const o = self.dg.object;
9124 const mod = o.module;
91259140 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
91269141 const operand_ty = self.typeOf(ty_op.operand);
91279142 const operand = try self.resolveInst(ty_op.operand);
91289143
9129 const params = [_]*llvm.Value{operand};
9130 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{try o.lowerType(operand_ty)});
9131
9132 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
9144 const llvm_operand_ty = try o.lowerType(operand_ty);
9145 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
9146 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
9147
9148 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9149 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9150 self.builder.buildCall(
9151 llvm_fn_ty.toLlvm(&o.builder),
9152 fn_val,
9153 &params,
9154 params.len,
9155 .C,
9156 .Auto,
9157 "",
9158 ),
9159 &self.wip,
9160 );
91339161 const result_ty = self.typeOfIndex(inst);
9134 const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder);
9135
9136 const bits = operand_ty.intInfo(mod).bits;
9137 const result_bits = result_ty.intInfo(mod).bits;
9138 if (bits > result_bits) {
9139 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
9140 } else if (bits < result_bits) {
9141 return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
9142 } else {
9143 return wrong_size_result;
9144 }
9162 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
91459163 }
91469164
9147 fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
9165 fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !Builder.Value {
91489166 const o = self.dg.object;
91499167 const mod = o.module;
91509168 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -9153,7 +9171,7 @@ pub const FuncGen = struct {
91539171 assert(bits % 8 == 0);
91549172
91559173 var operand = try self.resolveInst(ty_op.operand);
9156 var operand_llvm_ty = try o.lowerType(operand_ty);
9174 var llvm_operand_ty = try o.lowerType(operand_ty);
91579175
91589176 if (bits % 16 == 8) {
91599177 // If not an even byte-multiple, we need zero-extend + shift-left 1 byte
......@@ -9161,35 +9179,39 @@ pub const FuncGen = struct {
91619179 const scalar_ty = try o.builder.intType(@intCast(bits + 8));
91629180 if (operand_ty.zigTypeTag(mod) == .Vector) {
91639181 const vec_len = operand_ty.vectorLen(mod);
9164 operand_llvm_ty = try o.builder.vectorType(.normal, vec_len, scalar_ty);
9165 } else operand_llvm_ty = scalar_ty;
9182 llvm_operand_ty = try o.builder.vectorType(.normal, vec_len, scalar_ty);
9183 } else llvm_operand_ty = scalar_ty;
91669184
91679185 const shift_amt =
9168 try o.builder.splatConst(operand_llvm_ty, try o.builder.intConst(scalar_ty, 8));
9169 const extended = self.builder.buildZExt(operand, operand_llvm_ty.toLlvm(&o.builder), "");
9170 operand = self.builder.buildShl(extended, shift_amt.toLlvm(&o.builder), "");
9186 try o.builder.splatValue(llvm_operand_ty, try o.builder.intConst(scalar_ty, 8));
9187 const extended = try self.wip.cast(.zext, operand, llvm_operand_ty, "");
9188 operand = try self.wip.bin(.shl, extended, shift_amt, "");
91719189
91729190 bits = bits + 8;
91739191 }
91749192
9175 const params = [_]*llvm.Value{operand};
9176 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
9177
9178 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
9193 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
9194 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
9195
9196 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9197 const wrong_size_result = (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
9198 self.builder.buildCall(
9199 llvm_fn_ty.toLlvm(&o.builder),
9200 fn_val,
9201 &params,
9202 params.len,
9203 .C,
9204 .Auto,
9205 "",
9206 ),
9207 &self.wip,
9208 );
91799209
91809210 const result_ty = self.typeOfIndex(inst);
9181 const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder);
9182 const result_bits = result_ty.intInfo(mod).bits;
9183 if (bits > result_bits) {
9184 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
9185 } else if (bits < result_bits) {
9186 return self.builder.buildZExt(wrong_size_result, result_llvm_ty, "");
9187 } else {
9188 return wrong_size_result;
9189 }
9211 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
91909212 }
91919213
9192 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9214 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
91939215 const o = self.dg.object;
91949216 const mod = o.module;
91959217 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -9197,58 +9219,60 @@ pub const FuncGen = struct {
91979219 const error_set_ty = self.air.getRefType(ty_op.ty);
91989220
91999221 const names = error_set_ty.errorSetNames(mod);
9200 const valid_block = try self.wip.block("Valid");
9201 const invalid_block = try self.wip.block("Invalid");
9202 const end_block = try self.wip.block("End");
9203 const switch_instr = self.builder.buildSwitch(operand, invalid_block.toLlvm(&self.wip), @intCast(names.len));
9222 const valid_block = try self.wip.block(@intCast(names.len), "Valid");
9223 const invalid_block = try self.wip.block(1, "Invalid");
9224 const end_block = try self.wip.block(2, "End");
9225 var wip_switch = try self.wip.@"switch"(operand, invalid_block, @intCast(names.len));
9226 defer wip_switch.finish(&self.wip);
92049227
92059228 for (names) |name| {
92069229 const err_int = mod.global_error_set.getIndex(name).?;
9207 const this_tag_int_value =
9208 try o.lowerValue((try mod.intValue(Type.err_int, err_int)).toIntern());
9209 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), valid_block.toLlvm(&self.wip));
9230 const this_tag_int_value = try o.builder.intConst(Builder.Type.err_int, err_int);
9231 try wip_switch.addCase(this_tag_int_value, valid_block, &self.wip);
92109232 }
92119233 self.wip.cursor = .{ .block = valid_block };
9212 self.builder.positionBuilderAtEnd(valid_block.toLlvm(&self.wip));
9213 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
9234 _ = try self.wip.br(end_block);
92149235
92159236 self.wip.cursor = .{ .block = invalid_block };
9216 self.builder.positionBuilderAtEnd(invalid_block.toLlvm(&self.wip));
9217 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
9237 _ = try self.wip.br(end_block);
92189238
92199239 self.wip.cursor = .{ .block = end_block };
9220 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));
9221
9222 const incoming_values: [2]*llvm.Value = .{
9223 Builder.Constant.true.toLlvm(&o.builder),
9224 Builder.Constant.false.toLlvm(&o.builder),
9225 };
9226 const incoming_blocks: [2]*llvm.BasicBlock = .{
9227 valid_block.toLlvm(&self.wip), invalid_block.toLlvm(&self.wip),
9228 };
9229 const phi_node = self.builder.buildPhi(Builder.Type.i1.toLlvm(&o.builder), "");
9230 phi_node.addIncoming(&incoming_values, &incoming_blocks, 2);
9231 return phi_node;
9240 const phi = try self.wip.phi(.i1, "");
9241 try phi.finish(
9242 &.{ Builder.Constant.true.toValue(), Builder.Constant.false.toValue() },
9243 &.{ valid_block, invalid_block },
9244 &self.wip,
9245 );
9246 return phi.toValue();
92329247 }
92339248
9234 fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9249 fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9250 const o = self.dg.object;
92359251 const un_op = self.air.instructions.items(.data)[inst].un_op;
92369252 const operand = try self.resolveInst(un_op);
92379253 const enum_ty = self.typeOf(un_op);
92389254
92399255 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
9240 const params = [_]*llvm.Value{operand};
9241 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
9256 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9257 return (try self.wip.unimplemented(.i1, "")).finish(self.builder.buildCall(
9258 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
9259 llvm_fn.toLlvm(&o.builder),
9260 &params,
9261 params.len,
9262 .Fast,
9263 .Auto,
9264 "",
9265 ), &self.wip);
92429266 }
92439267
9244 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
9268 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
92459269 const o = self.dg.object;
92469270 const mod = o.module;
92479271 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
92489272
92499273 // TODO: detect when the type changes and re-emit this function.
92509274 const gop = try o.named_enum_map.getOrPut(o.gpa, enum_type.decl);
9251 if (gop.found_existing) return gop.value_ptr.toLlvm(&o.builder);
9275 if (gop.found_existing) return gop.value_ptr.*;
92529276 errdefer assert(o.named_enum_map.remove(enum_type.decl));
92539277
92549278 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
......@@ -9256,9 +9280,9 @@ pub const FuncGen = struct {
92569280 fqn.fmt(&mod.intern_pool),
92579281 });
92589282
9259 const fn_type = try o.builder.fnType(.i1, &.{try o.lowerType(
9260 enum_type.tag_ty.toType(),
9261 )}, .normal);
9283 const fn_type = try o.builder.fnType(.i1, &.{
9284 try o.lowerType(enum_type.tag_ty.toType()),
9285 }, .normal);
92629286 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
92639287 fn_val.setLinkage(.Internal);
92649288 fn_val.setFunctionCallConv(.Fast);
......@@ -9277,63 +9301,63 @@ pub const FuncGen = struct {
92779301 try o.builder.functions.append(self.gpa, function);
92789302 gop.value_ptr.* = global.kind.function;
92799303
9280 const prev_block = self.builder.getInsertBlock();
9281 const prev_debug_location = self.builder.getCurrentDebugLocation2();
9282 defer {
9283 self.builder.positionBuilderAtEnd(prev_block);
9284 if (self.di_scope != null) {
9285 self.builder.setCurrentDebugLocation2(prev_debug_location);
9286 }
9287 }
9288
9289 var wip = Builder.WipFunction.init(&o.builder, global.kind.function);
9304 var wip = try Builder.WipFunction.init(&o.builder, global.kind.function);
92909305 defer wip.deinit();
9306 wip.cursor = .{ .block = try wip.block(0, "Entry") };
92919307
9292 const entry_block = try wip.block("Entry");
9293 wip.cursor = .{ .block = entry_block };
9294 self.builder.positionBuilderAtEnd(entry_block.toLlvm(&wip));
9295 self.builder.clearCurrentDebugLocation();
9296
9297 const named_block = try wip.block("Named");
9298 const unnamed_block = try wip.block("Unnamed");
9299 const tag_int_value = fn_val.getParam(0);
9300 const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block.toLlvm(&wip), @intCast(enum_type.names.len));
9308 const named_block = try wip.block(@intCast(enum_type.names.len), "Named");
9309 const unnamed_block = try wip.block(1, "Unnamed");
9310 const tag_int_value = wip.arg(0);
9311 var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(enum_type.names.len));
9312 defer wip_switch.finish(&wip);
93019313
93029314 for (0..enum_type.names.len) |field_index| {
9303 const this_tag_int_value =
9304 try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern());
9305 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), named_block.toLlvm(&wip));
9315 const this_tag_int_value = try o.lowerValue(
9316 (try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
9317 );
9318 try wip_switch.addCase(this_tag_int_value, named_block, &wip);
93069319 }
93079320 wip.cursor = .{ .block = named_block };
9308 self.builder.positionBuilderAtEnd(named_block.toLlvm(&wip));
9309 _ = self.builder.buildRet(Builder.Constant.true.toLlvm(&o.builder));
9321 _ = try wip.ret(Builder.Constant.true.toValue());
93109322
93119323 wip.cursor = .{ .block = unnamed_block };
9312 self.builder.positionBuilderAtEnd(unnamed_block.toLlvm(&wip));
9313 _ = self.builder.buildRet(Builder.Constant.false.toLlvm(&o.builder));
9324 _ = try wip.ret(Builder.Constant.false.toValue());
93149325
93159326 try wip.finish();
9316 return fn_val;
9327 return global.kind.function;
93179328 }
93189329
9319 fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9330 fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9331 const o = self.dg.object;
93209332 const un_op = self.air.instructions.items(.data)[inst].un_op;
93219333 const operand = try self.resolveInst(un_op);
93229334 const enum_ty = self.typeOf(un_op);
93239335
93249336 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
9325 const params = [_]*llvm.Value{operand};
9326 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
9337 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
9338 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9339 return (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
9340 self.builder.buildCall(
9341 llvm_fn_ty.toLlvm(&o.builder),
9342 llvm_fn.toLlvm(&o.builder),
9343 &params,
9344 params.len,
9345 .Fast,
9346 .Auto,
9347 "",
9348 ),
9349 &self.wip,
9350 );
93279351 }
93289352
9329 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {
9353 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
93309354 const o = self.dg.object;
93319355 const mod = o.module;
93329356 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
93339357
93349358 // TODO: detect when the type changes and re-emit this function.
93359359 const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);
9336 if (gop.found_existing) return gop.value_ptr.toLlvm(&o.builder);
9360 if (gop.found_existing) return gop.value_ptr.ptrConst(&o.builder).kind.function;
93379361 errdefer assert(o.decl_map.remove(enum_type.decl));
93389362
93399363 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
......@@ -9362,26 +9386,15 @@ pub const FuncGen = struct {
93629386 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);
93639387 try o.builder.functions.append(self.gpa, function);
93649388
9365 const prev_block = self.builder.getInsertBlock();
9366 const prev_debug_location = self.builder.getCurrentDebugLocation2();
9367 defer {
9368 self.builder.positionBuilderAtEnd(prev_block);
9369 if (self.di_scope != null) {
9370 self.builder.setCurrentDebugLocation2(prev_debug_location);
9371 }
9372 }
9373
9374 var wip = Builder.WipFunction.init(&o.builder, global.kind.function);
9389 var wip = try Builder.WipFunction.init(&o.builder, global.kind.function);
93759390 defer wip.deinit();
9391 wip.cursor = .{ .block = try wip.block(0, "Entry") };
93769392
9377 const entry_block = try wip.block("Entry");
9378 wip.cursor = .{ .block = entry_block };
9379 self.builder.positionBuilderAtEnd(entry_block.toLlvm(&wip));
9380 self.builder.clearCurrentDebugLocation();
9381
9382 const bad_value_block = try wip.block("BadValue");
9383 const tag_int_value = fn_val.getParam(0);
9384 const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block.toLlvm(&wip), @intCast(enum_type.names.len));
9393 const bad_value_block = try wip.block(1, "BadValue");
9394 const tag_int_value = wip.arg(0);
9395 var wip_switch =
9396 try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len));
9397 defer wip_switch.finish(&wip);
93859398
93869399 for (enum_type.names, 0..) |name_ip, field_index| {
93879400 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_ip));
......@@ -9398,46 +9411,45 @@ pub const FuncGen = struct {
93989411 .linkage = .private,
93999412 .unnamed_addr = .unnamed_addr,
94009413 .type = str_ty,
9401 .alignment = comptime Builder.Alignment.fromByteUnits(1),
94029414 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
94039415 };
94049416 var str_variable = Builder.Variable{
94059417 .global = @enumFromInt(o.builder.globals.count()),
94069418 .mutability = .constant,
94079419 .init = str_init,
9420 .alignment = comptime Builder.Alignment.fromByteUnits(1),
94089421 };
94099422 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);
94109423 const global_index = try o.builder.addGlobal(.empty, str_global);
94119424 try o.builder.variables.append(o.gpa, str_variable);
94129425
9413 const slice_val = try o.builder.structConst(ret_ty, &.{
9426 const slice_val = try o.builder.structValue(ret_ty, &.{
94149427 global_index.toConst(),
94159428 try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),
94169429 });
94179430
9418 const return_block = try wip.block("Name");
9419 const this_tag_int_value =
9420 try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern());
9421 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), return_block.toLlvm(&wip));
9431 const return_block = try wip.block(1, "Name");
9432 const this_tag_int_value = try o.lowerValue(
9433 (try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
9434 );
9435 try wip_switch.addCase(this_tag_int_value, return_block, &wip);
94229436
94239437 wip.cursor = .{ .block = return_block };
9424 self.builder.positionBuilderAtEnd(return_block.toLlvm(&wip));
9425 _ = self.builder.buildRet(slice_val.toLlvm(&o.builder));
9438 _ = try wip.ret(slice_val);
94269439 }
94279440
94289441 wip.cursor = .{ .block = bad_value_block };
9429 self.builder.positionBuilderAtEnd(bad_value_block.toLlvm(&wip));
9430 _ = self.builder.buildUnreachable();
9442 _ = try wip.@"unreachable"();
94319443
94329444 try wip.finish();
9433 return fn_val;
9445 return global.kind.function;
94349446 }
94359447
9436 fn getCmpLtErrorsLenFunction(self: *FuncGen) !*llvm.Value {
9448 fn getCmpLtErrorsLenFunction(self: *FuncGen) !Builder.Function.Index {
94379449 const o = self.dg.object;
94389450
94399451 const name = try o.builder.string(lt_errors_fn_name);
9440 if (o.builder.getGlobal(name)) |llvm_fn| return llvm_fn.toLlvm(&o.builder);
9452 if (o.builder.getGlobal(name)) |llvm_fn| return llvm_fn.ptrConst(&o.builder).kind.function;
94419453
94429454 // Function signature: fn (anyerror) bool
94439455
......@@ -9458,47 +9470,45 @@ pub const FuncGen = struct {
94589470 };
94599471
94609472 try o.builder.llvm.globals.append(self.gpa, llvm_fn);
9461 const global_index = try o.builder.addGlobal(name, global);
9473 _ = try o.builder.addGlobal(name, global);
94629474 try o.builder.functions.append(self.gpa, function);
9463 return global_index.toLlvm(&o.builder);
9475 return global.kind.function;
94649476 }
94659477
9466 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9478 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
94679479 const o = self.dg.object;
94689480 const un_op = self.air.instructions.items(.data)[inst].un_op;
94699481 const operand = try self.resolveInst(un_op);
94709482 const slice_ty = self.typeOfIndex(inst);
9471 const slice_llvm_ty = (try o.lowerType(slice_ty)).toLlvm(&o.builder);
9483 const slice_llvm_ty = try o.lowerType(slice_ty);
94729484
94739485 const error_name_table_ptr = try self.getErrorNameTable();
9474 const ptr_slice_llvm_ty = self.context.pointerType(0);
9475 const error_name_table = self.builder.buildLoad(ptr_slice_llvm_ty, error_name_table_ptr.toLlvm(&o.builder), "");
9476 const indices = [_]*llvm.Value{operand};
9477 const error_name_ptr = self.builder.buildInBoundsGEP(slice_llvm_ty, error_name_table, &indices, indices.len, "");
9478 return self.builder.buildLoad(slice_llvm_ty, error_name_ptr, "");
9486 const error_name_table =
9487 try self.wip.load(.normal, .ptr, error_name_table_ptr.toValue(&o.builder), .default, "");
9488 const error_name_ptr =
9489 try self.wip.gep(.inbounds, slice_llvm_ty, error_name_table, &.{operand}, "");
9490 return self.wip.load(.normal, slice_llvm_ty, error_name_ptr, .default, "");
94799491 }
94809492
9481 fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9493 fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
94829494 const o = self.dg.object;
9483 const mod = o.module;
94849495 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
94859496 const scalar = try self.resolveInst(ty_op.operand);
94869497 const vector_ty = self.typeOfIndex(inst);
9487 const len = vector_ty.vectorLen(mod);
9488 return self.builder.buildVectorSplat(len, scalar, "");
9498 return self.wip.splatVector(try o.lowerType(vector_ty), scalar, "");
94899499 }
94909500
9491 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9501 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
94929502 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
94939503 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
94949504 const pred = try self.resolveInst(pl_op.operand);
94959505 const a = try self.resolveInst(extra.lhs);
94969506 const b = try self.resolveInst(extra.rhs);
94979507
9498 return self.builder.buildSelect(pred, a, b, "");
9508 return self.wip.select(pred, a, b, "");
94999509 }
95009510
9501 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9511 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
95029512 const o = self.dg.object;
95039513 const mod = o.module;
95049514 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -9528,11 +9538,11 @@ pub const FuncGen = struct {
95289538 }
95299539 }
95309540
9531 const llvm_mask_value = try o.builder.vectorConst(
9541 const llvm_mask_value = try o.builder.vectorValue(
95329542 try o.builder.vectorType(.normal, mask_len, .i32),
95339543 values,
95349544 );
9535 return self.builder.buildShuffleVector(a, b, llvm_mask_value.toLlvm(&o.builder), "");
9545 return self.wip.shuffleVector(a, b, llvm_mask_value, "");
95369546 }
95379547
95389548 /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.
......@@ -9549,61 +9559,69 @@ pub const FuncGen = struct {
95499559 ///
95509560 fn buildReducedCall(
95519561 self: *FuncGen,
9552 llvm_fn: *llvm.Value,
9553 operand_vector: *llvm.Value,
9562 llvm_fn: Builder.Function.Index,
9563 operand_vector: Builder.Value,
95549564 vector_len: usize,
9555 accum_init: *llvm.Value,
9556 ) !*llvm.Value {
9565 accum_init: Builder.Value,
9566 ) !Builder.Value {
95579567 const o = self.dg.object;
95589568 const usize_ty = try o.lowerType(Type.usize);
9559 const llvm_vector_len = try o.builder.intConst(usize_ty, vector_len);
9560 const llvm_result_ty = accum_init.typeOf();
9569 const llvm_vector_len = try o.builder.intValue(usize_ty, vector_len);
9570 const llvm_result_ty = accum_init.typeOfWip(&self.wip);
95619571
95629572 // Allocate and initialize our mutable variables
9563 const i_ptr = try self.buildAlloca(usize_ty.toLlvm(&o.builder), null);
9564 _ = self.builder.buildStore((try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder), i_ptr);
9565 const accum_ptr = try self.buildAlloca(llvm_result_ty, null);
9566 _ = self.builder.buildStore(accum_init, accum_ptr);
9573 const i_ptr = try self.buildAlloca(usize_ty, .default);
9574 _ = try self.wip.store(.normal, try o.builder.intValue(usize_ty, 0), i_ptr, .default);
9575 const accum_ptr = try self.buildAlloca(llvm_result_ty, .default);
9576 _ = try self.wip.store(.normal, accum_init, accum_ptr, .default);
95679577
95689578 // Setup the loop
9569 const loop = try self.wip.block("ReduceLoop");
9570 const loop_exit = try self.wip.block("AfterReduce");
9571 _ = self.builder.buildBr(loop.toLlvm(&self.wip));
9579 const loop = try self.wip.block(2, "ReduceLoop");
9580 const loop_exit = try self.wip.block(1, "AfterReduce");
9581 _ = try self.wip.br(loop);
95729582 {
95739583 self.wip.cursor = .{ .block = loop };
9574 self.builder.positionBuilderAtEnd(loop.toLlvm(&self.wip));
95759584
95769585 // while (i < vec.len)
9577 const i = self.builder.buildLoad(usize_ty.toLlvm(&o.builder), i_ptr, "");
9578 const cond = self.builder.buildICmp(.ULT, i, llvm_vector_len.toLlvm(&o.builder), "");
9579 const loop_then = try self.wip.block("ReduceLoopThen");
9586 const i = try self.wip.load(.normal, usize_ty, i_ptr, .default, "");
9587 const cond = try self.wip.icmp(.ult, i, llvm_vector_len, "");
9588 const loop_then = try self.wip.block(1, "ReduceLoopThen");
95809589
9581 _ = self.builder.buildCondBr(cond, loop_then.toLlvm(&self.wip), loop_exit.toLlvm(&self.wip));
9590 _ = try self.wip.brCond(cond, loop_then, loop_exit);
95829591
95839592 {
95849593 self.wip.cursor = .{ .block = loop_then };
9585 self.builder.positionBuilderAtEnd(loop_then.toLlvm(&self.wip));
95869594
95879595 // accum = f(accum, vec[i]);
9588 const accum = self.builder.buildLoad(llvm_result_ty, accum_ptr, "");
9589 const element = self.builder.buildExtractElement(operand_vector, i, "");
9590 const params = [2]*llvm.Value{ accum, element };
9591 const new_accum = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");
9592 _ = self.builder.buildStore(new_accum, accum_ptr);
9596 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
9597 const element = try self.wip.extractElement(operand_vector, i, "");
9598 const params = [2]*llvm.Value{ accum.toLlvm(&self.wip), element.toLlvm(&self.wip) };
9599 const new_accum = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
9600 self.builder.buildCall(
9601 llvm_fn.typeOf(&o.builder).toLlvm(&o.builder),
9602 llvm_fn.toLlvm(&o.builder),
9603 &params,
9604 params.len,
9605 .C,
9606 .Auto,
9607 "",
9608 ),
9609 &self.wip,
9610 );
9611 _ = try self.wip.store(.normal, new_accum, accum_ptr, .default);
95939612
95949613 // i += 1
9595 const new_i = self.builder.buildAdd(i, (try o.builder.intConst(usize_ty, 1)).toLlvm(&o.builder), "");
9596 _ = self.builder.buildStore(new_i, i_ptr);
9597 _ = self.builder.buildBr(loop.toLlvm(&self.wip));
9614 const new_i = try self.wip.bin(.add, i, try o.builder.intValue(usize_ty, 1), "");
9615 _ = try self.wip.store(.normal, new_i, i_ptr, .default);
9616 _ = try self.wip.br(loop);
95989617 }
95999618 }
96009619
96019620 self.wip.cursor = .{ .block = loop_exit };
9602 self.builder.positionBuilderAtEnd(loop_exit.toLlvm(&self.wip));
9603 return self.builder.buildLoad(llvm_result_ty, accum_ptr, "");
9621 return self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
96049622 }
96059623
9606 fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
9624 fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !Builder.Value {
96079625 self.builder.setFastMath(want_fast_math);
96089626 const o = self.dg.object;
96099627 const mod = o.module;
......@@ -9613,40 +9631,70 @@ pub const FuncGen = struct {
96139631 const operand = try self.resolveInst(reduce.operand);
96149632 const operand_ty = self.typeOf(reduce.operand);
96159633 const scalar_ty = self.typeOfIndex(inst);
9634 const llvm_scalar_ty = try o.lowerType(scalar_ty);
96169635
96179636 switch (reduce.operation) {
9618 .And => return self.builder.buildAndReduce(operand),
9619 .Or => return self.builder.buildOrReduce(operand),
9620 .Xor => return self.builder.buildXorReduce(operand),
9637 .And => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9638 .finish(self.builder.buildAndReduce(operand.toLlvm(&self.wip)), &self.wip),
9639 .Or => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9640 .finish(self.builder.buildOrReduce(operand.toLlvm(&self.wip)), &self.wip),
9641 .Xor => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9642 .finish(self.builder.buildXorReduce(operand.toLlvm(&self.wip)), &self.wip),
96219643 .Min => switch (scalar_ty.zigTypeTag(mod)) {
9622 .Int => return self.builder.buildIntMinReduce(operand, scalar_ty.isSignedInt(mod)),
9644 .Int => return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9645 self.builder.buildIntMinReduce(
9646 operand.toLlvm(&self.wip),
9647 scalar_ty.isSignedInt(mod),
9648 ),
9649 &self.wip,
9650 ),
96239651 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9624 return self.builder.buildFPMinReduce(operand);
9652 return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9653 .finish(self.builder.buildFPMinReduce(operand.toLlvm(&self.wip)), &self.wip);
96259654 },
96269655 else => unreachable,
96279656 },
96289657 .Max => switch (scalar_ty.zigTypeTag(mod)) {
9629 .Int => return self.builder.buildIntMaxReduce(operand, scalar_ty.isSignedInt(mod)),
9658 .Int => return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9659 self.builder.buildIntMaxReduce(
9660 operand.toLlvm(&self.wip),
9661 scalar_ty.isSignedInt(mod),
9662 ),
9663 &self.wip,
9664 ),
96309665 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9631 return self.builder.buildFPMaxReduce(operand);
9666 return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9667 .finish(self.builder.buildFPMaxReduce(operand.toLlvm(&self.wip)), &self.wip);
96329668 },
96339669 else => unreachable,
96349670 },
96359671 .Add => switch (scalar_ty.zigTypeTag(mod)) {
9636 .Int => return self.builder.buildAddReduce(operand),
9672 .Int => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9673 .finish(self.builder.buildAddReduce(operand.toLlvm(&self.wip)), &self.wip),
96379674 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9638 const scalar_llvm_ty = try o.lowerType(scalar_ty);
9639 const neutral_value = try o.builder.fpConst(scalar_llvm_ty, -0.0);
9640 return self.builder.buildFPAddReduce(neutral_value.toLlvm(&o.builder), operand);
9675 const neutral_value = try o.builder.fpConst(llvm_scalar_ty, -0.0);
9676 return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9677 self.builder.buildFPAddReduce(
9678 neutral_value.toLlvm(&o.builder),
9679 operand.toLlvm(&self.wip),
9680 ),
9681 &self.wip,
9682 );
96419683 },
96429684 else => unreachable,
96439685 },
96449686 .Mul => switch (scalar_ty.zigTypeTag(mod)) {
9645 .Int => return self.builder.buildMulReduce(operand),
9687 .Int => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9688 .finish(self.builder.buildMulReduce(operand.toLlvm(&self.wip)), &self.wip),
96469689 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9647 const scalar_llvm_ty = try o.lowerType(scalar_ty);
9648 const neutral_value = try o.builder.fpConst(scalar_llvm_ty, 1.0);
9649 return self.builder.buildFPMulReduce(neutral_value.toLlvm(&o.builder), operand);
9690 const neutral_value = try o.builder.fpConst(llvm_scalar_ty, 1.0);
9691 return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9692 self.builder.buildFPMulReduce(
9693 neutral_value.toLlvm(&o.builder),
9694 operand.toLlvm(&self.wip),
9695 ),
9696 &self.wip,
9697 );
96509698 },
96519699 else => unreachable,
96529700 },
......@@ -9671,34 +9719,54 @@ pub const FuncGen = struct {
96719719 else => unreachable,
96729720 };
96739721
9674 const param_llvm_ty = try o.lowerType(scalar_ty);
9675 const libc_fn = try self.getLibcFunction(fn_name, &(.{param_llvm_ty} ** 2), param_llvm_ty);
9676 const init_value = try o.lowerValue((try mod.floatValue(scalar_ty, switch (reduce.operation) {
9677 .Min => std.math.nan(f32),
9678 .Max => std.math.nan(f32),
9679 .Add => -0.0,
9680 .Mul => 1.0,
9722 const libc_fn =
9723 try self.getLibcFunction(fn_name, &.{ llvm_scalar_ty, llvm_scalar_ty }, llvm_scalar_ty);
9724 const init_val = switch (llvm_scalar_ty) {
9725 .i16 => try o.builder.intValue(.i16, @as(i16, @bitCast(
9726 @as(f16, switch (reduce.operation) {
9727 .Min, .Max => std.math.nan(f16),
9728 .Add => -0.0,
9729 .Mul => 1.0,
9730 else => unreachable,
9731 }),
9732 ))),
9733 .i80 => try o.builder.intValue(.i80, @as(i80, @bitCast(
9734 @as(f80, switch (reduce.operation) {
9735 .Min, .Max => std.math.nan(f80),
9736 .Add => -0.0,
9737 .Mul => 1.0,
9738 else => unreachable,
9739 }),
9740 ))),
9741 .i128 => try o.builder.intValue(.i128, @as(i128, @bitCast(
9742 @as(f128, switch (reduce.operation) {
9743 .Min, .Max => std.math.nan(f128),
9744 .Add => -0.0,
9745 .Mul => 1.0,
9746 else => unreachable,
9747 }),
9748 ))),
96819749 else => unreachable,
9682 })).toIntern());
9683 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value.toLlvm(&o.builder));
9750 };
9751 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_val);
96849752 }
96859753
9686 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9754 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
96879755 const o = self.dg.object;
96889756 const mod = o.module;
96899757 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
96909758 const result_ty = self.typeOfIndex(inst);
96919759 const len: usize = @intCast(result_ty.arrayLen(mod));
96929760 const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]);
9693 const llvm_result_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder);
9761 const llvm_result_ty = try o.lowerType(result_ty);
96949762
96959763 switch (result_ty.zigTypeTag(mod)) {
96969764 .Vector => {
9697 var vector = llvm_result_ty.getUndef();
9765 var vector = try o.builder.poisonValue(llvm_result_ty);
96989766 for (elements, 0..) |elem, i| {
9699 const index_u32 = try o.builder.intConst(.i32, i);
9767 const index_u32 = try o.builder.intValue(.i32, i);
97009768 const llvm_elem = try self.resolveInst(elem);
9701 vector = self.builder.buildInsertElement(vector, llvm_elem, index_u32.toLlvm(&o.builder), "");
9769 vector = try self.wip.insertElement(vector, llvm_elem, index_u32, "");
97029770 }
97039771 return vector;
97049772 },
......@@ -9710,7 +9778,7 @@ pub const FuncGen = struct {
97109778 const int_ty = try o.builder.intType(@intCast(big_bits));
97119779 const fields = struct_obj.fields.values();
97129780 comptime assert(Type.packed_struct_layout_version == 2);
9713 var running_int = (try o.builder.intConst(int_ty, 0)).toLlvm(&o.builder);
9781 var running_int = try o.builder.intValue(int_ty, 0);
97149782 var running_bits: u16 = 0;
97159783 for (elements, 0..) |elem, i| {
97169784 const field = fields[i];
......@@ -9718,18 +9786,18 @@ pub const FuncGen = struct {
97189786
97199787 const non_int_val = try self.resolveInst(elem);
97209788 const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod));
9721 const small_int_ty = (try o.builder.intType(ty_bit_size)).toLlvm(&o.builder);
9789 const small_int_ty = try o.builder.intType(ty_bit_size);
97229790 const small_int_val = if (field.ty.isPtrAtRuntime(mod))
9723 self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
9791 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
97249792 else
9725 self.builder.buildBitCast(non_int_val, small_int_ty, "");
9726 const shift_rhs = try o.builder.intConst(int_ty, running_bits);
9793 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
9794 const shift_rhs = try o.builder.intValue(int_ty, running_bits);
97279795 // If the field is as large as the entire packed struct, this
97289796 // zext would go from, e.g. i16 to i16. This is legal with
97299797 // constZExtOrBitCast but not legal with constZExt.
9730 const extended_int_val = self.builder.buildZExtOrBitCast(small_int_val, int_ty.toLlvm(&o.builder), "");
9731 const shifted = self.builder.buildShl(extended_int_val, shift_rhs.toLlvm(&o.builder), "");
9732 running_int = self.builder.buildOr(running_int, shifted, "");
9798 const extended_int_val = try self.wip.conv(.unsigned, small_int_val, int_ty, "");
9799 const shifted = try self.wip.bin(.shl, extended_int_val, shift_rhs, "");
9800 running_int = try self.wip.bin(.@"or", running_int, shifted, "");
97339801 running_bits += ty_bit_size;
97349802 }
97359803 return running_int;
......@@ -9738,19 +9806,16 @@ pub const FuncGen = struct {
97389806 if (isByRef(result_ty, mod)) {
97399807 // TODO in debug builds init to undef so that the padding will be 0xaa
97409808 // even if we fully populate the fields.
9741 const alloca_inst = try self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(mod));
9809 const alignment = Builder.Alignment.fromByteUnits(result_ty.abiAlignment(mod));
9810 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
97429811
9743 var indices: [2]*llvm.Value = .{
9744 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
9745 undefined,
9746 };
97479812 for (elements, 0..) |elem, i| {
97489813 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
97499814
97509815 const llvm_elem = try self.resolveInst(elem);
97519816 const llvm_i = llvmField(result_ty, i, mod).?.index;
9752 indices[1] = (try o.builder.intConst(.i32, llvm_i)).toLlvm(&o.builder);
9753 const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
9817 const field_ptr =
9818 try self.wip.gepStruct(llvm_result_ty, alloca_inst, llvm_i, "");
97549819 const field_ptr_ty = try mod.ptrType(.{
97559820 .child = self.typeOf(elem).toIntern(),
97569821 .flags = .{
......@@ -9759,18 +9824,18 @@ pub const FuncGen = struct {
97599824 ),
97609825 },
97619826 });
9762 try self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic);
9827 try self.store(field_ptr, field_ptr_ty, llvm_elem, .none);
97639828 }
97649829
97659830 return alloca_inst;
97669831 } else {
9767 var result = llvm_result_ty.getUndef();
9832 var result = try o.builder.poisonValue(llvm_result_ty);
97689833 for (elements, 0..) |elem, i| {
97699834 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
97709835
97719836 const llvm_elem = try self.resolveInst(elem);
97729837 const llvm_i = llvmField(result_ty, i, mod).?.index;
9773 result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, "");
9838 result = try self.wip.insertValue(result, llvm_elem, &.{llvm_i}, "");
97749839 }
97759840 return result;
97769841 }
......@@ -9778,8 +9843,10 @@ pub const FuncGen = struct {
97789843 .Array => {
97799844 assert(isByRef(result_ty, mod));
97809845
9781 const usize_ty = try o.lowerType(Type.usize);
9782 const alloca_inst = try self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(mod));
9846 const llvm_usize = try o.lowerType(Type.usize);
9847 const usize_zero = try o.builder.intValue(llvm_usize, 0);
9848 const alignment = Builder.Alignment.fromByteUnits(result_ty.abiAlignment(mod));
9849 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
97839850
97849851 const array_info = result_ty.arrayInfo(mod);
97859852 const elem_ptr_ty = try mod.ptrType(.{
......@@ -9787,26 +9854,21 @@ pub const FuncGen = struct {
97879854 });
97889855
97899856 for (elements, 0..) |elem, i| {
9790 const indices: [2]*llvm.Value = .{
9791 (try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder),
9792 (try o.builder.intConst(usize_ty, i)).toLlvm(&o.builder),
9793 };
9794 const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
9857 const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{
9858 usize_zero, try o.builder.intValue(llvm_usize, i),
9859 }, "");
97959860 const llvm_elem = try self.resolveInst(elem);
9796 try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
9861 try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .none);
97979862 }
97989863 if (array_info.sentinel) |sent_val| {
9799 const indices: [2]*llvm.Value = .{
9800 (try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder),
9801 (try o.builder.intConst(usize_ty, array_info.len)).toLlvm(&o.builder),
9802 };
9803 const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
9864 const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{
9865 usize_zero, try o.builder.intValue(llvm_usize, array_info.len),
9866 }, "");
98049867 const llvm_elem = try self.resolveValue(.{
98059868 .ty = array_info.elem_type,
98069869 .val = sent_val,
98079870 });
9808
9809 try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toLlvm(&o.builder), .NotAtomic);
9871 try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toValue(), .none);
98109872 }
98119873
98129874 return alloca_inst;
......@@ -9815,7 +9877,7 @@ pub const FuncGen = struct {
98159877 }
98169878 }
98179879
9818 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9880 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
98199881 const o = self.dg.object;
98209882 const mod = o.module;
98219883 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -9827,15 +9889,15 @@ pub const FuncGen = struct {
98279889
98289890 if (union_obj.layout == .Packed) {
98299891 const big_bits = union_ty.bitSize(mod);
9830 const int_llvm_ty = (try o.builder.intType(@intCast(big_bits))).toLlvm(&o.builder);
9892 const int_llvm_ty = try o.builder.intType(@intCast(big_bits));
98319893 const field = union_obj.fields.values()[extra.field_index];
98329894 const non_int_val = try self.resolveInst(extra.init);
9833 const small_int_ty = (try o.builder.intType(@intCast(field.ty.bitSize(mod)))).toLlvm(&o.builder);
9895 const small_int_ty = try o.builder.intType(@intCast(field.ty.bitSize(mod)));
98349896 const small_int_val = if (field.ty.isPtrAtRuntime(mod))
9835 self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
9897 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
98369898 else
9837 self.builder.buildBitCast(non_int_val, small_int_ty, "");
9838 return self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");
9899 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
9900 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");
98399901 }
98409902
98419903 const tag_int = blk: {
......@@ -9848,25 +9910,29 @@ pub const FuncGen = struct {
98489910 };
98499911 if (layout.payload_size == 0) {
98509912 if (layout.tag_size == 0) {
9851 return null;
9913 return .none;
98529914 }
98539915 assert(!isByRef(union_ty, mod));
9854 return (try o.builder.intConst(union_llvm_ty, tag_int)).toLlvm(&o.builder);
9916 return o.builder.intValue(union_llvm_ty, tag_int);
98559917 }
98569918 assert(isByRef(union_ty, mod));
98579919 // The llvm type of the alloca will be the named LLVM union type, and will not
98589920 // necessarily match the format that we need, depending on which tag is active.
98599921 // We must construct the correct unnamed struct type here, in order to then set
98609922 // the fields appropriately.
9861 const result_ptr = try self.buildAlloca(union_llvm_ty.toLlvm(&o.builder), layout.abi_align);
9923 const alignment = Builder.Alignment.fromByteUnits(layout.abi_align);
9924 const result_ptr = try self.buildAlloca(union_llvm_ty, alignment);
98629925 const llvm_payload = try self.resolveInst(extra.init);
98639926 assert(union_obj.haveFieldTypes());
98649927 const field = union_obj.fields.values()[extra.field_index];
98659928 const field_llvm_ty = try o.lowerType(field.ty);
98669929 const field_size = field.ty.abiSize(mod);
98679930 const field_align = field.normalAlignment(mod);
9931 const llvm_usize = try o.lowerType(Type.usize);
9932 const usize_zero = try o.builder.intValue(llvm_usize, 0);
9933 const i32_zero = try o.builder.intValue(.i32, 0);
98689934
9869 const llvm_union_ty = (t: {
9935 const llvm_union_ty = t: {
98709936 const payload_ty = p: {
98719937 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) {
98729938 const padding_len = layout.payload_size;
......@@ -9894,52 +9960,46 @@ pub const FuncGen = struct {
98949960 fields_len += 1;
98959961 }
98969962 break :t try o.builder.structType(.normal, fields[0..fields_len]);
9897 }).toLlvm(&o.builder);
9963 };
98989964
98999965 // Now we follow the layout as expressed above with GEP instructions to set the
99009966 // tag and the payload.
99019967 const field_ptr_ty = try mod.ptrType(.{
99029968 .child = field.ty.toIntern(),
9903 .flags = .{
9904 .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align),
9905 },
9969 .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },
99069970 });
99079971 if (layout.tag_size == 0) {
9908 const indices: [3]*llvm.Value = .{
9909 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
9910 } ** 3;
9911 const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
9912 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, len, "");
9913 try self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic);
9972 const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero };
9973 const len: usize = if (field_size == layout.payload_size) 2 else 3;
9974 const field_ptr =
9975 try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], "");
9976 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
99149977 return result_ptr;
99159978 }
99169979
99179980 {
9918 const indices: [3]*llvm.Value = .{
9919 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
9920 (try o.builder.intConst(.i32, @intFromBool(layout.tag_align >= layout.payload_align))).toLlvm(&o.builder),
9921 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
9922 };
9923 const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
9924 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, len, "");
9925 try self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic);
9981 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
9982 const indices: [3]Builder.Value =
9983 .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero };
9984 const len: usize = if (field_size == layout.payload_size) 2 else 3;
9985 const field_ptr =
9986 try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], "");
9987 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
99269988 }
99279989 {
9928 const indices: [2]*llvm.Value = .{
9929 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
9930 (try o.builder.intConst(.i32, @intFromBool(layout.tag_align < layout.payload_align))).toLlvm(&o.builder),
9931 };
9932 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, indices.len, "");
9990 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9991 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
9992 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
99339993 const tag_ty = try o.lowerType(union_obj.tag_ty);
9934 const llvm_tag = try o.builder.intConst(tag_ty, tag_int);
9935 const store_inst = self.builder.buildStore(llvm_tag.toLlvm(&o.builder), field_ptr);
9936 store_inst.setAlignment(union_obj.tag_ty.abiAlignment(mod));
9994 const llvm_tag = try o.builder.intValue(tag_ty, tag_int);
9995 const tag_alignment = Builder.Alignment.fromByteUnits(union_obj.tag_ty.abiAlignment(mod));
9996 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
99379997 }
99389998
99399999 return result_ptr;
994010000 }
994110001
9942 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10002 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
994310003 const o = self.dg.object;
994410004 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
994510005
......@@ -9968,10 +10028,10 @@ pub const FuncGen = struct {
996810028 .powerpcle,
996910029 .powerpc64,
997010030 .powerpc64le,
9971 => return null,
10031 => return .none,
997210032 .arm, .armeb, .thumb, .thumbeb => {
997310033 switch (prefetch.rw) {
9974 .write => return null,
10034 .write => return .none,
997510035 else => {},
997610036 }
997710037 },
......@@ -9981,48 +10041,63 @@ pub const FuncGen = struct {
998110041 }
998210042
998310043 const llvm_fn_name = "llvm.prefetch.p0";
9984 const fn_val = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
9985 // declare void @llvm.prefetch(i8*, i32, i32, i32)
9986 const fn_type = try o.builder.fnType(.void, &.{ .ptr, .i32, .i32, .i32 }, .normal);
9987 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));
9988 };
10044 // declare void @llvm.prefetch(i8*, i32, i32, i32)
10045 const llvm_fn_ty = try o.builder.fnType(.void, &.{ .ptr, .i32, .i32, .i32 }, .normal);
10046 const fn_val = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
10047 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
998910048
999010049 const ptr = try self.resolveInst(prefetch.ptr);
999110050
999210051 const params = [_]*llvm.Value{
9993 ptr,
10052 ptr.toLlvm(&self.wip),
999410053 (try o.builder.intConst(.i32, @intFromEnum(prefetch.rw))).toLlvm(&o.builder),
999510054 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),
999610055 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),
999710056 };
9998 _ = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
9999 return null;
10057 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
10058 llvm_fn_ty.toLlvm(&o.builder),
10059 fn_val,
10060 &params,
10061 params.len,
10062 .C,
10063 .Auto,
10064 "",
10065 ), &self.wip);
10066 return .none;
1000010067 }
1000110068
10002 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10069 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
1000310070 const o = self.dg.object;
1000410071 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1000510072 const inst_ty = self.typeOfIndex(inst);
1000610073 const operand = try self.resolveInst(ty_op.operand);
1000710074
10008 const llvm_dest_ty = (try o.lowerType(inst_ty)).toLlvm(&o.builder);
10009 return self.builder.buildAddrSpaceCast(operand, llvm_dest_ty, "");
10075 return self.wip.cast(.addrspacecast, operand, try o.lowerType(inst_ty), "");
1001010076 }
1001110077
10012 fn amdgcnWorkIntrinsic(self: *FuncGen, dimension: u32, default: u32, comptime basename: []const u8) !?*llvm.Value {
10078 fn amdgcnWorkIntrinsic(self: *FuncGen, dimension: u32, default: u32, comptime basename: []const u8) !Builder.Value {
10079 const o = self.dg.object;
1001310080 const llvm_fn_name = switch (dimension) {
1001410081 0 => basename ++ ".x",
1001510082 1 => basename ++ ".y",
1001610083 2 => basename ++ ".z",
10017 else => return (try self.dg.object.builder.intConst(.i32, default)).toLlvm(&self.dg.object.builder),
10084 else => return o.builder.intValue(.i32, default),
1001810085 };
1001910086
1002010087 const args: [0]*llvm.Value = .{};
1002110088 const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});
10022 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
10089 return (try self.wip.unimplemented(.i32, "")).finish(self.builder.buildCall(
10090 (try o.builder.fnType(.i32, &.{}, .normal)).toLlvm(&o.builder),
10091 llvm_fn,
10092 &args,
10093 args.len,
10094 .Fast,
10095 .Auto,
10096 "",
10097 ), &self.wip);
1002310098 }
1002410099
10025 fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10100 fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
1002610101 const o = self.dg.object;
1002710102 const target = o.module.getTarget();
1002810103 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
......@@ -10032,38 +10107,41 @@ pub const FuncGen = struct {
1003210107 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workitem.id");
1003310108 }
1003410109
10035 fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10110 fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
1003610111 const o = self.dg.object;
1003710112 const target = o.module.getTarget();
1003810113 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
1003910114
1004010115 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1004110116 const dimension = pl_op.payload;
10042 if (dimension >= 3) {
10043 return (try o.builder.intConst(.i32, 1)).toLlvm(&o.builder);
10044 }
10117 if (dimension >= 3) return o.builder.intValue(.i32, 1);
1004510118
1004610119 // Fetch the dispatch pointer, which points to this structure:
1004710120 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913
1004810121 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});
1004910122 const args: [0]*llvm.Value = .{};
10050 const dispatch_ptr = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");
10051 dispatch_ptr.setAlignment(4);
10123 const llvm_ret_ty = try o.builder.ptrType(Builder.AddrSpace.amdgpu.constant);
10124 const dispatch_ptr = (try self.wip.unimplemented(llvm_ret_ty, "")).finish(self.builder.buildCall(
10125 (try o.builder.fnType(llvm_ret_ty, &.{}, .normal)).toLlvm(&o.builder),
10126 llvm_fn,
10127 &args,
10128 args.len,
10129 .Fast,
10130 .Auto,
10131 "",
10132 ), &self.wip);
10133 o.addAttrInt(dispatch_ptr.toLlvm(&self.wip), 0, "align", 4);
1005210134
1005310135 // Load the work_group_* member from the struct as u16.
1005410136 // Just treat the dispatch pointer as an array of u16 to keep things simple.
10055 const offset = 2 + dimension;
10056 const index = [_]*llvm.Value{
10057 (try o.builder.intConst(.i32, offset)).toLlvm(&o.builder),
10058 };
10059 const llvm_u16 = Builder.Type.i16.toLlvm(&o.builder);
10060 const workgroup_size_ptr = self.builder.buildInBoundsGEP(llvm_u16, dispatch_ptr, &index, index.len, "");
10061 const workgroup_size = self.builder.buildLoad(llvm_u16, workgroup_size_ptr, "");
10062 workgroup_size.setAlignment(2);
10063 return workgroup_size;
10137 const workgroup_size_ptr = try self.wip.gep(.inbounds, .i16, dispatch_ptr, &.{
10138 try o.builder.intValue(try o.lowerType(Type.usize), 2 + dimension),
10139 }, "");
10140 const workgroup_size_alignment = comptime Builder.Alignment.fromByteUnits(2);
10141 return self.wip.load(.normal, .i16, workgroup_size_ptr, workgroup_size_alignment, "");
1006410142 }
1006510143
10066 fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
10144 fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
1006710145 const o = self.dg.object;
1006810146 const target = o.module.getTarget();
1006910147 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
......@@ -10095,13 +10173,13 @@ pub const FuncGen = struct {
1009510173 .linkage = .private,
1009610174 .unnamed_addr = .unnamed_addr,
1009710175 .type = .ptr,
10098 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
1009910176 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
1010010177 };
1010110178 var variable = Builder.Variable{
1010210179 .global = @enumFromInt(o.builder.globals.count()),
1010310180 .mutability = .constant,
1010410181 .init = undef_init,
10182 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
1010510183 };
1010610184 try o.builder.llvm.globals.append(o.gpa, error_name_table_global);
1010710185 _ = try o.builder.addGlobal(name, global);
......@@ -10112,97 +10190,95 @@ pub const FuncGen = struct {
1011210190 }
1011310191
1011410192 /// Assumes the optional is not pointer-like and payload has bits.
10115 fn optIsNonNull(
10193 fn optCmpNull(
1011610194 self: *FuncGen,
10117 opt_llvm_ty: *llvm.Type,
10118 opt_handle: *llvm.Value,
10195 cond: Builder.IntegerCondition,
10196 opt_llvm_ty: Builder.Type,
10197 opt_handle: Builder.Value,
1011910198 is_by_ref: bool,
10120 ) Allocator.Error!*llvm.Value {
10199 ) Allocator.Error!Builder.Value {
10200 const o = self.dg.object;
1012110201 const field = b: {
1012210202 if (is_by_ref) {
10123 const field_ptr = self.builder.buildStructGEP(opt_llvm_ty, opt_handle, 1, "");
10124 break :b self.builder.buildLoad(Builder.Type.i8.toLlvm(&self.dg.object.builder), field_ptr, "");
10203 const field_ptr = try self.wip.gepStruct(opt_llvm_ty, opt_handle, 1, "");
10204 break :b try self.wip.load(.normal, .i8, field_ptr, .default, "");
1012510205 }
10126 break :b self.builder.buildExtractValue(opt_handle, 1, "");
10206 break :b try self.wip.extractValue(opt_handle, &.{1}, "");
1012710207 };
1012810208 comptime assert(optional_layout_version == 3);
1012910209
10130 return self.builder.buildICmp(.NE, field, (try self.dg.object.builder.intConst(.i8, 0)).toLlvm(&self.dg.object.builder), "");
10210 return self.wip.icmp(cond, field, try o.builder.intValue(.i8, 0), "");
1013110211 }
1013210212
1013310213 /// Assumes the optional is not pointer-like and payload has bits.
1013410214 fn optPayloadHandle(
1013510215 fg: *FuncGen,
10136 opt_llvm_ty: *llvm.Type,
10137 opt_handle: *llvm.Value,
10216 opt_llvm_ty: Builder.Type,
10217 opt_handle: Builder.Value,
1013810218 opt_ty: Type,
1013910219 can_elide_load: bool,
10140 ) !*llvm.Value {
10220 ) !Builder.Value {
1014110221 const o = fg.dg.object;
1014210222 const mod = o.module;
1014310223 const payload_ty = opt_ty.optionalChild(mod);
1014410224
1014510225 if (isByRef(opt_ty, mod)) {
1014610226 // We have a pointer and we need to return a pointer to the first field.
10147 const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, "");
10227 const payload_ptr = try fg.wip.gepStruct(opt_llvm_ty, opt_handle, 0, "");
1014810228
10149 const payload_alignment = payload_ty.abiAlignment(mod);
10229 const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod));
1015010230 if (isByRef(payload_ty, mod)) {
1015110231 if (can_elide_load)
1015210232 return payload_ptr;
1015310233
1015410234 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
1015510235 }
10156 const payload_llvm_ty = (try o.lowerType(payload_ty)).toLlvm(&o.builder);
10157 const load_inst = fg.builder.buildLoad(payload_llvm_ty, payload_ptr, "");
10158 load_inst.setAlignment(payload_alignment);
10159 return load_inst;
10236 const payload_llvm_ty = try o.lowerType(payload_ty);
10237 return fg.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
1016010238 }
1016110239
1016210240 assert(!isByRef(payload_ty, mod));
10163 return fg.builder.buildExtractValue(opt_handle, 0, "");
10241 return fg.wip.extractValue(opt_handle, &.{0}, "");
1016410242 }
1016510243
1016610244 fn buildOptional(
1016710245 self: *FuncGen,
1016810246 optional_ty: Type,
10169 payload: *llvm.Value,
10170 non_null_bit: *llvm.Value,
10171 ) !?*llvm.Value {
10247 payload: Builder.Value,
10248 non_null_bit: Builder.Value,
10249 ) !Builder.Value {
1017210250 const o = self.dg.object;
10173 const optional_llvm_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);
10174 const non_null_field = self.builder.buildZExt(non_null_bit, Builder.Type.i8.toLlvm(&o.builder), "");
10251 const optional_llvm_ty = try o.lowerType(optional_ty);
10252 const non_null_field = try self.wip.cast(.zext, non_null_bit, .i8, "");
1017510253 const mod = o.module;
1017610254
1017710255 if (isByRef(optional_ty, mod)) {
10178 const payload_alignment = optional_ty.abiAlignment(mod);
10256 const payload_alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
1017910257 const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment);
1018010258
1018110259 {
10182 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");
10183 const store_inst = self.builder.buildStore(payload, field_ptr);
10184 store_inst.setAlignment(payload_alignment);
10260 const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 0, "");
10261 _ = try self.wip.store(.normal, payload, field_ptr, payload_alignment);
1018510262 }
1018610263 {
10187 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 1, "");
10188 const store_inst = self.builder.buildStore(non_null_field, field_ptr);
10189 store_inst.setAlignment(1);
10264 const non_null_alignment = comptime Builder.Alignment.fromByteUnits(1);
10265 const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 1, "");
10266 _ = try self.wip.store(.normal, non_null_field, field_ptr, non_null_alignment);
1019010267 }
1019110268
1019210269 return alloca_inst;
1019310270 }
1019410271
10195 const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
10196 return self.builder.buildInsertValue(partial, non_null_field, 1, "");
10272 return self.wip.buildAggregate(optional_llvm_ty, &.{ payload, non_null_field }, "");
1019710273 }
1019810274
1019910275 fn fieldPtr(
1020010276 self: *FuncGen,
1020110277 inst: Air.Inst.Index,
10202 struct_ptr: *llvm.Value,
10278 struct_ptr: Builder.Value,
1020310279 struct_ptr_ty: Type,
1020410280 field_index: u32,
10205 ) !?*llvm.Value {
10281 ) !Builder.Value {
1020610282 const o = self.dg.object;
1020710283 const mod = o.module;
1020810284 const struct_ty = struct_ptr_ty.childType(mod);
......@@ -10224,25 +10300,25 @@ pub const FuncGen = struct {
1022410300 // Offset our operand pointer by the correct number of bytes.
1022510301 const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, mod);
1022610302 if (byte_offset == 0) return struct_ptr;
10227 const byte_llvm_ty = Builder.Type.i8.toLlvm(&o.builder);
1022810303 const usize_ty = try o.lowerType(Type.usize);
10229 const llvm_index = try o.builder.intConst(usize_ty, byte_offset);
10230 const indices: [1]*llvm.Value = .{llvm_index.toLlvm(&o.builder)};
10231 return self.builder.buildInBoundsGEP(byte_llvm_ty, struct_ptr, &indices, indices.len, "");
10304 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);
10305 return self.wip.gep(.inbounds, .i8, struct_ptr, &.{llvm_index}, "");
1023210306 },
1023310307 else => {
10234 const struct_llvm_ty = (try o.lowerPtrElemTy(struct_ty)).toLlvm(&o.builder);
10308 const struct_llvm_ty = try o.lowerPtrElemTy(struct_ty);
1023510309
1023610310 if (llvmField(struct_ty, field_index, mod)) |llvm_field| {
10237 return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field.index, "");
10311 return self.wip.gepStruct(struct_llvm_ty, struct_ptr, llvm_field.index, "");
1023810312 } else {
1023910313 // If we found no index then this means this is a zero sized field at the
1024010314 // end of the struct. Treat our struct pointer as an array of two and get
1024110315 // the index to the element at index `1` to get a pointer to the end of
1024210316 // the struct.
10243 const llvm_index = try o.builder.intConst(.i32, @intFromBool(struct_ty.hasRuntimeBitsIgnoreComptime(mod)));
10244 const indices: [1]*llvm.Value = .{llvm_index.toLlvm(&o.builder)};
10245 return self.builder.buildInBoundsGEP(struct_llvm_ty, struct_ptr, &indices, indices.len, "");
10317 const llvm_index = try o.builder.intValue(
10318 try o.lowerType(Type.usize),
10319 @intFromBool(struct_ty.hasRuntimeBitsIgnoreComptime(mod)),
10320 );
10321 return self.wip.gep(.inbounds, struct_llvm_ty, struct_ptr, &.{llvm_index}, "");
1024610322 }
1024710323 },
1024810324 },
......@@ -10250,15 +10326,18 @@ pub const FuncGen = struct {
1025010326 const layout = struct_ty.unionGetLayout(mod);
1025110327 if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr;
1025210328 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
10253 const union_llvm_ty = (try o.lowerType(struct_ty)).toLlvm(&o.builder);
10254 const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_ptr, payload_index, "");
10255 return union_field_ptr;
10329 const union_llvm_ty = try o.lowerType(struct_ty);
10330 return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");
1025610331 },
1025710332 else => unreachable,
1025810333 }
1025910334 }
1026010335
10261 fn getIntrinsic(fg: *FuncGen, name: []const u8, types: []const Builder.Type) Allocator.Error!*llvm.Value {
10336 fn getIntrinsic(
10337 fg: *FuncGen,
10338 name: []const u8,
10339 types: []const Builder.Type,
10340 ) Allocator.Error!*llvm.Value {
1026210341 const o = fg.dg.object;
1026310342 const id = llvm.lookupIntrinsicID(name.ptr, name.len);
1026410343 assert(id != 0);
......@@ -10271,109 +10350,105 @@ pub const FuncGen = struct {
1027110350 /// Load a by-ref type by constructing a new alloca and performing a memcpy.
1027210351 fn loadByRef(
1027310352 fg: *FuncGen,
10274 ptr: *llvm.Value,
10353 ptr: Builder.Value,
1027510354 pointee_type: Type,
10276 ptr_alignment: u32,
10355 ptr_alignment: Builder.Alignment,
1027710356 is_volatile: bool,
10278 ) !*llvm.Value {
10357 ) !Builder.Value {
1027910358 const o = fg.dg.object;
1028010359 const mod = o.module;
10281 const pointee_llvm_ty = (try o.lowerType(pointee_type)).toLlvm(&o.builder);
10282 const result_align = @max(ptr_alignment, pointee_type.abiAlignment(mod));
10360 const pointee_llvm_ty = try o.lowerType(pointee_type);
10361 const result_align = Builder.Alignment.fromByteUnits(
10362 @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)),
10363 );
1028310364 const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);
1028410365 const usize_ty = try o.lowerType(Type.usize);
1028510366 const size_bytes = pointee_type.abiSize(mod);
10286 _ = fg.builder.buildMemCpy(
10287 result_ptr,
10288 result_align,
10289 ptr,
10290 ptr_alignment,
10367 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildMemCpy(
10368 result_ptr.toLlvm(&fg.wip),
10369 @intCast(result_align.toByteUnits() orelse 0),
10370 ptr.toLlvm(&fg.wip),
10371 @intCast(ptr_alignment.toByteUnits() orelse 0),
1029110372 (try o.builder.intConst(usize_ty, size_bytes)).toLlvm(&o.builder),
1029210373 is_volatile,
10293 );
10374 ), &fg.wip);
1029410375 return result_ptr;
1029510376 }
1029610377
1029710378 /// This function always performs a copy. For isByRef=true types, it creates a new
1029810379 /// alloca and copies the value into it, then returns the alloca instruction.
1029910380 /// For isByRef=false types, it creates a load instruction and returns it.
10300 fn load(self: *FuncGen, ptr: *llvm.Value, ptr_ty: Type) !?*llvm.Value {
10381 fn load(self: *FuncGen, ptr: Builder.Value, ptr_ty: Type) !Builder.Value {
1030110382 const o = self.dg.object;
1030210383 const mod = o.module;
1030310384 const info = ptr_ty.ptrInfo(mod);
1030410385 const elem_ty = info.child.toType();
10305 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;
10386 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
1030610387
10307 const ptr_alignment: u32 = @intCast(info.flags.alignment.toByteUnitsOptional() orelse
10308 elem_ty.abiAlignment(mod));
10309 const ptr_volatile = llvm.Bool.fromBool(info.flags.is_volatile);
10388 const ptr_alignment = Builder.Alignment.fromByteUnits(
10389 info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod),
10390 );
10391 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
10392 false => .normal,
10393 true => .@"volatile",
10394 };
1031010395
1031110396 assert(info.flags.vector_index != .runtime);
1031210397 if (info.flags.vector_index != .none) {
10313 const index_u32 = try o.builder.intConst(.i32, @intFromEnum(info.flags.vector_index));
10398 const index_u32 = try o.builder.intValue(.i32, @intFromEnum(info.flags.vector_index));
1031410399 const vec_elem_ty = try o.lowerType(elem_ty);
1031510400 const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty);
1031610401
10317 const loaded_vector = self.builder.buildLoad(vec_ty.toLlvm(&o.builder), ptr, "");
10318 loaded_vector.setAlignment(ptr_alignment);
10319 loaded_vector.setVolatile(ptr_volatile);
10320
10321 return self.builder.buildExtractElement(loaded_vector, index_u32.toLlvm(&o.builder), "");
10402 const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, "");
10403 return self.wip.extractElement(loaded_vector, index_u32, "");
1032210404 }
1032310405
1032410406 if (info.packed_offset.host_size == 0) {
1032510407 if (isByRef(elem_ty, mod)) {
1032610408 return self.loadByRef(ptr, elem_ty, ptr_alignment, info.flags.is_volatile);
1032710409 }
10328 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
10329 const llvm_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");
10330 llvm_inst.setAlignment(ptr_alignment);
10331 llvm_inst.setVolatile(ptr_volatile);
10332 return llvm_inst;
10410 return self.wip.load(ptr_kind, try o.lowerType(elem_ty), ptr, ptr_alignment, "");
1033310411 }
1033410412
1033510413 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
10336 const containing_int = self.builder.buildLoad(containing_int_ty.toLlvm(&o.builder), ptr, "");
10337 containing_int.setAlignment(ptr_alignment);
10338 containing_int.setVolatile(ptr_volatile);
10414 const containing_int = try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
1033910415
1034010416 const elem_bits = ptr_ty.childType(mod).bitSize(mod);
10341 const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset);
10342 const shifted_value = self.builder.buildLShr(containing_int, shift_amt.toLlvm(&o.builder), "");
10343 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
10417 const shift_amt = try o.builder.intValue(containing_int_ty, info.packed_offset.bit_offset);
10418 const shifted_value = try self.wip.bin(.lshr, containing_int, shift_amt, "");
10419 const elem_llvm_ty = try o.lowerType(elem_ty);
1034410420
1034510421 if (isByRef(elem_ty, mod)) {
10346 const result_align = elem_ty.abiAlignment(mod);
10422 const result_align = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
1034710423 const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align);
1034810424
10349 const same_size_int = (try o.builder.intType(@intCast(elem_bits))).toLlvm(&o.builder);
10350 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
10351 const store_inst = self.builder.buildStore(truncated_int, result_ptr);
10352 store_inst.setAlignment(result_align);
10425 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10426 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10427 _ = try self.wip.store(.normal, truncated_int, result_ptr, result_align);
1035310428 return result_ptr;
1035410429 }
1035510430
1035610431 if (elem_ty.zigTypeTag(mod) == .Float or elem_ty.zigTypeTag(mod) == .Vector) {
10357 const same_size_int = (try o.builder.intType(@intCast(elem_bits))).toLlvm(&o.builder);
10358 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
10359 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
10432 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10433 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10434 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
1036010435 }
1036110436
1036210437 if (elem_ty.isPtrAtRuntime(mod)) {
10363 const same_size_int = (try o.builder.intType(@intCast(elem_bits))).toLlvm(&o.builder);
10364 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
10365 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");
10438 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10439 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10440 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
1036610441 }
1036710442
10368 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");
10443 return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
1036910444 }
1037010445
1037110446 fn store(
1037210447 self: *FuncGen,
10373 ptr: *llvm.Value,
10448 ptr: Builder.Value,
1037410449 ptr_ty: Type,
10375 elem: *llvm.Value,
10376 ordering: llvm.AtomicOrdering,
10450 elem: Builder.Value,
10451 ordering: Builder.AtomicOrdering,
1037710452 ) !void {
1037810453 const o = self.dg.object;
1037910454 const mod = o.module;
......@@ -10382,43 +10457,41 @@ pub const FuncGen = struct {
1038210457 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
1038310458 return;
1038410459 }
10385 const ptr_alignment = ptr_ty.ptrAlignment(mod);
10386 const ptr_volatile = llvm.Bool.fromBool(info.flags.is_volatile);
10460 const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
10461 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
10462 false => .normal,
10463 true => .@"volatile",
10464 };
1038710465
1038810466 assert(info.flags.vector_index != .runtime);
1038910467 if (info.flags.vector_index != .none) {
10390 const index_u32 = try o.builder.intConst(.i32, @intFromEnum(info.flags.vector_index));
10468 const index_u32 = try o.builder.intValue(.i32, @intFromEnum(info.flags.vector_index));
1039110469 const vec_elem_ty = try o.lowerType(elem_ty);
1039210470 const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty);
1039310471
10394 const loaded_vector = self.builder.buildLoad(vec_ty.toLlvm(&o.builder), ptr, "");
10395 loaded_vector.setAlignment(ptr_alignment);
10396 loaded_vector.setVolatile(ptr_volatile);
10472 const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, "");
1039710473
10398 const modified_vector = self.builder.buildInsertElement(loaded_vector, elem, index_u32.toLlvm(&o.builder), "");
10474 const modified_vector = try self.wip.insertElement(loaded_vector, elem, index_u32, "");
1039910475
10400 const store_inst = self.builder.buildStore(modified_vector, ptr);
10401 assert(ordering == .NotAtomic);
10402 store_inst.setAlignment(ptr_alignment);
10403 store_inst.setVolatile(ptr_volatile);
10476 assert(ordering == .none);
10477 _ = try self.wip.store(ptr_kind, modified_vector, ptr, ptr_alignment);
1040410478 return;
1040510479 }
1040610480
1040710481 if (info.packed_offset.host_size != 0) {
1040810482 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
10409 const containing_int = self.builder.buildLoad(containing_int_ty.toLlvm(&o.builder), ptr, "");
10410 assert(ordering == .NotAtomic);
10411 containing_int.setAlignment(ptr_alignment);
10412 containing_int.setVolatile(ptr_volatile);
10483 assert(ordering == .none);
10484 const containing_int =
10485 try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
1041310486 const elem_bits = ptr_ty.childType(mod).bitSize(mod);
1041410487 const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset);
1041510488 // Convert to equally-sized integer type in order to perform the bit
1041610489 // operations on the value to store
1041710490 const value_bits_type = try o.builder.intType(@intCast(elem_bits));
1041810491 const value_bits = if (elem_ty.isPtrAtRuntime(mod))
10419 self.builder.buildPtrToInt(elem, value_bits_type.toLlvm(&o.builder), "")
10492 try self.wip.cast(.ptrtoint, elem, value_bits_type, "")
1042010493 else
10421 self.builder.buildBitCast(elem, value_bits_type.toLlvm(&o.builder), "");
10494 try self.wip.cast(.bitcast, elem, value_bits_type, "");
1042210495
1042310496 var mask_val = try o.builder.intConst(value_bits_type, -1);
1042410497 mask_val = try o.builder.castConst(.zext, mask_val, containing_int_ty);
......@@ -10426,79 +10499,73 @@ pub const FuncGen = struct {
1042610499 mask_val =
1042710500 try o.builder.binConst(.xor, mask_val, try o.builder.intConst(containing_int_ty, -1));
1042810501
10429 const anded_containing_int = self.builder.buildAnd(containing_int, mask_val.toLlvm(&o.builder), "");
10430 const extended_value = self.builder.buildZExt(value_bits, containing_int_ty.toLlvm(&o.builder), "");
10431 const shifted_value = self.builder.buildShl(extended_value, shift_amt.toLlvm(&o.builder), "");
10432 const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, "");
10502 const anded_containing_int =
10503 try self.wip.bin(.@"and", containing_int, mask_val.toValue(), "");
10504 const extended_value = try self.wip.cast(.zext, value_bits, containing_int_ty, "");
10505 const shifted_value = try self.wip.bin(.shl, extended_value, shift_amt.toValue(), "");
10506 const ored_value = try self.wip.bin(.@"or", shifted_value, anded_containing_int, "");
1043310507
10434 const store_inst = self.builder.buildStore(ored_value, ptr);
10435 assert(ordering == .NotAtomic);
10436 store_inst.setAlignment(ptr_alignment);
10437 store_inst.setVolatile(ptr_volatile);
10508 assert(ordering == .none);
10509 _ = try self.wip.store(ptr_kind, ored_value, ptr, ptr_alignment);
1043810510 return;
1043910511 }
1044010512 if (!isByRef(elem_ty, mod)) {
10441 const store_inst = self.builder.buildStore(elem, ptr);
10442 store_inst.setOrdering(ordering);
10443 store_inst.setAlignment(ptr_alignment);
10444 store_inst.setVolatile(ptr_volatile);
10513 _ = try self.wip.storeAtomic(ptr_kind, elem, ptr, self.sync_scope, ordering, ptr_alignment);
1044510514 return;
1044610515 }
10447 assert(ordering == .NotAtomic);
10516 assert(ordering == .none);
1044810517 const size_bytes = elem_ty.abiSize(mod);
10449 _ = self.builder.buildMemCpy(
10450 ptr,
10451 ptr_alignment,
10452 elem,
10518 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
10519 ptr.toLlvm(&self.wip),
10520 @intCast(ptr_alignment.toByteUnits() orelse 0),
10521 elem.toLlvm(&self.wip),
1045310522 elem_ty.abiAlignment(mod),
1045410523 (try o.builder.intConst(try o.lowerType(Type.usize), size_bytes)).toLlvm(&o.builder),
1045510524 info.flags.is_volatile,
10456 );
10525 ), &self.wip);
1045710526 }
1045810527
10459 fn valgrindMarkUndef(fg: *FuncGen, ptr: *llvm.Value, len: *llvm.Value) Allocator.Error!void {
10528 fn valgrindMarkUndef(fg: *FuncGen, ptr: Builder.Value, len: Builder.Value) Allocator.Error!void {
1046010529 const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
1046110530 const o = fg.dg.object;
1046210531 const usize_ty = try o.lowerType(Type.usize);
10463 const zero = (try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder);
10464 const req = (try o.builder.intConst(usize_ty, VG_USERREQ__MAKE_MEM_UNDEFINED)).toLlvm(&o.builder);
10465 const ptr_as_usize = fg.builder.buildPtrToInt(ptr, usize_ty.toLlvm(&o.builder), "");
10532 const zero = try o.builder.intValue(usize_ty, 0);
10533 const req = try o.builder.intValue(usize_ty, VG_USERREQ__MAKE_MEM_UNDEFINED);
10534 const ptr_as_usize = try fg.wip.cast(.ptrtoint, ptr, usize_ty, "");
1046610535 _ = try valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
1046710536 }
1046810537
1046910538 fn valgrindClientRequest(
1047010539 fg: *FuncGen,
10471 default_value: *llvm.Value,
10472 request: *llvm.Value,
10473 a1: *llvm.Value,
10474 a2: *llvm.Value,
10475 a3: *llvm.Value,
10476 a4: *llvm.Value,
10477 a5: *llvm.Value,
10478 ) Allocator.Error!*llvm.Value {
10540 default_value: Builder.Value,
10541 request: Builder.Value,
10542 a1: Builder.Value,
10543 a2: Builder.Value,
10544 a3: Builder.Value,
10545 a4: Builder.Value,
10546 a5: Builder.Value,
10547 ) Allocator.Error!Builder.Value {
1047910548 const o = fg.dg.object;
1048010549 const mod = o.module;
1048110550 const target = mod.getTarget();
1048210551 if (!target_util.hasValgrindSupport(target)) return default_value;
1048310552
1048410553 const llvm_usize = try o.lowerType(Type.usize);
10485 const usize_alignment = Type.usize.abiSize(mod);
10554 const usize_alignment = Builder.Alignment.fromByteUnits(Type.usize.abiAlignment(mod));
1048610555
10487 const array_llvm_ty = (try o.builder.arrayType(6, llvm_usize)).toLlvm(&o.builder);
10488 const array_ptr = fg.valgrind_client_request_array orelse a: {
10489 const array_ptr = try fg.buildAlloca(array_llvm_ty, @intCast(usize_alignment));
10556 const array_llvm_ty = try o.builder.arrayType(6, llvm_usize);
10557 const array_ptr = if (fg.valgrind_client_request_array == .none) a: {
10558 const array_ptr = try fg.buildAlloca(array_llvm_ty, usize_alignment);
1049010559 fg.valgrind_client_request_array = array_ptr;
1049110560 break :a array_ptr;
10492 };
10493 const array_elements = [_]*llvm.Value{ request, a1, a2, a3, a4, a5 };
10494 const zero = (try o.builder.intConst(llvm_usize, 0)).toLlvm(&o.builder);
10561 } else fg.valgrind_client_request_array;
10562 const array_elements = [_]Builder.Value{ request, a1, a2, a3, a4, a5 };
10563 const zero = try o.builder.intValue(llvm_usize, 0);
1049510564 for (array_elements, 0..) |elem, i| {
10496 const indexes = [_]*llvm.Value{
10497 zero, (try o.builder.intConst(llvm_usize, i)).toLlvm(&o.builder),
10498 };
10499 const elem_ptr = fg.builder.buildInBoundsGEP(array_llvm_ty, array_ptr, &indexes, indexes.len, "");
10500 const store_inst = fg.builder.buildStore(elem, elem_ptr);
10501 store_inst.setAlignment(@intCast(usize_alignment));
10565 const elem_ptr = try fg.wip.gep(.inbounds, array_llvm_ty, array_ptr, &.{
10566 zero, try o.builder.intValue(llvm_usize, i),
10567 }, "");
10568 _ = try fg.wip.store(.normal, elem, elem_ptr, usize_alignment);
1050210569 }
1050310570
1050410571 const arch_specific: struct {
......@@ -10533,8 +10600,8 @@ pub const FuncGen = struct {
1053310600 };
1053410601
1053510602 const fn_llvm_ty = (try o.builder.fnType(llvm_usize, &(.{llvm_usize} ** 2), .normal)).toLlvm(&o.builder);
10536 const array_ptr_as_usize = fg.builder.buildPtrToInt(array_ptr, llvm_usize.toLlvm(&o.builder), "");
10537 const args = [_]*llvm.Value{ array_ptr_as_usize, default_value };
10603 const array_ptr_as_usize = try fg.wip.cast(.ptrtoint, array_ptr, llvm_usize, "");
10604 const args = [_]*llvm.Value{ array_ptr_as_usize.toLlvm(&fg.wip), default_value.toLlvm(&fg.wip) };
1053810605 const asm_fn = llvm.getInlineAsm(
1053910606 fn_llvm_ty,
1054010607 arch_specific.template.ptr,
......@@ -10547,14 +10614,9 @@ pub const FuncGen = struct {
1054710614 .False, // can throw
1054810615 );
1054910616
10550 const call = fg.builder.buildCall(
10551 fn_llvm_ty,
10552 asm_fn,
10553 &args,
10554 args.len,
10555 .C,
10556 .Auto,
10557 "",
10617 const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(
10618 fg.builder.buildCall(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
10619 &fg.wip,
1055810620 );
1055910621 return call;
1056010622 }
......@@ -10764,14 +10826,14 @@ fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
1076410826 }
1076510827}
1076610828
10767fn toLlvmAtomicOrdering(atomic_order: std.builtin.AtomicOrder) llvm.AtomicOrdering {
10829fn toLlvmAtomicOrdering(atomic_order: std.builtin.AtomicOrder) Builder.AtomicOrdering {
1076810830 return switch (atomic_order) {
10769 .Unordered => .Unordered,
10770 .Monotonic => .Monotonic,
10771 .Acquire => .Acquire,
10772 .Release => .Release,
10773 .AcqRel => .AcquireRelease,
10774 .SeqCst => .SequentiallyConsistent,
10831 .Unordered => .unordered,
10832 .Monotonic => .monotonic,
10833 .Acquire => .acquire,
10834 .Release => .release,
10835 .AcqRel => .acq_rel,
10836 .SeqCst => .seq_cst,
1077510837 };
1077610838}
1077710839
......@@ -11718,12 +11780,40 @@ fn compilerRtIntBits(bits: u16) u16 {
1171811780 return bits;
1171911781}
1172011782
11783fn buildAllocaInner(
11784 wip: *Builder.WipFunction,
11785 di_scope_non_null: bool,
11786 llvm_ty: Builder.Type,
11787 alignment: Builder.Alignment,
11788 target: std.Target,
11789) Allocator.Error!Builder.Value {
11790 const address_space = llvmAllocaAddressSpace(target);
11791
11792 const alloca = blk: {
11793 const prev_cursor = wip.cursor;
11794 const prev_debug_location = wip.llvm.builder.getCurrentDebugLocation2();
11795 defer {
11796 wip.cursor = prev_cursor;
11797 if (wip.cursor.block == .entry) wip.cursor.instruction += 1;
11798 if (di_scope_non_null) wip.llvm.builder.setCurrentDebugLocation2(prev_debug_location);
11799 }
11800
11801 wip.cursor = .{ .block = .entry };
11802 wip.llvm.builder.clearCurrentDebugLocation();
11803 break :blk try wip.alloca(.normal, llvm_ty, .none, alignment, address_space, "");
11804 };
11805
11806 // The pointer returned from this function should have the generic address space,
11807 // if this isn't the case then cast it to the generic address space.
11808 return wip.conv(.unneeded, alloca, .ptr, "");
11809}
11810
1172111811fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 {
11722 return @intFromBool(Type.anyerror.abiAlignment(mod) > payload_ty.abiAlignment(mod));
11812 return @intFromBool(Type.err_int.abiAlignment(mod) > payload_ty.abiAlignment(mod));
1172311813}
1172411814
1172511815fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 {
11726 return @intFromBool(Type.anyerror.abiAlignment(mod) <= payload_ty.abiAlignment(mod));
11816 return @intFromBool(Type.err_int.abiAlignment(mod) <= payload_ty.abiAlignment(mod));
1172711817}
1172811818
1172911819/// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location
src/codegen/llvm/Builder.zig+3768-301
......@@ -43,6 +43,8 @@ constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
4343
4444pub const expected_fields_len = 32;
4545pub const expected_gep_indices_len = 8;
46pub const expected_cases_len = 8;
47pub const expected_incoming_len = 8;
4648
4749pub const Options = struct {
4850 allocator: Allocator,
......@@ -186,6 +188,7 @@ pub const Type = enum(u32) {
186188 pub const Function = struct {
187189 ret: Type,
188190 params_len: u32,
191 //params: [params_len]Value,
189192
190193 pub const Kind = enum { normal, vararg };
191194 };
......@@ -194,12 +197,18 @@ pub const Type = enum(u32) {
194197 name: String,
195198 types_len: u32,
196199 ints_len: u32,
200 //types: [types_len]Type,
201 //ints: [ints_len]u32,
197202 };
198203
199204 pub const Vector = extern struct {
200205 len: u32,
201206 child: Type,
202207
208 fn length(self: Vector) u32 {
209 return self.len;
210 }
211
203212 pub const Kind = enum { normal, scalable };
204213 };
205214
......@@ -208,13 +217,14 @@ pub const Type = enum(u32) {
208217 len_hi: u32,
209218 child: Type,
210219
211 fn len(self: Array) u64 {
220 fn length(self: Array) u64 {
212221 return @as(u64, self.len_hi) << 32 | self.len_lo;
213222 }
214223 };
215224
216225 pub const Structure = struct {
217226 fields_len: u32,
227 //fields: [fields_len]Type,
218228
219229 pub const Kind = enum { normal, @"packed" };
220230 };
......@@ -295,6 +305,29 @@ pub const Type = enum(u32) {
295305 };
296306 }
297307
308 pub fn functionParameters(self: Type, builder: *const Builder) []const Type {
309 const item = builder.type_items.items[@intFromEnum(self)];
310 switch (item.tag) {
311 .function,
312 .vararg_function,
313 => {
314 const extra = builder.typeExtraDataTrail(Type.Function, item.data);
315 return @ptrCast(builder.type_extra.items[extra.end..][0..extra.data.params_len]);
316 },
317 else => unreachable,
318 }
319 }
320
321 pub fn functionReturn(self: Type, builder: *const Builder) Type {
322 const item = builder.type_items.items[@intFromEnum(self)];
323 switch (item.tag) {
324 .function,
325 .vararg_function,
326 => return builder.typeExtraData(Type.Function, item.data).ret,
327 else => unreachable,
328 }
329 }
330
298331 pub fn isVector(self: Type, builder: *const Builder) bool {
299332 return switch (self.tag(builder)) {
300333 .vector, .scalable_vector => true,
......@@ -325,6 +358,13 @@ pub const Type = enum(u32) {
325358 };
326359 }
327360
361 pub fn isAggregate(self: Type, builder: *const Builder) bool {
362 return switch (self.tag(builder)) {
363 .small_array, .array, .structure, .packed_structure, .named_structure => true,
364 else => false,
365 };
366 }
367
328368 pub fn scalarBits(self: Type, builder: *const Builder) u24 {
329369 return switch (self) {
330370 .void, .label, .token, .metadata, .none, .x86_amx => unreachable,
......@@ -388,6 +428,33 @@ pub const Type = enum(u32) {
388428 };
389429 }
390430
431 pub fn changeScalar(self: Type, scalar: Type, builder: *Builder) Allocator.Error!Type {
432 try builder.ensureUnusedTypeCapacity(1, Type.Vector, 0);
433 return self.changeScalarAssumeCapacity(scalar, builder);
434 }
435
436 pub fn changeScalarAssumeCapacity(self: Type, scalar: Type, builder: *Builder) Type {
437 if (self.isFloatingPoint()) return scalar;
438 const item = builder.type_items.items[@intFromEnum(self)];
439 return switch (item.tag) {
440 .integer,
441 .pointer,
442 => scalar,
443 inline .vector,
444 .scalable_vector,
445 => |kind| builder.vectorTypeAssumeCapacity(
446 switch (kind) {
447 .vector => .normal,
448 .scalable_vector => .scalable,
449 else => unreachable,
450 },
451 builder.typeExtraData(Type.Vector, item.data).len,
452 scalar,
453 ),
454 else => unreachable,
455 };
456 }
457
391458 pub fn vectorLen(self: Type, builder: *const Builder) u32 {
392459 const item = builder.type_items.items[@intFromEnum(self)];
393460 return switch (item.tag) {
......@@ -398,6 +465,37 @@ pub const Type = enum(u32) {
398465 };
399466 }
400467
468 pub fn changeLength(self: Type, len: u32, builder: *Builder) Allocator.Error!Type {
469 try builder.ensureUnusedTypeCapacity(1, Type.Array, 0);
470 return self.changeLengthAssumeCapacity(len, builder);
471 }
472
473 pub fn changeLengthAssumeCapacity(self: Type, len: u32, builder: *Builder) Type {
474 const item = builder.type_items.items[@intFromEnum(self)];
475 return switch (item.tag) {
476 inline .vector,
477 .scalable_vector,
478 => |kind| builder.vectorTypeAssumeCapacity(
479 switch (kind) {
480 .vector => .normal,
481 .scalable_vector => .scalable,
482 else => unreachable,
483 },
484 len,
485 builder.typeExtraData(Type.Vector, item.data).child,
486 ),
487 .small_array => builder.arrayTypeAssumeCapacity(
488 len,
489 builder.typeExtraData(Type.Vector, item.data).child,
490 ),
491 .array => builder.arrayTypeAssumeCapacity(
492 len,
493 builder.typeExtraData(Type.Array, item.data).child,
494 ),
495 else => unreachable,
496 };
497 }
498
401499 pub fn aggregateLen(self: Type, builder: *const Builder) u64 {
402500 const item = builder.type_items.items[@intFromEnum(self)];
403501 return switch (item.tag) {
......@@ -405,7 +503,7 @@ pub const Type = enum(u32) {
405503 .scalable_vector,
406504 .small_array,
407505 => builder.typeExtraData(Type.Vector, item.data).len,
408 .array => builder.typeExtraData(Type.Array, item.data).len(),
506 .array => builder.typeExtraData(Type.Array, item.data).length(),
409507 .structure,
410508 .packed_structure,
411509 => builder.typeExtraData(Type.Structure, item.data).fields_len,
......@@ -430,7 +528,40 @@ pub const Type = enum(u32) {
430528 }
431529 }
432530
433 pub const FormatData = struct {
531 pub fn childTypeAt(self: Type, indices: []const u32, builder: *const Builder) Type {
532 if (indices.len == 0) return self;
533 const item = builder.type_items.items[@intFromEnum(self)];
534 return switch (item.tag) {
535 .small_array => builder.typeExtraData(Type.Vector, item.data).child
536 .childTypeAt(indices[1..], builder),
537 .array => builder.typeExtraData(Type.Array, item.data).child
538 .childTypeAt(indices[1..], builder),
539 .structure,
540 .packed_structure,
541 => {
542 const extra = builder.typeExtraDataTrail(Type.Structure, item.data);
543 const fields: []const Type =
544 @ptrCast(builder.type_extra.items[extra.end..][0..extra.data.fields_len]);
545 return fields[indices[0]].childTypeAt(indices[1..], builder);
546 },
547 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
548 .childTypeAt(indices, builder),
549 else => unreachable,
550 };
551 }
552
553 pub fn targetLayoutType(self: Type, builder: *const Builder) Type {
554 _ = self;
555 _ = builder;
556 @panic("TODO: implement targetLayoutType");
557 }
558
559 pub fn isSized(self: Type, builder: *const Builder) Allocator.Error!bool {
560 var visited: IsSizedVisited = .{};
561 return self.isSizedVisited(&visited, builder);
562 }
563
564 const FormatData = struct {
434565 type: Type,
435566 builder: *const Builder,
436567 };
......@@ -441,11 +572,90 @@ pub const Type = enum(u32) {
441572 writer: anytype,
442573 ) @TypeOf(writer).Error!void {
443574 assert(data.type != .none);
575 if (comptime std.mem.eql(u8, fmt_str, "m")) {
576 const item = data.builder.type_items.items[@intFromEnum(data.type)];
577 switch (item.tag) {
578 .simple => try writer.writeAll(switch (@as(Simple, @enumFromInt(item.data))) {
579 .void => "isVoid",
580 .half => "f16",
581 .bfloat => "bf16",
582 .float => "f32",
583 .double => "f64",
584 .fp128 => "f128",
585 .x86_fp80 => "f80",
586 .ppc_fp128 => "ppcf128",
587 .x86_amx => "x86amx",
588 .x86_mmx => "x86mmx",
589 .label, .token => unreachable,
590 .metadata => "Metadata",
591 }),
592 .function, .vararg_function => |kind| {
593 const extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
594 const params: []const Type =
595 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.params_len]);
596 try writer.print("f_{m}", .{extra.data.ret.fmt(data.builder)});
597 for (params) |param| try writer.print("{m}", .{param.fmt(data.builder)});
598 switch (kind) {
599 .function => {},
600 .vararg_function => try writer.writeAll("vararg"),
601 else => unreachable,
602 }
603 try writer.writeByte('f');
604 },
605 .integer => try writer.print("i{d}", .{item.data}),
606 .pointer => try writer.print("p{d}", .{item.data}),
607 .target => {
608 const extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
609 const types: []const Type =
610 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.types_len]);
611 const ints: []const u32 = @ptrCast(data.builder.type_extra.items[extra.end +
612 extra.data.types_len ..][0..extra.data.ints_len]);
613 try writer.print("t{s}", .{extra.data.name.toSlice(data.builder).?});
614 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});
615 for (ints) |int| try writer.print("_{d}", .{int});
616 try writer.writeByte('t');
617 },
618 .vector, .scalable_vector => |kind| {
619 const extra = data.builder.typeExtraData(Type.Vector, item.data);
620 try writer.print("{s}v{d}{m}", .{
621 switch (kind) {
622 .vector => "",
623 .scalable_vector => "nx",
624 else => unreachable,
625 },
626 extra.len,
627 extra.child.fmt(data.builder),
628 });
629 },
630 inline .small_array, .array => |kind| {
631 const extra = data.builder.typeExtraData(switch (kind) {
632 .small_array => Type.Vector,
633 .array => Type.Array,
634 else => unreachable,
635 }, item.data);
636 try writer.print("a{d}{m}", .{ extra.length(), extra.child.fmt(data.builder) });
637 },
638 .structure, .packed_structure => {
639 const extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
640 const fields: []const Type =
641 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.fields_len]);
642 try writer.writeAll("sl_");
643 for (fields) |field| try writer.print("{m}", .{field.fmt(data.builder)});
644 try writer.writeByte('s');
645 },
646 .named_structure => {
647 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
648 try writer.writeAll("s_");
649 if (extra.id.toSlice(data.builder)) |id| try writer.writeAll(id);
650 },
651 }
652 return;
653 }
444654 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
445655 const item = data.builder.type_items.items[@intFromEnum(data.type)];
446656 switch (item.tag) {
447657 .simple => unreachable,
448 .function, .vararg_function => {
658 .function, .vararg_function => |kind| {
449659 const extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
450660 const params: []const Type =
451661 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.params_len]);
......@@ -457,7 +667,7 @@ pub const Type = enum(u32) {
457667 if (index > 0) try writer.writeAll(", ");
458668 try writer.print("{%}", .{param.fmt(data.builder)});
459669 }
460 switch (item.tag) {
670 switch (kind) {
461671 .function => {},
462672 .vararg_function => {
463673 if (params.len > 0) try writer.writeAll(", ");
......@@ -483,29 +693,31 @@ pub const Type = enum(u32) {
483693 for (ints) |int| try writer.print(", {d}", .{int});
484694 try writer.writeByte(')');
485695 },
486 .vector => {
696 .vector, .scalable_vector => |kind| {
487697 const extra = data.builder.typeExtraData(Type.Vector, item.data);
488 try writer.print("<{d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });
489 },
490 .scalable_vector => {
491 const extra = data.builder.typeExtraData(Type.Vector, item.data);
492 try writer.print("<vscale x {d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });
493 },
494 .small_array => {
495 const extra = data.builder.typeExtraData(Type.Vector, item.data);
496 try writer.print("[{d} x {%}]", .{ extra.len, extra.child.fmt(data.builder) });
698 try writer.print("<{s}{d} x {%}>", .{
699 switch (kind) {
700 .vector => "",
701 .scalable_vector => "vscale x ",
702 else => unreachable,
703 },
704 extra.len,
705 extra.child.fmt(data.builder),
706 });
497707 },
498 .array => {
499 const extra = data.builder.typeExtraData(Type.Array, item.data);
500 try writer.print("[{d} x {%}]", .{ extra.len(), extra.child.fmt(data.builder) });
708 inline .small_array, .array => |kind| {
709 const extra = data.builder.typeExtraData(switch (kind) {
710 .small_array => Type.Vector,
711 .array => Type.Array,
712 else => unreachable,
713 }, item.data);
714 try writer.print("[{d} x {%}]", .{ extra.length(), extra.child.fmt(data.builder) });
501715 },
502 .structure,
503 .packed_structure,
504 => {
716 .structure, .packed_structure => |kind| {
505717 const extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
506718 const fields: []const Type =
507719 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.fields_len]);
508 switch (item.tag) {
720 switch (kind) {
509721 .structure => {},
510722 .packed_structure => try writer.writeByte('<'),
511723 else => unreachable,
......@@ -516,7 +728,7 @@ pub const Type = enum(u32) {
516728 try writer.print("{%}", .{field.fmt(data.builder)});
517729 }
518730 try writer.writeAll(" }");
519 switch (item.tag) {
731 switch (kind) {
520732 .structure => {},
521733 .packed_structure => try writer.writeByte('>'),
522734 else => unreachable,
......@@ -544,6 +756,82 @@ pub const Type = enum(u32) {
544756 assert(builder.useLibLlvm());
545757 return builder.llvm.types.items[@intFromEnum(self)];
546758 }
759
760 const IsSizedVisited = std.AutoHashMapUnmanaged(Type, void);
761 fn isSizedVisited(
762 self: Type,
763 visited: *IsSizedVisited,
764 builder: *const Builder,
765 ) Allocator.Error!bool {
766 return switch (self) {
767 .void,
768 .label,
769 .token,
770 .metadata,
771 => false,
772 .half,
773 .bfloat,
774 .float,
775 .double,
776 .fp128,
777 .x86_fp80,
778 .ppc_fp128,
779 .x86_amx,
780 .x86_mmx,
781 .i1,
782 .i8,
783 .i16,
784 .i29,
785 .i32,
786 .i64,
787 .i80,
788 .i128,
789 .ptr,
790 => true,
791 .none => unreachable,
792 _ => {
793 const item = builder.type_items.items[@intFromEnum(self)];
794 return switch (item.tag) {
795 .simple => unreachable,
796 .function,
797 .vararg_function,
798 => false,
799 .integer,
800 .pointer,
801 => true,
802 .target => self.targetLayoutType(builder).isSizedVisited(visited, builder),
803 .vector,
804 .scalable_vector,
805 .small_array,
806 => builder.typeExtraData(Type.Vector, item.data)
807 .child.isSizedVisited(visited, builder),
808 .array => builder.typeExtraData(Type.Array, item.data)
809 .child.isSizedVisited(visited, builder),
810 .structure,
811 .packed_structure,
812 => {
813 if (try visited.fetchPut(builder.gpa, self, {})) |_| return false;
814
815 const extra = builder.typeExtraDataTrail(Type.Structure, item.data);
816 const fields: []const Type = @ptrCast(
817 builder.type_extra.items[extra.end..][0..extra.data.fields_len],
818 );
819 for (fields) |field| {
820 if (field.isVector(builder) and field.vectorKind(builder) == .scalable)
821 return false;
822 if (!try field.isSizedVisited(visited, builder))
823 return false;
824 }
825 return true;
826 },
827 .named_structure => {
828 const body = builder.typeExtraData(Type.NamedStructure, item.data).body;
829 return body != .none and try body.isSizedVisited(visited, builder);
830 },
831 };
832 },
833 };
834 }
547835};
548836
549837pub const Linkage = enum {
......@@ -727,11 +1015,11 @@ pub const AddrSpace = enum(u24) {
7271015
7281016 pub fn format(
7291017 self: AddrSpace,
730 comptime _: []const u8,
1018 comptime prefix: []const u8,
7311019 _: std.fmt.FormatOptions,
7321020 writer: anytype,
7331021 ) @TypeOf(writer).Error!void {
734 if (self != .default) try writer.print(" addrspace({d})", .{@intFromEnum(self)});
1022 if (self != .default) try writer.print("{s} addrspace({d})", .{ prefix, @intFromEnum(self) });
7351023 }
7361024};
7371025
......@@ -785,9 +1073,7 @@ pub const Global = struct {
7851073 addr_space: AddrSpace = .default,
7861074 externally_initialized: ExternallyInitialized = .default,
7871075 type: Type,
788 section: String = .none,
7891076 partition: String = .none,
790 alignment: Alignment = .default,
7911077 kind: union(enum) {
7921078 alias: Alias.Index,
7931079 variable: Variable.Index,
......@@ -824,6 +1110,10 @@ pub const Global = struct {
8241110 return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
8251111 }
8261112
1113 pub fn typeOf(self: Index, builder: *const Builder) Type {
1114 return self.ptrConst(builder).type;
1115 }
1116
8271117 pub fn toConst(self: Index) Constant {
8281118 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));
8291119 }
......@@ -943,11 +1233,19 @@ pub const Global = struct {
9431233
9441234pub const Alias = struct {
9451235 global: Global.Index,
1236 thread_local: ThreadLocal = .default,
1237 init: Constant = .no_init,
9461238
9471239 pub const Index = enum(u32) {
9481240 none = std.math.maxInt(u32),
9491241 _,
9501242
1243 pub fn getAliasee(self: Index, builder: *const Builder) Global.Index {
1244 const aliasee = self.ptrConst(builder).init.getBase(builder);
1245 assert(aliasee != .none);
1246 return aliasee;
1247 }
1248
9511249 pub fn ptr(self: Index, builder: *Builder) *Alias {
9521250 return &builder.aliases.items[@intFromEnum(self)];
9531251 }
......@@ -956,6 +1254,18 @@ pub const Alias = struct {
9561254 return &builder.aliases.items[@intFromEnum(self)];
9571255 }
9581256
1257 pub fn typeOf(self: Index, builder: *const Builder) Type {
1258 return self.ptrConst(builder).global.typeOf(builder);
1259 }
1260
1261 pub fn toConst(self: Index, builder: *const Builder) Constant {
1262 return self.ptrConst(builder).global.toConst();
1263 }
1264
1265 pub fn toValue(self: Index, builder: *const Builder) Value {
1266 return self.toConst(builder).toValue();
1267 }
1268
9591269 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
9601270 return self.ptrConst(builder).global.toLlvm(builder);
9611271 }
......@@ -967,6 +1277,8 @@ pub const Variable = struct {
9671277 thread_local: ThreadLocal = .default,
9681278 mutability: enum { global, constant } = .global,
9691279 init: Constant = .no_init,
1280 section: String = .none,
1281 alignment: Alignment = .default,
9701282
9711283 pub const Index = enum(u32) {
9721284 none = std.math.maxInt(u32),
......@@ -980,6 +1292,18 @@ pub const Variable = struct {
9801292 return &builder.variables.items[@intFromEnum(self)];
9811293 }
9821294
1295 pub fn typeOf(self: Index, builder: *const Builder) Type {
1296 return self.ptrConst(builder).global.typeOf(builder);
1297 }
1298
1299 pub fn toConst(self: Index, builder: *const Builder) Constant {
1300 return self.ptrConst(builder).global.toConst();
1301 }
1302
1303 pub fn toValue(self: Index, builder: *const Builder) Value {
1304 return self.toConst(builder).toValue();
1305 }
1306
9831307 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
9841308 return self.ptrConst(builder).global.toLlvm(builder);
9851309 }
......@@ -988,9 +1312,11 @@ pub const Variable = struct {
9881312
9891313pub const Function = struct {
9901314 global: Global.Index,
1315 section: String = .none,
1316 alignment: Alignment = .default,
9911317 blocks: []const Block = &.{},
9921318 instructions: std.MultiArrayList(Instruction) = .{},
993 names: ?[*]const String = null,
1319 names: [*]const String = &[0]String{},
9941320 metadata: ?[*]const Metadata = null,
9951321 extra: []const u32 = &.{},
9961322
......@@ -1006,6 +1332,18 @@ pub const Function = struct {
10061332 return &builder.functions.items[@intFromEnum(self)];
10071333 }
10081334
1335 pub fn typeOf(self: Index, builder: *const Builder) Type {
1336 return self.ptrConst(builder).global.typeOf(builder);
1337 }
1338
1339 pub fn toConst(self: Index, builder: *const Builder) Constant {
1340 return self.ptrConst(builder).global.toConst();
1341 }
1342
1343 pub fn toValue(self: Index, builder: *const Builder) Value {
1344 return self.toConst(builder).toValue();
1345 }
1346
10091347 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
10101348 return self.ptrConst(builder).global.toLlvm(builder);
10111349 }
......@@ -1021,82 +1359,843 @@ pub const Function = struct {
10211359 tag: Tag,
10221360 data: u32,
10231361
1024 pub const Tag = enum {
1362 pub const Tag = enum(u8) {
1363 add,
1364 @"add nsw",
1365 @"add nuw",
1366 @"add nuw nsw",
1367 addrspacecast,
1368 alloca,
1369 @"alloca inalloca",
1370 @"and",
10251371 arg,
1372 ashr,
1373 @"ashr exact",
1374 bitcast,
10261375 block,
1027 @"ret void",
1376 br,
1377 br_cond,
1378 extractelement,
1379 extractvalue,
1380 fadd,
1381 @"fadd fast",
1382 @"fcmp false",
1383 @"fcmp fast false",
1384 @"fcmp fast oeq",
1385 @"fcmp fast oge",
1386 @"fcmp fast ogt",
1387 @"fcmp fast ole",
1388 @"fcmp fast olt",
1389 @"fcmp fast one",
1390 @"fcmp fast ord",
1391 @"fcmp fast true",
1392 @"fcmp fast ueq",
1393 @"fcmp fast uge",
1394 @"fcmp fast ugt",
1395 @"fcmp fast ule",
1396 @"fcmp fast ult",
1397 @"fcmp fast une",
1398 @"fcmp fast uno",
1399 @"fcmp oeq",
1400 @"fcmp oge",
1401 @"fcmp ogt",
1402 @"fcmp ole",
1403 @"fcmp olt",
1404 @"fcmp one",
1405 @"fcmp ord",
1406 @"fcmp true",
1407 @"fcmp ueq",
1408 @"fcmp uge",
1409 @"fcmp ugt",
1410 @"fcmp ule",
1411 @"fcmp ult",
1412 @"fcmp une",
1413 @"fcmp uno",
1414 fdiv,
1415 @"fdiv fast",
1416 fence,
1417 fmul,
1418 @"fmul fast",
1419 fneg,
1420 @"fneg fast",
1421 fpext,
1422 fptosi,
1423 fptoui,
1424 fptrunc,
1425 frem,
1426 @"frem fast",
1427 fsub,
1428 @"fsub fast",
1429 getelementptr,
1430 @"getelementptr inbounds",
1431 @"icmp eq",
1432 @"icmp ne",
1433 @"icmp sge",
1434 @"icmp sgt",
1435 @"icmp sle",
1436 @"icmp slt",
1437 @"icmp uge",
1438 @"icmp ugt",
1439 @"icmp ule",
1440 @"icmp ult",
1441 insertelement,
1442 insertvalue,
1443 inttoptr,
1444 @"llvm.maxnum.",
1445 @"llvm.minnum.",
1446 @"llvm.sadd.sat.",
1447 @"llvm.smax.",
1448 @"llvm.smin.",
1449 @"llvm.smul.fix.sat.",
1450 @"llvm.sshl.sat.",
1451 @"llvm.ssub.sat.",
1452 @"llvm.uadd.sat.",
1453 @"llvm.umax.",
1454 @"llvm.umin.",
1455 @"llvm.umul.fix.sat.",
1456 @"llvm.ushl.sat.",
1457 @"llvm.usub.sat.",
1458 load,
1459 @"load atomic",
1460 @"load atomic volatile",
1461 @"load volatile",
1462 lshr,
1463 @"lshr exact",
1464 mul,
1465 @"mul nsw",
1466 @"mul nuw",
1467 @"mul nuw nsw",
1468 @"or",
1469 phi,
1470 @"phi fast",
1471 ptrtoint,
10281472 ret,
1473 @"ret void",
1474 sdiv,
1475 @"sdiv exact",
1476 select,
1477 @"select fast",
1478 sext,
1479 shl,
1480 @"shl nsw",
1481 @"shl nuw",
1482 @"shl nuw nsw",
1483 shufflevector,
1484 sitofp,
1485 srem,
1486 store,
1487 @"store atomic",
1488 @"store atomic volatile",
1489 @"store volatile",
1490 sub,
1491 @"sub nsw",
1492 @"sub nuw",
1493 @"sub nuw nsw",
1494 @"switch",
1495 trunc,
1496 udiv,
1497 @"udiv exact",
1498 urem,
1499 uitofp,
1500 unimplemented,
1501 @"unreachable",
1502 va_arg,
1503 xor,
1504 zext,
10291505 };
10301506
10311507 pub const Index = enum(u32) {
1508 none = std.math.maxInt(u31),
10321509 _,
10331510
10341511 pub fn name(self: Instruction.Index, function: *const Function) String {
1035 return if (function.names) |names|
1036 names[@intFromEnum(self)]
1037 else
1038 @enumFromInt(@intFromEnum(self));
1512 return function.names[@intFromEnum(self)];
10391513 }
1040 };
1041 };
1042
1043 pub fn deinit(self: *Function, gpa: Allocator) void {
1044 gpa.free(self.extra);
1045 if (self.metadata) |metadata| gpa.free(metadata[0..self.instructions.len]);
1046 if (self.names) |names| gpa.free(names[0..self.instructions.len]);
1047 self.instructions.deinit(gpa);
1048 self.* = undefined;
1049 }
1050};
1051
1052pub const WipFunction = struct {
1053 builder: *Builder,
1054 function: Function.Index,
1055 llvm: if (build_options.have_llvm) struct {
1056 builder: *llvm.Builder,
1057 blocks: std.ArrayListUnmanaged(*llvm.BasicBlock),
1058 instructions: std.ArrayListUnmanaged(*llvm.Value),
1059 } else void,
1060 cursor: Cursor,
1061 blocks: std.ArrayListUnmanaged(Block),
1062 instructions: std.MultiArrayList(Instruction),
1063 names: std.ArrayListUnmanaged(String),
1064 metadata: std.ArrayListUnmanaged(Metadata),
1065 extra: std.ArrayListUnmanaged(u32),
1066
1067 pub const Cursor = struct { block: Block.Index, instruction: u32 = 0 };
10681514
1069 pub const Block = struct {
1070 name: String,
1071 incoming: u32,
1072 instructions: std.ArrayListUnmanaged(Instruction.Index),
1515 pub fn toValue(self: Instruction.Index) Value {
1516 return @enumFromInt(@intFromEnum(self));
1517 }
10731518
1074 const Index = enum(u32) {
1075 entry,
1076 _,
1519 pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool {
1520 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
1521 .br,
1522 .br_cond,
1523 .ret,
1524 .@"ret void",
1525 .@"unreachable",
1526 => true,
1527 else => false,
1528 };
1529 }
10771530
1078 pub fn toLlvm(self: Index, wip: *const WipFunction) *llvm.BasicBlock {
1079 assert(wip.builder.useLibLlvm());
1080 return wip.llvm.blocks.items[@intFromEnum(self)];
1531 pub fn hasResultWip(self: Instruction.Index, wip: *const WipFunction) bool {
1532 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
1533 .br,
1534 .br_cond,
1535 .fence,
1536 .ret,
1537 .@"ret void",
1538 .store,
1539 .@"store atomic",
1540 .@"store atomic volatile",
1541 .@"store volatile",
1542 .@"unreachable",
1543 => false,
1544 else => true,
1545 };
10811546 }
1082 };
1083 };
10841547
1085 pub const Instruction = Function.Instruction;
1548 pub fn typeOfWip(self: Instruction.Index, wip: *const WipFunction) Type {
1549 const instruction = wip.instructions.get(@intFromEnum(self));
1550 return switch (instruction.tag) {
1551 .add,
1552 .@"add nsw",
1553 .@"add nuw",
1554 .@"add nuw nsw",
1555 .@"and",
1556 .ashr,
1557 .@"ashr exact",
1558 .fadd,
1559 .@"fadd fast",
1560 .fdiv,
1561 .@"fdiv fast",
1562 .fmul,
1563 .@"fmul fast",
1564 .frem,
1565 .@"frem fast",
1566 .fsub,
1567 .@"fsub fast",
1568 .@"llvm.maxnum.",
1569 .@"llvm.minnum.",
1570 .@"llvm.sadd.sat.",
1571 .@"llvm.smax.",
1572 .@"llvm.smin.",
1573 .@"llvm.smul.fix.sat.",
1574 .@"llvm.sshl.sat.",
1575 .@"llvm.ssub.sat.",
1576 .@"llvm.uadd.sat.",
1577 .@"llvm.umax.",
1578 .@"llvm.umin.",
1579 .@"llvm.umul.fix.sat.",
1580 .@"llvm.ushl.sat.",
1581 .@"llvm.usub.sat.",
1582 .lshr,
1583 .@"lshr exact",
1584 .mul,
1585 .@"mul nsw",
1586 .@"mul nuw",
1587 .@"mul nuw nsw",
1588 .@"or",
1589 .sdiv,
1590 .@"sdiv exact",
1591 .shl,
1592 .@"shl nsw",
1593 .@"shl nuw",
1594 .@"shl nuw nsw",
1595 .srem,
1596 .sub,
1597 .@"sub nsw",
1598 .@"sub nuw",
1599 .@"sub nuw nsw",
1600 .udiv,
1601 .@"udiv exact",
1602 .urem,
1603 .xor,
1604 => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip),
1605 .addrspacecast,
1606 .bitcast,
1607 .fpext,
1608 .fptosi,
1609 .fptoui,
1610 .fptrunc,
1611 .inttoptr,
1612 .ptrtoint,
1613 .sext,
1614 .sitofp,
1615 .trunc,
1616 .uitofp,
1617 .zext,
1618 => wip.extraData(Cast, instruction.data).type,
1619 .alloca,
1620 .@"alloca inalloca",
1621 => wip.builder.ptrTypeAssumeCapacity(
1622 wip.extraData(Alloca, instruction.data).info.addr_space,
1623 ),
1624 .arg => wip.function.typeOf(wip.builder)
1625 .functionParameters(wip.builder)[instruction.data],
1626 .block => .label,
1627 .br,
1628 .br_cond,
1629 .fence,
1630 .ret,
1631 .@"ret void",
1632 .store,
1633 .@"store atomic",
1634 .@"store atomic volatile",
1635 .@"store volatile",
1636 .@"switch",
1637 .@"unreachable",
1638 => .none,
1639 .extractelement => wip.extraData(ExtractElement, instruction.data)
1640 .val.typeOfWip(wip).childType(wip.builder),
1641 .extractvalue => {
1642 const extra = wip.extraDataTrail(ExtractValue, instruction.data);
1643 const indices: []const u32 =
1644 wip.extra.items[extra.end..][0..extra.data.indices_len];
1645 return extra.data.val.typeOfWip(wip).childTypeAt(indices, wip.builder);
1646 },
1647 .@"fcmp false",
1648 .@"fcmp fast false",
1649 .@"fcmp fast oeq",
1650 .@"fcmp fast oge",
1651 .@"fcmp fast ogt",
1652 .@"fcmp fast ole",
1653 .@"fcmp fast olt",
1654 .@"fcmp fast one",
1655 .@"fcmp fast ord",
1656 .@"fcmp fast true",
1657 .@"fcmp fast ueq",
1658 .@"fcmp fast uge",
1659 .@"fcmp fast ugt",
1660 .@"fcmp fast ule",
1661 .@"fcmp fast ult",
1662 .@"fcmp fast une",
1663 .@"fcmp fast uno",
1664 .@"fcmp oeq",
1665 .@"fcmp oge",
1666 .@"fcmp ogt",
1667 .@"fcmp ole",
1668 .@"fcmp olt",
1669 .@"fcmp one",
1670 .@"fcmp ord",
1671 .@"fcmp true",
1672 .@"fcmp ueq",
1673 .@"fcmp uge",
1674 .@"fcmp ugt",
1675 .@"fcmp ule",
1676 .@"fcmp ult",
1677 .@"fcmp une",
1678 .@"fcmp uno",
1679 .@"icmp eq",
1680 .@"icmp ne",
1681 .@"icmp sge",
1682 .@"icmp sgt",
1683 .@"icmp sle",
1684 .@"icmp slt",
1685 .@"icmp uge",
1686 .@"icmp ugt",
1687 .@"icmp ule",
1688 .@"icmp ult",
1689 => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip)
1690 .changeScalarAssumeCapacity(.i1, wip.builder),
1691 .fneg,
1692 .@"fneg fast",
1693 => @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip),
1694 .getelementptr,
1695 .@"getelementptr inbounds",
1696 => {
1697 const extra = wip.extraDataTrail(GetElementPtr, instruction.data);
1698 const indices: []const Value =
1699 @ptrCast(wip.extra.items[extra.end..][0..extra.data.indices_len]);
1700 const base_ty = extra.data.base.typeOfWip(wip);
1701 if (!base_ty.isVector(wip.builder)) for (indices) |index| {
1702 const index_ty = index.typeOfWip(wip);
1703 if (!index_ty.isVector(wip.builder)) continue;
1704 return index_ty.changeScalarAssumeCapacity(base_ty, wip.builder);
1705 };
1706 return base_ty;
1707 },
1708 .insertelement => wip.extraData(InsertElement, instruction.data).val.typeOfWip(wip),
1709 .insertvalue => wip.extraData(InsertValue, instruction.data).val.typeOfWip(wip),
1710 .load,
1711 .@"load atomic",
1712 .@"load atomic volatile",
1713 .@"load volatile",
1714 => wip.extraData(Load, instruction.data).type,
1715 .phi,
1716 .@"phi fast",
1717 => wip.extraData(WipPhi, instruction.data).type,
1718 .select,
1719 .@"select fast",
1720 => wip.extraData(Select, instruction.data).lhs.typeOfWip(wip),
1721 .shufflevector => {
1722 const extra = wip.extraData(ShuffleVector, instruction.data);
1723 return extra.lhs.typeOfWip(wip).changeLengthAssumeCapacity(
1724 extra.mask.typeOfWip(wip).vectorLen(wip.builder),
1725 wip.builder,
1726 );
1727 },
1728 .unimplemented => @enumFromInt(instruction.data),
1729 .va_arg => wip.extraData(VaArg, instruction.data).type,
1730 };
1731 }
10861732
1087 pub fn init(builder: *Builder, function: Function.Index) WipFunction {
1088 if (builder.useLibLlvm()) {
1089 const llvm_function = function.toLlvm(builder);
1090 while (llvm_function.getFirstBasicBlock()) |bb| bb.deleteBasicBlock();
1091 }
1092 return .{
1093 .builder = builder,
1094 .function = function,
1095 .llvm = if (builder.useLibLlvm()) .{
1096 .builder = builder.llvm.context.createBuilder(),
1097 .blocks = .{},
1098 .instructions = .{},
1099 } else undefined,
1733 pub fn typeOf(
1734 self: Instruction.Index,
1735 function_index: Function.Index,
1736 builder: *Builder,
1737 ) Type {
1738 const function = function_index.ptrConst(builder);
1739 const instruction = function.instructions.get(@intFromEnum(self));
1740 return switch (instruction.tag) {
1741 .add,
1742 .@"add nsw",
1743 .@"add nuw",
1744 .@"add nuw nsw",
1745 .@"and",
1746 .ashr,
1747 .@"ashr exact",
1748 .fadd,
1749 .@"fadd fast",
1750 .fdiv,
1751 .@"fdiv fast",
1752 .fmul,
1753 .@"fmul fast",
1754 .frem,
1755 .@"frem fast",
1756 .fsub,
1757 .@"fsub fast",
1758 .@"llvm.maxnum.",
1759 .@"llvm.minnum.",
1760 .@"llvm.sadd.sat.",
1761 .@"llvm.smax.",
1762 .@"llvm.smin.",
1763 .@"llvm.smul.fix.sat.",
1764 .@"llvm.sshl.sat.",
1765 .@"llvm.ssub.sat.",
1766 .@"llvm.uadd.sat.",
1767 .@"llvm.umax.",
1768 .@"llvm.umin.",
1769 .@"llvm.umul.fix.sat.",
1770 .@"llvm.ushl.sat.",
1771 .@"llvm.usub.sat.",
1772 .lshr,
1773 .@"lshr exact",
1774 .mul,
1775 .@"mul nsw",
1776 .@"mul nuw",
1777 .@"mul nuw nsw",
1778 .@"or",
1779 .sdiv,
1780 .@"sdiv exact",
1781 .shl,
1782 .@"shl nsw",
1783 .@"shl nuw",
1784 .@"shl nuw nsw",
1785 .srem,
1786 .sub,
1787 .@"sub nsw",
1788 .@"sub nuw",
1789 .@"sub nuw nsw",
1790 .udiv,
1791 .@"udiv exact",
1792 .urem,
1793 .xor,
1794 => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder),
1795 .addrspacecast,
1796 .bitcast,
1797 .fpext,
1798 .fptosi,
1799 .fptoui,
1800 .fptrunc,
1801 .inttoptr,
1802 .ptrtoint,
1803 .sext,
1804 .sitofp,
1805 .trunc,
1806 .uitofp,
1807 .zext,
1808 => function.extraData(Cast, instruction.data).type,
1809 .alloca,
1810 .@"alloca inalloca",
1811 => builder.ptrTypeAssumeCapacity(
1812 function.extraData(Alloca, instruction.data).info.addr_space,
1813 ),
1814 .arg => function.global.typeOf(builder)
1815 .functionParameters(builder)[instruction.data],
1816 .block => .label,
1817 .br,
1818 .br_cond,
1819 .fence,
1820 .ret,
1821 .@"ret void",
1822 .store,
1823 .@"store atomic",
1824 .@"store atomic volatile",
1825 .@"store volatile",
1826 .@"switch",
1827 .@"unreachable",
1828 => .none,
1829 .extractelement => function.extraData(ExtractElement, instruction.data)
1830 .val.typeOf(function_index, builder).childType(builder),
1831 .extractvalue => {
1832 const extra = function.extraDataTrail(ExtractValue, instruction.data);
1833 const indices: []const u32 =
1834 function.extra[extra.end..][0..extra.data.indices_len];
1835 return extra.data.val.typeOf(function_index, builder)
1836 .childTypeAt(indices, builder);
1837 },
1838 .@"fcmp false",
1839 .@"fcmp fast false",
1840 .@"fcmp fast oeq",
1841 .@"fcmp fast oge",
1842 .@"fcmp fast ogt",
1843 .@"fcmp fast ole",
1844 .@"fcmp fast olt",
1845 .@"fcmp fast one",
1846 .@"fcmp fast ord",
1847 .@"fcmp fast true",
1848 .@"fcmp fast ueq",
1849 .@"fcmp fast uge",
1850 .@"fcmp fast ugt",
1851 .@"fcmp fast ule",
1852 .@"fcmp fast ult",
1853 .@"fcmp fast une",
1854 .@"fcmp fast uno",
1855 .@"fcmp oeq",
1856 .@"fcmp oge",
1857 .@"fcmp ogt",
1858 .@"fcmp ole",
1859 .@"fcmp olt",
1860 .@"fcmp one",
1861 .@"fcmp ord",
1862 .@"fcmp true",
1863 .@"fcmp ueq",
1864 .@"fcmp uge",
1865 .@"fcmp ugt",
1866 .@"fcmp ule",
1867 .@"fcmp ult",
1868 .@"fcmp une",
1869 .@"fcmp uno",
1870 .@"icmp eq",
1871 .@"icmp ne",
1872 .@"icmp sge",
1873 .@"icmp sgt",
1874 .@"icmp sle",
1875 .@"icmp slt",
1876 .@"icmp uge",
1877 .@"icmp ugt",
1878 .@"icmp ule",
1879 .@"icmp ult",
1880 => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder)
1881 .changeScalarAssumeCapacity(.i1, builder),
1882 .fneg,
1883 .@"fneg fast",
1884 => @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder),
1885 .getelementptr,
1886 .@"getelementptr inbounds",
1887 => {
1888 const extra = function.extraDataTrail(GetElementPtr, instruction.data);
1889 const indices: []const Value =
1890 @ptrCast(function.extra[extra.end..][0..extra.data.indices_len]);
1891 const base_ty = extra.data.base.typeOf(function_index, builder);
1892 if (!base_ty.isVector(builder)) for (indices) |index| {
1893 const index_ty = index.typeOf(function_index, builder);
1894 if (!index_ty.isVector(builder)) continue;
1895 return index_ty.changeScalarAssumeCapacity(base_ty, builder);
1896 };
1897 return base_ty;
1898 },
1899 .insertelement => function.extraData(InsertElement, instruction.data)
1900 .val.typeOf(function_index, builder),
1901 .insertvalue => function.extraData(InsertValue, instruction.data)
1902 .val.typeOf(function_index, builder),
1903 .load,
1904 .@"load atomic",
1905 .@"load atomic volatile",
1906 .@"load volatile",
1907 => function.extraData(Load, instruction.data).type,
1908 .phi,
1909 .@"phi fast",
1910 => {
1911 const extra = function.extraDataTrail(Phi, instruction.data);
1912 const incoming_vals: []const Value =
1913 @ptrCast(function.extra[extra.end..][0..extra.data.incoming_len]);
1914 return incoming_vals[0].typeOf(function_index, builder);
1915 },
1916 .select,
1917 .@"select fast",
1918 => function.extraData(Select, instruction.data).lhs.typeOf(function_index, builder),
1919 .shufflevector => {
1920 const extra = function.extraData(ShuffleVector, instruction.data);
1921 return extra.lhs.typeOf(function_index, builder).changeLengthAssumeCapacity(
1922 extra.mask.typeOf(function_index, builder).vectorLen(builder),
1923 builder,
1924 );
1925 },
1926 .unimplemented => @enumFromInt(instruction.data),
1927 .va_arg => function.extraData(VaArg, instruction.data).type,
1928 };
1929 }
1930
1931 const FormatData = struct {
1932 instruction: Instruction.Index,
1933 function: Function.Index,
1934 builder: *Builder,
1935 };
1936 fn format(
1937 data: FormatData,
1938 comptime fmt_str: []const u8,
1939 _: std.fmt.FormatOptions,
1940 writer: anytype,
1941 ) @TypeOf(writer).Error!void {
1942 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
1943 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1944 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
1945 if (data.instruction == .none) return;
1946 try writer.writeByte(',');
1947 }
1948 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
1949 if (data.instruction == .none) return;
1950 try writer.writeByte(' ');
1951 }
1952 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) try writer.print(
1953 "{%} ",
1954 .{data.instruction.typeOf(data.function, data.builder).fmt(data.builder)},
1955 );
1956 assert(data.instruction != .none);
1957 try writer.print("%{}", .{
1958 data.instruction.name(data.function.ptrConst(data.builder)).fmt(data.builder),
1959 });
1960 }
1961 pub fn fmt(
1962 self: Instruction.Index,
1963 function: Function.Index,
1964 builder: *Builder,
1965 ) std.fmt.Formatter(format) {
1966 return .{ .data = .{ .instruction = self, .function = function, .builder = builder } };
1967 }
1968
1969 pub fn toLlvm(self: Instruction.Index, wip: *const WipFunction) *llvm.Value {
1970 assert(wip.builder.useLibLlvm());
1971 return wip.llvm.instructions.items[@intFromEnum(self)];
1972 }
1973
1974 fn llvmName(self: Instruction.Index, wip: *const WipFunction) [*:0]const u8 {
1975 return if (wip.builder.strip)
1976 ""
1977 else
1978 wip.names.items[@intFromEnum(self)].toSlice(wip.builder).?;
1979 }
1980 };
1981
1982 pub const ExtraIndex = u32;
1983
1984 pub const BrCond = struct {
1985 cond: Value,
1986 then: Block.Index,
1987 @"else": Block.Index,
1988 };
1989
1990 pub const Switch = struct {
1991 val: Value,
1992 default: Block.Index,
1993 cases_len: u32,
1994 //case_vals: [cases_len]Constant,
1995 //case_blocks: [cases_len]Block.Index,
1996 };
1997
1998 pub const Binary = struct {
1999 lhs: Value,
2000 rhs: Value,
2001 };
2002
2003 pub const ExtractElement = struct {
2004 val: Value,
2005 index: Value,
2006 };
2007
2008 pub const InsertElement = struct {
2009 val: Value,
2010 elem: Value,
2011 index: Value,
2012 };
2013
2014 pub const ShuffleVector = struct {
2015 lhs: Value,
2016 rhs: Value,
2017 mask: Value,
2018 };
2019
2020 pub const ExtractValue = struct {
2021 val: Value,
2022 indices_len: u32,
2023 //indices: [indices_len]u32,
2024 };
2025
2026 pub const InsertValue = struct {
2027 val: Value,
2028 elem: Value,
2029 indices_len: u32,
2030 //indices: [indices_len]u32,
2031 };
2032
2033 pub const Alloca = struct {
2034 type: Type,
2035 len: Value,
2036 info: Info,
2037
2038 pub const Kind = enum { normal, inalloca };
2039 pub const Info = packed struct(u32) {
2040 alignment: Alignment,
2041 addr_space: AddrSpace,
2042 _: u2 = undefined,
2043 };
2044 };
2045
2046 pub const Load = struct {
2047 type: Type,
2048 ptr: Value,
2049 info: MemoryAccessInfo,
2050 };
2051
2052 pub const Store = struct {
2053 val: Value,
2054 ptr: Value,
2055 info: MemoryAccessInfo,
2056 };
2057
2058 pub const GetElementPtr = struct {
2059 type: Type,
2060 base: Value,
2061 indices_len: u32,
2062 //indices: [indices_len]Value,
2063
2064 pub const Kind = Constant.GetElementPtr.Kind;
2065 };
2066
2067 pub const Cast = struct {
2068 val: Value,
2069 type: Type,
2070
2071 pub const Signedness = Constant.Cast.Signedness;
2072 };
2073
2074 pub const WipPhi = struct {
2075 type: Type,
2076 //incoming_vals: [block.incoming]Value,
2077 //incoming_blocks: [block.incoming]Block.Index,
2078 };
2079
2080 pub const Phi = struct {
2081 incoming_len: u32,
2082 //incoming_vals: [incoming_len]Value,
2083 //incoming_blocks: [incoming_len]Block.Index,
2084 };
2085
2086 pub const Select = struct {
2087 cond: Value,
2088 lhs: Value,
2089 rhs: Value,
2090 };
2091
2092 pub const VaArg = struct {
2093 list: Value,
2094 type: Type,
2095 };
2096 };
2097
2098 pub fn deinit(self: *Function, gpa: Allocator) void {
2099 gpa.free(self.extra);
2100 if (self.metadata) |metadata| gpa.free(metadata[0..self.instructions.len]);
2101 gpa.free(self.names[0..self.instructions.len]);
2102 self.instructions.deinit(gpa);
2103 self.* = undefined;
2104 }
2105
2106 pub fn arg(self: *const Function, index: u32) Value {
2107 const argument = self.instructions.get(index);
2108 assert(argument.tag == .arg);
2109 assert(argument.data == index);
2110
2111 const argument_index: Instruction.Index = @enumFromInt(index);
2112 return argument_index.toValue();
2113 }
2114
2115 fn extraDataTrail(
2116 self: *const Function,
2117 comptime T: type,
2118 index: Instruction.ExtraIndex,
2119 ) struct { data: T, end: Instruction.ExtraIndex } {
2120 var result: T = undefined;
2121 const fields = @typeInfo(T).Struct.fields;
2122 inline for (fields, self.extra[index..][0..fields.len]) |field, value|
2123 @field(result, field.name) = switch (field.type) {
2124 u32 => value,
2125 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),
2126 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
2127 else => @compileError("bad field type: " ++ @typeName(field.type)),
2128 };
2129 return .{ .data = result, .end = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) };
2130 }
2131
2132 fn extraData(self: *const Function, comptime T: type, index: Instruction.ExtraIndex) T {
2133 return self.extraDataTrail(T, index).data;
2134 }
2135};
2136
2137pub const WipFunction = struct {
2138 builder: *Builder,
2139 function: Function.Index,
2140 llvm: if (build_options.have_llvm) struct {
2141 builder: *llvm.Builder,
2142 blocks: std.ArrayListUnmanaged(*llvm.BasicBlock),
2143 instructions: std.ArrayListUnmanaged(*llvm.Value),
2144 } else void,
2145 cursor: Cursor,
2146 blocks: std.ArrayListUnmanaged(Block),
2147 instructions: std.MultiArrayList(Instruction),
2148 names: std.ArrayListUnmanaged(String),
2149 metadata: std.ArrayListUnmanaged(Metadata),
2150 extra: std.ArrayListUnmanaged(u32),
2151
2152 pub const Cursor = struct { block: Block.Index, instruction: u32 = 0 };
2153
2154 pub const Block = struct {
2155 name: String,
2156 incoming: u32,
2157 branches: u32 = 0,
2158 instructions: std.ArrayListUnmanaged(Instruction.Index),
2159
2160 const Index = enum(u32) {
2161 entry,
2162 _,
2163
2164 pub fn ptr(self: Index, wip: *WipFunction) *Block {
2165 return &wip.blocks.items[@intFromEnum(self)];
2166 }
2167
2168 pub fn ptrConst(self: Index, wip: *const WipFunction) *const Block {
2169 return &wip.blocks.items[@intFromEnum(self)];
2170 }
2171
2172 pub fn toInst(self: Index, function: *const Function) Instruction.Index {
2173 return function.blocks[@intFromEnum(self)].instruction;
2174 }
2175
2176 pub fn toLlvm(self: Index, wip: *const WipFunction) *llvm.BasicBlock {
2177 assert(wip.builder.useLibLlvm());
2178 return wip.llvm.blocks.items[@intFromEnum(self)];
2179 }
2180 };
2181 };
2182
2183 pub const Instruction = Function.Instruction;
2184
2185 pub fn init(builder: *Builder, function: Function.Index) Allocator.Error!WipFunction {
2186 if (builder.useLibLlvm()) {
2187 const llvm_function = function.toLlvm(builder);
2188 while (llvm_function.getFirstBasicBlock()) |bb| bb.deleteBasicBlock();
2189 }
2190
2191 var self = WipFunction{
2192 .builder = builder,
2193 .function = function,
2194 .llvm = if (builder.useLibLlvm()) .{
2195 .builder = builder.llvm.context.createBuilder(),
2196 .blocks = .{},
2197 .instructions = .{},
2198 } else undefined,
11002199 .cursor = undefined,
11012200 .blocks = .{},
11022201 .instructions = .{},
......@@ -1104,102 +2203,1447 @@ pub const WipFunction = struct {
11042203 .metadata = .{},
11052204 .extra = .{},
11062205 };
2206 errdefer self.deinit();
2207
2208 const params_len = function.typeOf(self.builder).functionParameters(self.builder).len;
2209 try self.ensureUnusedExtraCapacity(params_len, NoExtra, 0);
2210 try self.instructions.ensureUnusedCapacity(self.builder.gpa, params_len);
2211 if (!self.builder.strip) try self.names.ensureUnusedCapacity(self.builder.gpa, params_len);
2212 if (self.builder.useLibLlvm())
2213 try self.llvm.instructions.ensureUnusedCapacity(self.builder.gpa, params_len);
2214 for (0..params_len) |param_index| {
2215 self.instructions.appendAssumeCapacity(.{ .tag = .arg, .data = @intCast(param_index) });
2216 if (!self.builder.strip) self.names.appendAssumeCapacity(.empty); // TODO: param names
2217 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2218 function.toLlvm(self.builder).getParam(@intCast(param_index)),
2219 );
2220 }
2221
2222 return self;
11072223 }
11082224
1109 pub fn block(self: *WipFunction, name: []const u8) Allocator.Error!Block.Index {
2225 pub fn arg(self: *const WipFunction, index: u32) Value {
2226 const argument = self.instructions.get(index);
2227 assert(argument.tag == .arg);
2228 assert(argument.data == index);
2229
2230 const argument_index: Instruction.Index = @enumFromInt(index);
2231 return argument_index.toValue();
2232 }
2233
2234 pub fn block(self: *WipFunction, incoming: u32, name: []const u8) Allocator.Error!Block.Index {
11102235 try self.blocks.ensureUnusedCapacity(self.builder.gpa, 1);
11112236 if (self.builder.useLibLlvm()) try self.llvm.blocks.ensureUnusedCapacity(self.builder.gpa, 1);
11122237
1113 const index: Block.Index = @enumFromInt(self.blocks.items.len);
1114 const final_name = if (self.builder.strip) .empty else try self.builder.string(name);
1115 self.blocks.appendAssumeCapacity(.{ .name = final_name, .incoming = 0, .instructions = .{} });
1116 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(
1117 self.builder.llvm.context.appendBasicBlock(
1118 self.function.toLlvm(self.builder),
1119 final_name.toSlice(self.builder).?,
2238 const index: Block.Index = @enumFromInt(self.blocks.items.len);
2239 const final_name = if (self.builder.strip) .empty else try self.builder.string(name);
2240 self.blocks.appendAssumeCapacity(.{
2241 .name = final_name,
2242 .incoming = incoming,
2243 .instructions = .{},
2244 });
2245 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(
2246 self.builder.llvm.context.appendBasicBlock(
2247 self.function.toLlvm(self.builder),
2248 final_name.toSlice(self.builder).?,
2249 ),
2250 );
2251 return index;
2252 }
2253
2254 pub fn ret(self: *WipFunction, val: Value) Allocator.Error!Instruction.Index {
2255 assert(val.typeOfWip(self) == self.function.typeOf(self.builder).functionReturn(self.builder));
2256 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2257 const instruction = try self.addInst(null, .{ .tag = .ret, .data = @intFromEnum(val) });
2258 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2259 self.llvm.builder.buildRet(val.toLlvm(self)),
2260 );
2261 return instruction;
2262 }
2263
2264 pub fn retVoid(self: *WipFunction) Allocator.Error!Instruction.Index {
2265 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2266 const instruction = try self.addInst(null, .{ .tag = .@"ret void", .data = undefined });
2267 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2268 self.llvm.builder.buildRetVoid(),
2269 );
2270 return instruction;
2271 }
2272
2273 pub fn br(self: *WipFunction, dest: Block.Index) Allocator.Error!Instruction.Index {
2274 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2275 const instruction = try self.addInst(null, .{ .tag = .br, .data = @intFromEnum(dest) });
2276 dest.ptr(self).branches += 1;
2277 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2278 self.llvm.builder.buildBr(dest.toLlvm(self)),
2279 );
2280 return instruction;
2281 }
2282
2283 pub fn brCond(
2284 self: *WipFunction,
2285 cond: Value,
2286 then: Block.Index,
2287 @"else": Block.Index,
2288 ) Allocator.Error!Instruction.Index {
2289 assert(cond.typeOfWip(self) == .i1);
2290 try self.ensureUnusedExtraCapacity(1, Instruction.BrCond, 0);
2291 const instruction = try self.addInst(null, .{
2292 .tag = .br_cond,
2293 .data = self.addExtraAssumeCapacity(Instruction.BrCond{
2294 .cond = cond,
2295 .then = then,
2296 .@"else" = @"else",
2297 }),
2298 });
2299 then.ptr(self).branches += 1;
2300 @"else".ptr(self).branches += 1;
2301 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2302 self.llvm.builder.buildCondBr(cond.toLlvm(self), then.toLlvm(self), @"else".toLlvm(self)),
2303 );
2304 return instruction;
2305 }
2306
2307 pub const WipSwitch = struct {
2308 index: u32,
2309 instruction: Instruction.Index,
2310
2311 pub fn addCase(
2312 self: *WipSwitch,
2313 val: Constant,
2314 dest: Block.Index,
2315 wip: *WipFunction,
2316 ) Allocator.Error!void {
2317 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
2318 const extra = wip.extraDataTrail(Instruction.Switch, instruction.data);
2319 const case_vals: []Constant =
2320 @ptrCast(wip.extra.items[extra.end..][0..extra.data.cases_len]);
2321 const case_dests: []Block.Index =
2322 @ptrCast(wip.extra.items[extra.end + extra.data.cases_len ..][0..extra.data.cases_len]);
2323 assert(val.typeOf(wip.builder) == extra.data.val.typeOfWip(wip));
2324 case_vals[self.index] = val;
2325 case_dests[self.index] = dest;
2326 self.index += 1;
2327 dest.ptr(wip).branches += 1;
2328 if (wip.builder.useLibLlvm())
2329 self.instruction.toLlvm(wip).addCase(val.toLlvm(wip.builder), dest.toLlvm(wip));
2330 }
2331
2332 pub fn finish(self: WipSwitch, wip: *WipFunction) void {
2333 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
2334 const extra = wip.extraData(Instruction.Switch, instruction.data);
2335 assert(self.index == extra.cases_len);
2336 }
2337 };
2338
2339 pub fn @"switch"(
2340 self: *WipFunction,
2341 val: Value,
2342 default: Block.Index,
2343 cases_len: u32,
2344 ) Allocator.Error!WipSwitch {
2345 try self.ensureUnusedExtraCapacity(1, Instruction.Switch, cases_len * 2);
2346 const instruction = try self.addInst(null, .{
2347 .tag = .@"switch",
2348 .data = self.addExtraAssumeCapacity(Instruction.Switch{
2349 .val = val,
2350 .default = default,
2351 .cases_len = cases_len,
2352 }),
2353 });
2354 _ = self.extra.addManyAsSliceAssumeCapacity(cases_len * 2);
2355 default.ptr(self).branches += 1;
2356 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2357 self.llvm.builder.buildSwitch(val.toLlvm(self), default.toLlvm(self), @intCast(cases_len)),
2358 );
2359 return .{ .index = 0, .instruction = instruction };
2360 }
2361
2362 pub fn @"unreachable"(self: *WipFunction) Allocator.Error!Instruction.Index {
2363 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2364 const instruction = try self.addInst(null, .{ .tag = .@"unreachable", .data = undefined });
2365 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2366 self.llvm.builder.buildUnreachable(),
2367 );
2368 return instruction;
2369 }
2370
2371 pub fn un(
2372 self: *WipFunction,
2373 tag: Instruction.Tag,
2374 val: Value,
2375 name: []const u8,
2376 ) Allocator.Error!Value {
2377 switch (tag) {
2378 .fneg,
2379 .@"fneg fast",
2380 => assert(val.typeOfWip(self).scalarType(self.builder).isFloatingPoint()),
2381 else => unreachable,
2382 }
2383 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2384 const instruction = try self.addInst(name, .{ .tag = tag, .data = @intFromEnum(val) });
2385 if (self.builder.useLibLlvm()) {
2386 switch (tag) {
2387 .fneg => self.llvm.builder.setFastMath(false),
2388 .@"fneg fast" => self.llvm.builder.setFastMath(true),
2389 else => unreachable,
2390 }
2391 self.llvm.instructions.appendAssumeCapacity(switch (tag) {
2392 .fneg, .@"fneg fast" => &llvm.Builder.buildFNeg,
2393 else => unreachable,
2394 }(self.llvm.builder, val.toLlvm(self), instruction.llvmName(self)));
2395 }
2396 return instruction.toValue();
2397 }
2398
2399 pub fn not(self: *WipFunction, val: Value, name: []const u8) Allocator.Error!Value {
2400 const ty = val.typeOfWip(self);
2401 const all_ones = try self.builder.splatValue(
2402 ty,
2403 try self.builder.intConst(ty.scalarType(self.builder), -1),
2404 );
2405 return self.bin(.xor, val, all_ones, name);
2406 }
2407
2408 pub fn neg(self: *WipFunction, val: Value, name: []const u8) Allocator.Error!Value {
2409 return self.bin(.sub, try self.builder.zeroInitValue(val.typeOfWip(self)), val, name);
2410 }
2411
2412 pub fn bin(
2413 self: *WipFunction,
2414 tag: Instruction.Tag,
2415 lhs: Value,
2416 rhs: Value,
2417 name: []const u8,
2418 ) Allocator.Error!Value {
2419 switch (tag) {
2420 .add,
2421 .@"add nsw",
2422 .@"add nuw",
2423 .@"and",
2424 .ashr,
2425 .@"ashr exact",
2426 .fadd,
2427 .@"fadd fast",
2428 .fdiv,
2429 .@"fdiv fast",
2430 .fmul,
2431 .@"fmul fast",
2432 .frem,
2433 .@"frem fast",
2434 .fsub,
2435 .@"fsub fast",
2436 .@"llvm.maxnum.",
2437 .@"llvm.minnum.",
2438 .@"llvm.sadd.sat.",
2439 .@"llvm.smax.",
2440 .@"llvm.smin.",
2441 .@"llvm.smul.fix.sat.",
2442 .@"llvm.sshl.sat.",
2443 .@"llvm.ssub.sat.",
2444 .@"llvm.uadd.sat.",
2445 .@"llvm.umax.",
2446 .@"llvm.umin.",
2447 .@"llvm.umul.fix.sat.",
2448 .@"llvm.ushl.sat.",
2449 .@"llvm.usub.sat.",
2450 .lshr,
2451 .@"lshr exact",
2452 .mul,
2453 .@"mul nsw",
2454 .@"mul nuw",
2455 .@"or",
2456 .sdiv,
2457 .@"sdiv exact",
2458 .shl,
2459 .@"shl nsw",
2460 .@"shl nuw",
2461 .srem,
2462 .sub,
2463 .@"sub nsw",
2464 .@"sub nuw",
2465 .udiv,
2466 .@"udiv exact",
2467 .urem,
2468 .xor,
2469 => assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
2470 else => unreachable,
2471 }
2472 try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
2473 const instruction = try self.addInst(name, .{
2474 .tag = tag,
2475 .data = self.addExtraAssumeCapacity(Instruction.Binary{ .lhs = lhs, .rhs = rhs }),
2476 });
2477 if (self.builder.useLibLlvm()) {
2478 switch (tag) {
2479 .fadd,
2480 .fdiv,
2481 .fmul,
2482 .frem,
2483 .fsub,
2484 => self.llvm.builder.setFastMath(false),
2485 .@"fadd fast",
2486 .@"fdiv fast",
2487 .@"fmul fast",
2488 .@"frem fast",
2489 .@"fsub fast",
2490 => self.llvm.builder.setFastMath(true),
2491 else => {},
2492 }
2493 self.llvm.instructions.appendAssumeCapacity(switch (tag) {
2494 .add => &llvm.Builder.buildAdd,
2495 .@"add nsw" => &llvm.Builder.buildNSWAdd,
2496 .@"add nuw" => &llvm.Builder.buildNUWAdd,
2497 .@"and" => &llvm.Builder.buildAnd,
2498 .ashr => &llvm.Builder.buildAShr,
2499 .@"ashr exact" => &llvm.Builder.buildAShrExact,
2500 .fadd, .@"fadd fast" => &llvm.Builder.buildFAdd,
2501 .fdiv, .@"fdiv fast" => &llvm.Builder.buildFDiv,
2502 .fmul, .@"fmul fast" => &llvm.Builder.buildFMul,
2503 .frem, .@"frem fast" => &llvm.Builder.buildFRem,
2504 .fsub, .@"fsub fast" => &llvm.Builder.buildFSub,
2505 .@"llvm.maxnum." => &llvm.Builder.buildMaxNum,
2506 .@"llvm.minnum." => &llvm.Builder.buildMinNum,
2507 .@"llvm.sadd.sat." => &llvm.Builder.buildSAddSat,
2508 .@"llvm.smax." => &llvm.Builder.buildSMax,
2509 .@"llvm.smin." => &llvm.Builder.buildSMin,
2510 .@"llvm.smul.fix.sat." => &llvm.Builder.buildSMulFixSat,
2511 .@"llvm.sshl.sat." => &llvm.Builder.buildSShlSat,
2512 .@"llvm.ssub.sat." => &llvm.Builder.buildSSubSat,
2513 .@"llvm.uadd.sat." => &llvm.Builder.buildUAddSat,
2514 .@"llvm.umax." => &llvm.Builder.buildUMax,
2515 .@"llvm.umin." => &llvm.Builder.buildUMin,
2516 .@"llvm.umul.fix.sat." => &llvm.Builder.buildUMulFixSat,
2517 .@"llvm.ushl.sat." => &llvm.Builder.buildUShlSat,
2518 .@"llvm.usub.sat." => &llvm.Builder.buildUSubSat,
2519 .lshr => &llvm.Builder.buildLShr,
2520 .@"lshr exact" => &llvm.Builder.buildLShrExact,
2521 .mul => &llvm.Builder.buildMul,
2522 .@"mul nsw" => &llvm.Builder.buildNSWMul,
2523 .@"mul nuw" => &llvm.Builder.buildNUWMul,
2524 .@"or" => &llvm.Builder.buildOr,
2525 .sdiv => &llvm.Builder.buildSDiv,
2526 .@"sdiv exact" => &llvm.Builder.buildExactSDiv,
2527 .shl => &llvm.Builder.buildShl,
2528 .@"shl nsw" => &llvm.Builder.buildNSWShl,
2529 .@"shl nuw" => &llvm.Builder.buildNUWShl,
2530 .srem => &llvm.Builder.buildSRem,
2531 .sub => &llvm.Builder.buildSub,
2532 .@"sub nsw" => &llvm.Builder.buildNSWSub,
2533 .@"sub nuw" => &llvm.Builder.buildNUWSub,
2534 .udiv => &llvm.Builder.buildUDiv,
2535 .@"udiv exact" => &llvm.Builder.buildExactUDiv,
2536 .urem => &llvm.Builder.buildURem,
2537 .xor => &llvm.Builder.buildXor,
2538 else => unreachable,
2539 }(self.llvm.builder, lhs.toLlvm(self), rhs.toLlvm(self), instruction.llvmName(self)));
2540 }
2541 return instruction.toValue();
2542 }
2543
2544 pub fn extractElement(
2545 self: *WipFunction,
2546 val: Value,
2547 index: Value,
2548 name: []const u8,
2549 ) Allocator.Error!Value {
2550 assert(val.typeOfWip(self).isVector(self.builder));
2551 assert(index.typeOfWip(self).isInteger(self.builder));
2552 try self.ensureUnusedExtraCapacity(1, Instruction.ExtractElement, 0);
2553 const instruction = try self.addInst(name, .{
2554 .tag = .extractelement,
2555 .data = self.addExtraAssumeCapacity(Instruction.ExtractElement{
2556 .val = val,
2557 .index = index,
2558 }),
2559 });
2560 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2561 self.llvm.builder.buildExtractElement(
2562 val.toLlvm(self),
2563 index.toLlvm(self),
2564 instruction.llvmName(self),
2565 ),
2566 );
2567 return instruction.toValue();
2568 }
2569
2570 pub fn insertElement(
2571 self: *WipFunction,
2572 val: Value,
2573 elem: Value,
2574 index: Value,
2575 name: []const u8,
2576 ) Allocator.Error!Value {
2577 assert(val.typeOfWip(self).scalarType(self.builder) == elem.typeOfWip(self));
2578 assert(index.typeOfWip(self).isInteger(self.builder));
2579 try self.ensureUnusedExtraCapacity(1, Instruction.InsertElement, 0);
2580 const instruction = try self.addInst(name, .{
2581 .tag = .insertelement,
2582 .data = self.addExtraAssumeCapacity(Instruction.InsertElement{
2583 .val = val,
2584 .elem = elem,
2585 .index = index,
2586 }),
2587 });
2588 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2589 self.llvm.builder.buildInsertElement(
2590 val.toLlvm(self),
2591 elem.toLlvm(self),
2592 index.toLlvm(self),
2593 instruction.llvmName(self),
2594 ),
2595 );
2596 return instruction.toValue();
2597 }
2598
2599 pub fn shuffleVector(
2600 self: *WipFunction,
2601 lhs: Value,
2602 rhs: Value,
2603 mask: Value,
2604 name: []const u8,
2605 ) Allocator.Error!Value {
2606 assert(lhs.typeOfWip(self).isVector(self.builder));
2607 assert(lhs.typeOfWip(self) == rhs.typeOfWip(self));
2608 assert(mask.typeOfWip(self).scalarType(self.builder).isInteger(self.builder));
2609 _ = try self.ensureUnusedExtraCapacity(1, Instruction.ShuffleVector, 0);
2610 const instruction = try self.addInst(name, .{
2611 .tag = .shufflevector,
2612 .data = self.addExtraAssumeCapacity(Instruction.ShuffleVector{
2613 .lhs = lhs,
2614 .rhs = rhs,
2615 .mask = mask,
2616 }),
2617 });
2618 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2619 self.llvm.builder.buildShuffleVector(
2620 lhs.toLlvm(self),
2621 rhs.toLlvm(self),
2622 mask.toLlvm(self),
2623 instruction.llvmName(self),
2624 ),
2625 );
2626 return instruction.toValue();
2627 }
2628
2629 pub fn splatVector(
2630 self: *WipFunction,
2631 ty: Type,
2632 elem: Value,
2633 name: []const u8,
2634 ) Allocator.Error!Value {
2635 const scalar_ty = try ty.changeLength(1, self.builder);
2636 const mask_ty = try ty.changeScalar(.i32, self.builder);
2637 const zero = try self.builder.intConst(.i32, 0);
2638 const poison = try self.builder.poisonValue(scalar_ty);
2639 const mask = try self.builder.splatValue(mask_ty, zero);
2640 const scalar = try self.insertElement(poison, elem, zero.toValue(), name);
2641 return self.shuffleVector(scalar, poison, mask, name);
2642 }
2643
2644 pub fn extractValue(
2645 self: *WipFunction,
2646 val: Value,
2647 indices: []const u32,
2648 name: []const u8,
2649 ) Allocator.Error!Value {
2650 assert(indices.len > 0);
2651 _ = val.typeOfWip(self).childTypeAt(indices, self.builder);
2652 try self.ensureUnusedExtraCapacity(1, Instruction.ExtractValue, indices.len);
2653 const instruction = try self.addInst(name, .{
2654 .tag = .extractvalue,
2655 .data = self.addExtraAssumeCapacity(Instruction.ExtractValue{
2656 .val = val,
2657 .indices_len = @intCast(indices.len),
2658 }),
2659 });
2660 self.extra.appendSliceAssumeCapacity(indices);
2661 if (self.builder.useLibLlvm()) {
2662 const llvm_name = instruction.llvmName(self);
2663 var cur = val.toLlvm(self);
2664 for (indices) |index|
2665 cur = self.llvm.builder.buildExtractValue(cur, @intCast(index), llvm_name);
2666 self.llvm.instructions.appendAssumeCapacity(cur);
2667 }
2668 return instruction.toValue();
2669 }
2670
2671 pub fn insertValue(
2672 self: *WipFunction,
2673 val: Value,
2674 elem: Value,
2675 indices: []const u32,
2676 name: []const u8,
2677 ) Allocator.Error!Value {
2678 assert(indices.len > 0);
2679 assert(val.typeOfWip(self).childTypeAt(indices, self.builder) == elem.typeOfWip(self));
2680 try self.ensureUnusedExtraCapacity(1, Instruction.InsertValue, indices.len);
2681 const instruction = try self.addInst(name, .{
2682 .tag = .insertvalue,
2683 .data = self.addExtraAssumeCapacity(Instruction.InsertValue{
2684 .val = val,
2685 .elem = elem,
2686 .indices_len = @intCast(indices.len),
2687 }),
2688 });
2689 self.extra.appendSliceAssumeCapacity(indices);
2690 if (self.builder.useLibLlvm()) {
2691 const ExpectedContents = [expected_gep_indices_len]*llvm.Value;
2692 var stack align(@alignOf(ExpectedContents)) =
2693 std.heap.stackFallback(@sizeOf(ExpectedContents), self.builder.gpa);
2694 const allocator = stack.get();
2695
2696 const llvm_name = instruction.llvmName(self);
2697 const llvm_vals = try allocator.alloc(*llvm.Value, indices.len);
2698 defer allocator.free(llvm_vals);
2699 llvm_vals[0] = val.toLlvm(self);
2700 for (llvm_vals[1..], llvm_vals[0 .. llvm_vals.len - 1], indices[0 .. indices.len - 1]) |
2701 *cur_val,
2702 prev_val,
2703 index,
2704 | cur_val.* = self.llvm.builder.buildExtractValue(prev_val, @intCast(index), llvm_name);
2705
2706 var depth: usize = llvm_vals.len;
2707 var cur = elem.toLlvm(self);
2708 while (depth > 0) {
2709 depth -= 1;
2710 cur = self.llvm.builder.buildInsertValue(
2711 llvm_vals[depth],
2712 cur,
2713 @intCast(indices[depth]),
2714 llvm_name,
2715 );
2716 }
2717 self.llvm.instructions.appendAssumeCapacity(cur);
2718 }
2719 return instruction.toValue();
2720 }
2721
2722 pub fn buildAggregate(
2723 self: *WipFunction,
2724 ty: Type,
2725 elems: []const Value,
2726 name: []const u8,
2727 ) Allocator.Error!Value {
2728 assert(ty.aggregateLen(self.builder) == elems.len);
2729 var cur = try self.builder.poisonValue(ty);
2730 for (elems, 0..) |elem, index|
2731 cur = try self.insertValue(cur, elem, &[_]u32{@intCast(index)}, name);
2732 return cur;
2733 }
2734
2735 pub fn alloca(
2736 self: *WipFunction,
2737 kind: Instruction.Alloca.Kind,
2738 ty: Type,
2739 len: Value,
2740 alignment: Alignment,
2741 addr_space: AddrSpace,
2742 name: []const u8,
2743 ) Allocator.Error!Value {
2744 assert(len == .none or len.typeOfWip(self).isInteger(self.builder));
2745 _ = try self.builder.ptrType(addr_space);
2746 try self.ensureUnusedExtraCapacity(1, Instruction.Alloca, 0);
2747 const instruction = try self.addInst(name, .{
2748 .tag = switch (kind) {
2749 .normal => .alloca,
2750 .inalloca => .@"alloca inalloca",
2751 },
2752 .data = self.addExtraAssumeCapacity(Instruction.Alloca{
2753 .type = ty,
2754 .len = len,
2755 .info = .{ .alignment = alignment, .addr_space = addr_space },
2756 }),
2757 });
2758 if (self.builder.useLibLlvm()) {
2759 const llvm_instruction = self.llvm.builder.buildAllocaInAddressSpace(
2760 ty.toLlvm(self.builder),
2761 @intFromEnum(addr_space),
2762 instruction.llvmName(self),
2763 );
2764 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
2765 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
2766 }
2767 return instruction.toValue();
2768 }
2769
2770 pub fn load(
2771 self: *WipFunction,
2772 kind: MemoryAccessKind,
2773 ty: Type,
2774 ptr: Value,
2775 alignment: Alignment,
2776 name: []const u8,
2777 ) Allocator.Error!Value {
2778 return self.loadAtomic(kind, ty, ptr, .system, .none, alignment, name);
2779 }
2780
2781 pub fn loadAtomic(
2782 self: *WipFunction,
2783 kind: MemoryAccessKind,
2784 ty: Type,
2785 ptr: Value,
2786 scope: SyncScope,
2787 ordering: AtomicOrdering,
2788 alignment: Alignment,
2789 name: []const u8,
2790 ) Allocator.Error!Value {
2791 assert(ptr.typeOfWip(self).isPointer(self.builder));
2792 const final_scope = switch (ordering) {
2793 .none => .system,
2794 else => scope,
2795 };
2796 try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);
2797 const instruction = try self.addInst(name, .{
2798 .tag = switch (ordering) {
2799 .none => switch (kind) {
2800 .normal => .load,
2801 .@"volatile" => .@"load volatile",
2802 },
2803 else => switch (kind) {
2804 .normal => .@"load atomic",
2805 .@"volatile" => .@"load atomic volatile",
2806 },
2807 },
2808 .data = self.addExtraAssumeCapacity(Instruction.Load{
2809 .type = ty,
2810 .ptr = ptr,
2811 .info = .{ .scope = final_scope, .ordering = ordering, .alignment = alignment },
2812 }),
2813 });
2814 if (self.builder.useLibLlvm()) {
2815 const llvm_instruction = self.llvm.builder.buildLoad(
2816 ty.toLlvm(self.builder),
2817 ptr.toLlvm(self),
2818 instruction.llvmName(self),
2819 );
2820 if (final_scope == .singlethread) llvm_instruction.setAtomicSingleThread(.True);
2821 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
2822 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
2823 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
2824 }
2825 return instruction.toValue();
2826 }
2827
2828 pub fn store(
2829 self: *WipFunction,
2830 kind: MemoryAccessKind,
2831 val: Value,
2832 ptr: Value,
2833 alignment: Alignment,
2834 ) Allocator.Error!Instruction.Index {
2835 return self.storeAtomic(kind, val, ptr, .system, .none, alignment);
2836 }
2837
2838 pub fn storeAtomic(
2839 self: *WipFunction,
2840 kind: MemoryAccessKind,
2841 val: Value,
2842 ptr: Value,
2843 scope: SyncScope,
2844 ordering: AtomicOrdering,
2845 alignment: Alignment,
2846 ) Allocator.Error!Instruction.Index {
2847 assert(ptr.typeOfWip(self).isPointer(self.builder));
2848 const final_scope = switch (ordering) {
2849 .none => .system,
2850 else => scope,
2851 };
2852 try self.ensureUnusedExtraCapacity(1, Instruction.Store, 0);
2853 const instruction = try self.addInst(null, .{
2854 .tag = switch (ordering) {
2855 .none => switch (kind) {
2856 .normal => .store,
2857 .@"volatile" => .@"store volatile",
2858 },
2859 else => switch (kind) {
2860 .normal => .@"store atomic",
2861 .@"volatile" => .@"store atomic volatile",
2862 },
2863 },
2864 .data = self.addExtraAssumeCapacity(Instruction.Store{
2865 .val = val,
2866 .ptr = ptr,
2867 .info = .{ .scope = final_scope, .ordering = ordering, .alignment = alignment },
2868 }),
2869 });
2870 if (self.builder.useLibLlvm()) {
2871 const llvm_instruction = self.llvm.builder.buildStore(val.toLlvm(self), ptr.toLlvm(self));
2872 switch (kind) {
2873 .normal => {},
2874 .@"volatile" => llvm_instruction.setVolatile(.True),
2875 }
2876 if (final_scope == .singlethread) llvm_instruction.setAtomicSingleThread(.True);
2877 if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
2878 if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a));
2879 self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
2880 }
2881 return instruction;
2882 }
2883
2884 pub fn fence(
2885 self: *WipFunction,
2886 scope: SyncScope,
2887 ordering: AtomicOrdering,
2888 ) Allocator.Error!Instruction.Index {
2889 assert(ordering != .none);
2890 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
2891 const instruction = try self.addInst(null, .{
2892 .tag = .fence,
2893 .data = @bitCast(MemoryAccessInfo{
2894 .scope = scope,
2895 .ordering = ordering,
2896 .alignment = undefined,
2897 }),
2898 });
2899 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
2900 self.llvm.builder.buildFence(
2901 @enumFromInt(@intFromEnum(ordering)),
2902 llvm.Bool.fromBool(scope == .singlethread),
2903 "",
2904 ),
2905 );
2906 return instruction;
2907 }
2908
2909 pub fn gep(
2910 self: *WipFunction,
2911 kind: Instruction.GetElementPtr.Kind,
2912 ty: Type,
2913 base: Value,
2914 indices: []const Value,
2915 name: []const u8,
2916 ) Allocator.Error!Value {
2917 const base_ty = base.typeOfWip(self);
2918 const base_is_vector = base_ty.isVector(self.builder);
2919
2920 const VectorInfo = struct {
2921 kind: Type.Vector.Kind,
2922 len: u32,
2923
2924 fn init(vector_ty: Type, builder: *const Builder) @This() {
2925 return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
2926 }
2927 };
2928 var vector_info: ?VectorInfo =
2929 if (base_is_vector) VectorInfo.init(base_ty, self.builder) else null;
2930 for (indices) |index| {
2931 const index_ty = index.typeOfWip(self);
2932 switch (index_ty.tag(self.builder)) {
2933 .integer => {},
2934 .vector, .scalable_vector => {
2935 const index_info = VectorInfo.init(index_ty, self.builder);
2936 if (vector_info) |info|
2937 assert(std.meta.eql(info, index_info))
2938 else
2939 vector_info = index_info;
2940 },
2941 else => unreachable,
2942 }
2943 }
2944 if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
2945 inline else => |vector_kind| _ = try self.builder.vectorType(
2946 vector_kind,
2947 info.len,
2948 base_ty,
2949 ),
2950 };
2951
2952 try self.ensureUnusedExtraCapacity(1, Instruction.GetElementPtr, indices.len);
2953 const instruction = try self.addInst(name, .{
2954 .tag = switch (kind) {
2955 .normal => .getelementptr,
2956 .inbounds => .@"getelementptr inbounds",
2957 },
2958 .data = self.addExtraAssumeCapacity(Instruction.GetElementPtr{
2959 .type = ty,
2960 .base = base,
2961 .indices_len = @intCast(indices.len),
2962 }),
2963 });
2964 self.extra.appendSliceAssumeCapacity(@ptrCast(indices));
2965 if (self.builder.useLibLlvm()) {
2966 const ExpectedContents = [expected_gep_indices_len]*llvm.Value;
2967 var stack align(@alignOf(ExpectedContents)) =
2968 std.heap.stackFallback(@sizeOf(ExpectedContents), self.builder.gpa);
2969 const allocator = stack.get();
2970
2971 const llvm_indices = try allocator.alloc(*llvm.Value, indices.len);
2972 defer allocator.free(llvm_indices);
2973 for (llvm_indices, indices) |*llvm_index, index| llvm_index.* = index.toLlvm(self);
2974
2975 self.llvm.instructions.appendAssumeCapacity(switch (kind) {
2976 .normal => &llvm.Builder.buildGEP,
2977 .inbounds => &llvm.Builder.buildInBoundsGEP,
2978 }(
2979 self.llvm.builder,
2980 ty.toLlvm(self.builder),
2981 base.toLlvm(self),
2982 llvm_indices.ptr,
2983 @intCast(llvm_indices.len),
2984 instruction.llvmName(self),
2985 ));
2986 }
2987 return instruction.toValue();
2988 }
2989
2990 pub fn gepStruct(
2991 self: *WipFunction,
2992 ty: Type,
2993 base: Value,
2994 index: usize,
2995 name: []const u8,
2996 ) Allocator.Error!Value {
2997 assert(ty.isStruct(self.builder));
2998 return self.gep(.inbounds, ty, base, &.{
2999 try self.builder.intValue(.i32, 0), try self.builder.intValue(.i32, index),
3000 }, name);
3001 }
3002
3003 pub fn conv(
3004 self: *WipFunction,
3005 signedness: Instruction.Cast.Signedness,
3006 val: Value,
3007 ty: Type,
3008 name: []const u8,
3009 ) Allocator.Error!Value {
3010 const val_ty = val.typeOfWip(self);
3011 if (val_ty == ty) return val;
3012 return self.cast(self.builder.convTag(Instruction.Tag, signedness, val_ty, ty), val, ty, name);
3013 }
3014
3015 pub fn cast(
3016 self: *WipFunction,
3017 tag: Instruction.Tag,
3018 val: Value,
3019 ty: Type,
3020 name: []const u8,
3021 ) Allocator.Error!Value {
3022 switch (tag) {
3023 .addrspacecast,
3024 .bitcast,
3025 .fpext,
3026 .fptosi,
3027 .fptoui,
3028 .fptrunc,
3029 .inttoptr,
3030 .ptrtoint,
3031 .sext,
3032 .sitofp,
3033 .trunc,
3034 .uitofp,
3035 .zext,
3036 => {},
3037 else => unreachable,
3038 }
3039 if (val.typeOfWip(self) == ty) return val;
3040 try self.ensureUnusedExtraCapacity(1, Instruction.Cast, 0);
3041 const instruction = try self.addInst(name, .{
3042 .tag = tag,
3043 .data = self.addExtraAssumeCapacity(Instruction.Cast{
3044 .val = val,
3045 .type = ty,
3046 }),
3047 });
3048 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(switch (tag) {
3049 .addrspacecast => &llvm.Builder.buildAddrSpaceCast,
3050 .bitcast => &llvm.Builder.buildBitCast,
3051 .fpext => &llvm.Builder.buildFPExt,
3052 .fptosi => &llvm.Builder.buildFPToSI,
3053 .fptoui => &llvm.Builder.buildFPToUI,
3054 .fptrunc => &llvm.Builder.buildFPTrunc,
3055 .inttoptr => &llvm.Builder.buildIntToPtr,
3056 .ptrtoint => &llvm.Builder.buildPtrToInt,
3057 .sext => &llvm.Builder.buildSExt,
3058 .sitofp => &llvm.Builder.buildSIToFP,
3059 .trunc => &llvm.Builder.buildTrunc,
3060 .uitofp => &llvm.Builder.buildUIToFP,
3061 .zext => &llvm.Builder.buildZExt,
3062 else => unreachable,
3063 }(self.llvm.builder, val.toLlvm(self), ty.toLlvm(self.builder), instruction.llvmName(self)));
3064 return instruction.toValue();
3065 }
3066
3067 pub fn icmp(
3068 self: *WipFunction,
3069 cond: IntegerCondition,
3070 lhs: Value,
3071 rhs: Value,
3072 name: []const u8,
3073 ) Allocator.Error!Value {
3074 return self.cmpTag(switch (cond) {
3075 inline else => |tag| @field(Instruction.Tag, "icmp " ++ @tagName(tag)),
3076 }, @intFromEnum(cond), lhs, rhs, name);
3077 }
3078
3079 pub fn fcmp(
3080 self: *WipFunction,
3081 cond: FloatCondition,
3082 lhs: Value,
3083 rhs: Value,
3084 name: []const u8,
3085 ) Allocator.Error!Value {
3086 return self.cmpTag(switch (cond) {
3087 inline else => |tag| @field(Instruction.Tag, "fcmp " ++ @tagName(tag)),
3088 }, @intFromEnum(cond), lhs, rhs, name);
3089 }
3090
3091 pub fn fcmpFast(
3092 self: *WipFunction,
3093 cond: FloatCondition,
3094 lhs: Value,
3095 rhs: Value,
3096 name: []const u8,
3097 ) Allocator.Error!Value {
3098 return self.cmpTag(switch (cond) {
3099 inline else => |tag| @field(Instruction.Tag, "fcmp fast " ++ @tagName(tag)),
3100 }, @intFromEnum(cond), lhs, rhs, name);
3101 }
3102
3103 pub const WipPhi = struct {
3104 block: Block.Index,
3105 instruction: Instruction.Index,
3106
3107 pub fn toValue(self: WipPhi) Value {
3108 return self.instruction.toValue();
3109 }
3110
3111 pub fn finish(
3112 self: WipPhi,
3113 vals: []const Value,
3114 blocks: []const Block.Index,
3115 wip: *WipFunction,
3116 ) if (build_options.have_llvm) Allocator.Error!void else void {
3117 const incoming_len = self.block.ptrConst(wip).incoming;
3118 assert(vals.len == incoming_len and blocks.len == incoming_len);
3119 const instruction = wip.instructions.get(@intFromEnum(self.instruction));
3120 const extra = wip.extraDataTrail(Instruction.WipPhi, instruction.data);
3121 for (vals) |val| assert(val.typeOfWip(wip) == extra.data.type);
3122 const incoming_vals: []Value = @ptrCast(wip.extra.items[extra.end..][0..incoming_len]);
3123 const incoming_blocks: []Block.Index =
3124 @ptrCast(wip.extra.items[extra.end + incoming_len ..][0..incoming_len]);
3125 @memcpy(incoming_vals, vals);
3126 @memcpy(incoming_blocks, blocks);
3127 if (wip.builder.useLibLlvm()) {
3128 const ExpectedContents = extern struct {
3129 [expected_incoming_len]*llvm.Value,
3130 [expected_incoming_len]*llvm.BasicBlock,
3131 };
3132 var stack align(@alignOf(ExpectedContents)) =
3133 std.heap.stackFallback(@sizeOf(ExpectedContents), wip.builder.gpa);
3134 const allocator = stack.get();
3135
3136 const llvm_vals = try allocator.alloc(*llvm.Value, incoming_len);
3137 defer allocator.free(llvm_vals);
3138 const llvm_blocks = try allocator.alloc(*llvm.BasicBlock, incoming_len);
3139 defer allocator.free(llvm_blocks);
3140
3141 for (llvm_vals, vals) |*llvm_val, incoming_val| llvm_val.* = incoming_val.toLlvm(wip);
3142 for (llvm_blocks, blocks) |*llvm_block, incoming_block|
3143 llvm_block.* = incoming_block.toLlvm(wip);
3144 self.instruction.toLlvm(wip)
3145 .addIncoming(llvm_vals.ptr, llvm_blocks.ptr, @intCast(incoming_len));
3146 }
3147 }
3148 };
3149
3150 pub fn phi(self: *WipFunction, ty: Type, name: []const u8) Allocator.Error!WipPhi {
3151 return self.phiTag(.phi, ty, name);
3152 }
3153
3154 pub fn phiFast(self: *WipFunction, ty: Type, name: []const u8) Allocator.Error!WipPhi {
3155 return self.phiTag(.@"phi fast", ty, name);
3156 }
3157
3158 pub fn select(
3159 self: *WipFunction,
3160 cond: Value,
3161 lhs: Value,
3162 rhs: Value,
3163 name: []const u8,
3164 ) Allocator.Error!Value {
3165 return self.selectTag(.select, cond, lhs, rhs, name);
3166 }
3167
3168 pub fn selectFast(
3169 self: *WipFunction,
3170 cond: Value,
3171 lhs: Value,
3172 rhs: Value,
3173 name: []const u8,
3174 ) Allocator.Error!Value {
3175 return self.selectTag(.@"select fast", cond, lhs, rhs, name);
3176 }
3177
3178 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
3179 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
3180 const instruction = try self.addInst(name, .{
3181 .tag = .va_arg,
3182 .data = self.addExtraAssumeCapacity(Instruction.VaArg{
3183 .list = list,
3184 .type = ty,
3185 }),
3186 });
3187 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
3188 self.llvm.builder.buildVAArg(
3189 list.toLlvm(self),
3190 ty.toLlvm(self.builder),
3191 instruction.llvmName(self),
11203192 ),
11213193 );
1122 return index;
3194 return instruction.toValue();
11233195 }
11243196
1125 pub fn retVoid(self: *WipFunction) Allocator.Error!void {
1126 _ = try self.addInst(.{ .tag = .@"ret void", .data = undefined }, .none);
1127 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
1128 self.llvm.builder.buildRetVoid(),
1129 );
3197 pub const WipUnimplemented = struct {
3198 instruction: Instruction.Index,
3199
3200 pub fn finish(self: WipUnimplemented, val: *llvm.Value, wip: *WipFunction) Value {
3201 assert(wip.builder.useLibLlvm());
3202 wip.llvm.instructions.items[@intFromEnum(self.instruction)] = val;
3203 return self.instruction.toValue();
3204 }
3205 };
3206
3207 pub fn unimplemented(
3208 self: *WipFunction,
3209 ty: Type,
3210 name: []const u8,
3211 ) Allocator.Error!WipUnimplemented {
3212 try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
3213 const instruction = try self.addInst(name, .{
3214 .tag = .unimplemented,
3215 .data = @intFromEnum(ty),
3216 });
3217 if (self.builder.useLibLlvm()) _ = self.llvm.instructions.addOneAssumeCapacity();
3218 return .{ .instruction = instruction };
11303219 }
11313220
11323221 pub fn finish(self: *WipFunction) Allocator.Error!void {
11333222 const gpa = self.builder.gpa;
11343223 const function = self.function.ptr(self.builder);
3224 const params_len = self.function.typeOf(self.builder).functionParameters(self.builder).len;
11353225 const final_instructions_len = self.blocks.items.len + self.instructions.len;
11363226
11373227 const blocks = try gpa.alloc(Function.Block, self.blocks.items.len);
11383228 errdefer gpa.free(blocks);
11393229
1140 const instructions = try gpa.alloc(Instruction.Index, self.instructions.len);
1141 defer gpa.free(instructions);
3230 const instructions: struct {
3231 items: []Instruction.Index,
3232
3233 fn map(instructions: @This(), val: Value) Value {
3234 if (val == .none) return .none;
3235 return switch (val.unwrap()) {
3236 .instruction => |instruction| instructions.items[
3237 @intFromEnum(instruction)
3238 ].toValue(),
3239 .constant => |constant| constant.toValue(),
3240 };
3241 }
3242 } = .{ .items = try gpa.alloc(Instruction.Index, self.instructions.len) };
3243 defer gpa.free(instructions.items);
11423244
1143 const names = if (self.builder.strip) null else try gpa.alloc(String, final_instructions_len);
1144 errdefer if (names) |new_names| gpa.free(new_names);
3245 const names = try gpa.alloc(String, final_instructions_len);
3246 errdefer gpa.free(names);
11453247
11463248 const metadata =
11473249 if (self.builder.strip) null else try gpa.alloc(Metadata, final_instructions_len);
11483250 errdefer if (metadata) |new_metadata| gpa.free(new_metadata);
11493251
3252 var wip_extra: struct {
3253 index: Instruction.ExtraIndex = 0,
3254 items: []u32,
3255
3256 fn addExtra(wip_extra: *@This(), extra: anytype) Instruction.ExtraIndex {
3257 const result = wip_extra.index;
3258 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
3259 const value = @field(extra, field.name);
3260 wip_extra.items[wip_extra.index] = switch (field.type) {
3261 u32 => value,
3262 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),
3263 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
3264 else => @compileError("bad field type: " ++ @typeName(field.type)),
3265 };
3266 wip_extra.index += 1;
3267 }
3268 return result;
3269 }
3270
3271 fn appendSlice(wip_extra: *@This(), slice: anytype) void {
3272 if (@typeInfo(@TypeOf(slice)).Pointer.child == Value) @compileError("use appendValues");
3273 const data: []const u32 = @ptrCast(slice);
3274 @memcpy(wip_extra.items[wip_extra.index..][0..data.len], data);
3275 wip_extra.index += @intCast(data.len);
3276 }
3277
3278 fn appendValues(wip_extra: *@This(), vals: []const Value, ctx: anytype) void {
3279 for (wip_extra.items[wip_extra.index..][0..vals.len], vals) |*extra, val|
3280 extra.* = @intFromEnum(ctx.map(val));
3281 wip_extra.index += @intCast(vals.len);
3282 }
3283
3284 fn finish(wip_extra: *const @This()) []const u32 {
3285 assert(wip_extra.index == wip_extra.items.len);
3286 return wip_extra.items;
3287 }
3288 } = .{ .items = try gpa.alloc(u32, self.extra.items.len) };
3289 errdefer gpa.free(wip_extra.items);
3290
11503291 gpa.free(function.blocks);
11513292 function.blocks = &.{};
1152 if (function.names) |old_names| gpa.free(old_names[0..function.instructions.len]);
1153 function.names = null;
3293 gpa.free(function.names[0..function.instructions.len]);
11543294 if (function.metadata) |old_metadata| gpa.free(old_metadata[0..function.instructions.len]);
11553295 function.metadata = null;
3296 gpa.free(function.extra);
3297 function.extra = &.{};
11563298
11573299 function.instructions.shrinkRetainingCapacity(0);
11583300 try function.instructions.setCapacity(gpa, final_instructions_len);
11593301 errdefer function.instructions.shrinkRetainingCapacity(0);
11603302
11613303 {
1162 var final_instruction: Instruction.Index = @enumFromInt(0);
3304 var final_instruction_index: Instruction.Index = @enumFromInt(0);
3305 for (0..params_len) |param_index| {
3306 instructions.items[param_index] = final_instruction_index;
3307 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
3308 }
11633309 for (blocks, self.blocks.items) |*final_block, current_block| {
1164 final_block.instruction = final_instruction;
1165 final_instruction = @enumFromInt(@intFromEnum(final_instruction) + 1);
3310 assert(current_block.incoming == current_block.branches);
3311 final_block.instruction = final_instruction_index;
3312 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
11663313 for (current_block.instructions.items) |instruction| {
1167 instructions[@intFromEnum(instruction)] = final_instruction;
1168 final_instruction = @enumFromInt(@intFromEnum(final_instruction) + 1);
3314 instructions.items[@intFromEnum(instruction)] = final_instruction_index;
3315 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
11693316 }
11703317 }
11713318 }
11723319
1173 var next_name: String = @enumFromInt(0);
3320 var wip_name: struct {
3321 next_name: String = @enumFromInt(0),
3322
3323 fn map(wip_name: *@This(), old_name: String) String {
3324 if (old_name != .empty) return old_name;
3325
3326 const new_name = wip_name.next_name;
3327 wip_name.next_name = @enumFromInt(@intFromEnum(new_name) + 1);
3328 return new_name;
3329 }
3330 } = .{};
3331 for (0..params_len) |param_index| {
3332 const old_argument_index: Instruction.Index = @enumFromInt(param_index);
3333 const new_argument_index: Instruction.Index = @enumFromInt(function.instructions.len);
3334 const argument = self.instructions.get(@intFromEnum(old_argument_index));
3335 assert(argument.tag == .arg);
3336 assert(argument.data == param_index);
3337 function.instructions.appendAssumeCapacity(argument);
3338 names[@intFromEnum(new_argument_index)] = wip_name.map(
3339 if (self.builder.strip) .empty else self.names.items[@intFromEnum(old_argument_index)],
3340 );
3341 }
11743342 for (self.blocks.items) |current_block| {
1175 const block_instruction: Instruction.Index = @enumFromInt(function.instructions.len);
3343 const new_block_index: Instruction.Index = @enumFromInt(function.instructions.len);
11763344 function.instructions.appendAssumeCapacity(.{
11773345 .tag = .block,
11783346 .data = current_block.incoming,
11793347 });
1180 if (names) |new_names|
1181 new_names[@intFromEnum(block_instruction)] = switch (current_block.name) {
1182 .empty => name: {
1183 const name = next_name;
1184 next_name = @enumFromInt(@intFromEnum(name) + 1);
1185 break :name name;
1186 },
1187 else => |name| name,
1188 };
1189 for (current_block.instructions.items) |instruction_index| {
1190 var instruction = self.instructions.get(@intFromEnum(instruction_index));
3348 names[@intFromEnum(new_block_index)] = wip_name.map(current_block.name);
3349 for (current_block.instructions.items) |old_instruction_index| {
3350 const new_instruction_index: Instruction.Index =
3351 @enumFromInt(function.instructions.len);
3352 var instruction = self.instructions.get(@intFromEnum(old_instruction_index));
11913353 switch (instruction.tag) {
1192 .block => unreachable,
1193 .@"ret void" => {},
1194 else => unreachable,
3354 .add,
3355 .@"add nsw",
3356 .@"add nuw",
3357 .@"add nuw nsw",
3358 .@"and",
3359 .ashr,
3360 .@"ashr exact",
3361 .fadd,
3362 .@"fadd fast",
3363 .@"fcmp false",
3364 .@"fcmp fast false",
3365 .@"fcmp fast oeq",
3366 .@"fcmp fast oge",
3367 .@"fcmp fast ogt",
3368 .@"fcmp fast ole",
3369 .@"fcmp fast olt",
3370 .@"fcmp fast one",
3371 .@"fcmp fast ord",
3372 .@"fcmp fast true",
3373 .@"fcmp fast ueq",
3374 .@"fcmp fast uge",
3375 .@"fcmp fast ugt",
3376 .@"fcmp fast ule",
3377 .@"fcmp fast ult",
3378 .@"fcmp fast une",
3379 .@"fcmp fast uno",
3380 .@"fcmp oeq",
3381 .@"fcmp oge",
3382 .@"fcmp ogt",
3383 .@"fcmp ole",
3384 .@"fcmp olt",
3385 .@"fcmp one",
3386 .@"fcmp ord",
3387 .@"fcmp true",
3388 .@"fcmp ueq",
3389 .@"fcmp uge",
3390 .@"fcmp ugt",
3391 .@"fcmp ule",
3392 .@"fcmp ult",
3393 .@"fcmp une",
3394 .@"fcmp uno",
3395 .fdiv,
3396 .@"fdiv fast",
3397 .fmul,
3398 .@"fmul fast",
3399 .frem,
3400 .@"frem fast",
3401 .fsub,
3402 .@"fsub fast",
3403 .@"icmp eq",
3404 .@"icmp ne",
3405 .@"icmp sge",
3406 .@"icmp sgt",
3407 .@"icmp sle",
3408 .@"icmp slt",
3409 .@"icmp uge",
3410 .@"icmp ugt",
3411 .@"icmp ule",
3412 .@"icmp ult",
3413 .@"llvm.maxnum.",
3414 .@"llvm.minnum.",
3415 .@"llvm.sadd.sat.",
3416 .@"llvm.smax.",
3417 .@"llvm.smin.",
3418 .@"llvm.smul.fix.sat.",
3419 .@"llvm.sshl.sat.",
3420 .@"llvm.ssub.sat.",
3421 .@"llvm.uadd.sat.",
3422 .@"llvm.umax.",
3423 .@"llvm.umin.",
3424 .@"llvm.umul.fix.sat.",
3425 .@"llvm.ushl.sat.",
3426 .@"llvm.usub.sat.",
3427 .lshr,
3428 .@"lshr exact",
3429 .mul,
3430 .@"mul nsw",
3431 .@"mul nuw",
3432 .@"mul nuw nsw",
3433 .@"or",
3434 .sdiv,
3435 .@"sdiv exact",
3436 .shl,
3437 .@"shl nsw",
3438 .@"shl nuw",
3439 .@"shl nuw nsw",
3440 .srem,
3441 .sub,
3442 .@"sub nsw",
3443 .@"sub nuw",
3444 .@"sub nuw nsw",
3445 .udiv,
3446 .@"udiv exact",
3447 .urem,
3448 .xor,
3449 => {
3450 const extra = self.extraData(Instruction.Binary, instruction.data);
3451 instruction.data = wip_extra.addExtra(Instruction.Binary{
3452 .lhs = instructions.map(extra.lhs),
3453 .rhs = instructions.map(extra.rhs),
3454 });
3455 },
3456 .addrspacecast,
3457 .bitcast,
3458 .fpext,
3459 .fptosi,
3460 .fptoui,
3461 .fptrunc,
3462 .inttoptr,
3463 .ptrtoint,
3464 .sext,
3465 .sitofp,
3466 .trunc,
3467 .uitofp,
3468 .zext,
3469 => {
3470 const extra = self.extraData(Instruction.Cast, instruction.data);
3471 instruction.data = wip_extra.addExtra(Instruction.Cast{
3472 .val = instructions.map(extra.val),
3473 .type = extra.type,
3474 });
3475 },
3476 .alloca,
3477 .@"alloca inalloca",
3478 => {
3479 const extra = self.extraData(Instruction.Alloca, instruction.data);
3480 instruction.data = wip_extra.addExtra(Instruction.Alloca{
3481 .type = extra.type,
3482 .len = instructions.map(extra.len),
3483 .info = extra.info,
3484 });
3485 },
3486 .arg,
3487 .block,
3488 => unreachable,
3489 .br,
3490 .fence,
3491 .@"ret void",
3492 .unimplemented,
3493 .@"unreachable",
3494 => {},
3495 .extractelement => {
3496 const extra = self.extraData(Instruction.ExtractElement, instruction.data);
3497 instruction.data = wip_extra.addExtra(Instruction.ExtractElement{
3498 .val = instructions.map(extra.val),
3499 .index = instructions.map(extra.index),
3500 });
3501 },
3502 .br_cond => {
3503 const extra = self.extraData(Instruction.BrCond, instruction.data);
3504 instruction.data = wip_extra.addExtra(Instruction.BrCond{
3505 .cond = instructions.map(extra.cond),
3506 .then = extra.then,
3507 .@"else" = extra.@"else",
3508 });
3509 },
3510 .extractvalue => {
3511 const extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
3512 const indices: []const u32 =
3513 self.extra.items[extra.end..][0..extra.data.indices_len];
3514 instruction.data = wip_extra.addExtra(Instruction.ExtractValue{
3515 .val = instructions.map(extra.data.val),
3516 .indices_len = extra.data.indices_len,
3517 });
3518 wip_extra.appendSlice(indices);
3519 },
3520 .fneg,
3521 .@"fneg fast",
3522 .ret,
3523 => instruction.data = @intFromEnum(instructions.map(@enumFromInt(instruction.data))),
3524 .getelementptr,
3525 .@"getelementptr inbounds",
3526 => {
3527 const extra = self.extraDataTrail(Instruction.GetElementPtr, instruction.data);
3528 const indices: []const Value =
3529 @ptrCast(self.extra.items[extra.end..][0..extra.data.indices_len]);
3530 instruction.data = wip_extra.addExtra(Instruction.GetElementPtr{
3531 .type = extra.data.type,
3532 .base = instructions.map(extra.data.base),
3533 .indices_len = extra.data.indices_len,
3534 });
3535 wip_extra.appendValues(indices, instructions);
3536 },
3537 .insertelement => {
3538 const extra = self.extraData(Instruction.InsertElement, instruction.data);
3539 instruction.data = wip_extra.addExtra(Instruction.InsertElement{
3540 .val = instructions.map(extra.val),
3541 .elem = instructions.map(extra.elem),
3542 .index = instructions.map(extra.index),
3543 });
3544 },
3545 .insertvalue => {
3546 const extra = self.extraDataTrail(Instruction.InsertValue, instruction.data);
3547 const indices: []const u32 =
3548 self.extra.items[extra.end..][0..extra.data.indices_len];
3549 instruction.data = wip_extra.addExtra(Instruction.InsertValue{
3550 .val = instructions.map(extra.data.val),
3551 .elem = instructions.map(extra.data.elem),
3552 .indices_len = extra.data.indices_len,
3553 });
3554 wip_extra.appendSlice(indices);
3555 },
3556 .load,
3557 .@"load atomic",
3558 .@"load atomic volatile",
3559 .@"load volatile",
3560 => {
3561 const extra = self.extraData(Instruction.Load, instruction.data);
3562 instruction.data = wip_extra.addExtra(Instruction.Load{
3563 .type = extra.type,
3564 .ptr = instructions.map(extra.ptr),
3565 .info = extra.info,
3566 });
3567 },
3568 .phi,
3569 .@"phi fast",
3570 => {
3571 const extra = self.extraDataTrail(Instruction.WipPhi, instruction.data);
3572 const incoming_len = current_block.incoming;
3573 const incoming_vals: []const Value =
3574 @ptrCast(self.extra.items[extra.end..][0..incoming_len]);
3575 const incoming_blocks: []const Block.Index =
3576 @ptrCast(self.extra.items[extra.end + incoming_len ..][0..incoming_len]);
3577 instruction.data = wip_extra.addExtra(Instruction.Phi{
3578 .incoming_len = incoming_len,
3579 });
3580 wip_extra.appendValues(incoming_vals, instructions);
3581 wip_extra.appendSlice(incoming_blocks);
3582 },
3583 .select,
3584 .@"select fast",
3585 => {
3586 const extra = self.extraData(Instruction.Select, instruction.data);
3587 instruction.data = wip_extra.addExtra(Instruction.Select{
3588 .cond = instructions.map(extra.cond),
3589 .lhs = instructions.map(extra.lhs),
3590 .rhs = instructions.map(extra.rhs),
3591 });
3592 },
3593 .shufflevector => {
3594 const extra = self.extraData(Instruction.ShuffleVector, instruction.data);
3595 instruction.data = wip_extra.addExtra(Instruction.ShuffleVector{
3596 .lhs = instructions.map(extra.lhs),
3597 .rhs = instructions.map(extra.rhs),
3598 .mask = instructions.map(extra.mask),
3599 });
3600 },
3601 .store,
3602 .@"store atomic",
3603 .@"store atomic volatile",
3604 .@"store volatile",
3605 => {
3606 const extra = self.extraData(Instruction.Store, instruction.data);
3607 instruction.data = wip_extra.addExtra(Instruction.Store{
3608 .val = instructions.map(extra.val),
3609 .ptr = instructions.map(extra.ptr),
3610 .info = extra.info,
3611 });
3612 },
3613 .@"switch" => {
3614 const extra = self.extraDataTrail(Instruction.Switch, instruction.data);
3615 const case_vals: []const Constant =
3616 @ptrCast(self.extra.items[extra.end..][0..extra.data.cases_len]);
3617 const case_blocks: []const Block.Index = @ptrCast(self.extra
3618 .items[extra.end + extra.data.cases_len ..][0..extra.data.cases_len]);
3619 instruction.data = wip_extra.addExtra(Instruction.Switch{
3620 .val = instructions.map(extra.data.val),
3621 .default = extra.data.default,
3622 .cases_len = extra.data.cases_len,
3623 });
3624 wip_extra.appendSlice(case_vals);
3625 wip_extra.appendSlice(case_blocks);
3626 },
3627 .va_arg => {
3628 const extra = self.extraData(Instruction.VaArg, instruction.data);
3629 instruction.data = wip_extra.addExtra(Instruction.VaArg{
3630 .list = instructions.map(extra.list),
3631 .type = extra.type,
3632 });
3633 },
11953634 }
11963635 function.instructions.appendAssumeCapacity(instruction);
3636 names[@intFromEnum(new_instruction_index)] = wip_name.map(if (self.builder.strip)
3637 if (old_instruction_index.hasResultWip(self)) .empty else .none
3638 else
3639 self.names.items[@intFromEnum(old_instruction_index)]);
11973640 }
11983641 }
11993642
1200 function.extra = try self.extra.toOwnedSlice(gpa);
3643 assert(function.instructions.len == final_instructions_len);
3644 function.extra = wip_extra.finish();
12013645 function.blocks = blocks;
1202 function.names = if (names) |new_names| new_names.ptr else null;
3646 function.names = names.ptr;
12033647 function.metadata = if (metadata) |new_metadata| new_metadata.ptr else null;
12043648 }
12053649
......@@ -1212,36 +3656,330 @@ pub const WipFunction = struct {
12123656 self.* = undefined;
12133657 }
12143658
3659 fn cmpTag(
3660 self: *WipFunction,
3661 tag: Instruction.Tag,
3662 cond: u32,
3663 lhs: Value,
3664 rhs: Value,
3665 name: []const u8,
3666 ) Allocator.Error!Value {
3667 switch (tag) {
3668 .@"fcmp false",
3669 .@"fcmp fast false",
3670 .@"fcmp fast oeq",
3671 .@"fcmp fast oge",
3672 .@"fcmp fast ogt",
3673 .@"fcmp fast ole",
3674 .@"fcmp fast olt",
3675 .@"fcmp fast one",
3676 .@"fcmp fast ord",
3677 .@"fcmp fast true",
3678 .@"fcmp fast ueq",
3679 .@"fcmp fast uge",
3680 .@"fcmp fast ugt",
3681 .@"fcmp fast ule",
3682 .@"fcmp fast ult",
3683 .@"fcmp fast une",
3684 .@"fcmp fast uno",
3685 .@"fcmp oeq",
3686 .@"fcmp oge",
3687 .@"fcmp ogt",
3688 .@"fcmp ole",
3689 .@"fcmp olt",
3690 .@"fcmp one",
3691 .@"fcmp ord",
3692 .@"fcmp true",
3693 .@"fcmp ueq",
3694 .@"fcmp uge",
3695 .@"fcmp ugt",
3696 .@"fcmp ule",
3697 .@"fcmp ult",
3698 .@"fcmp une",
3699 .@"fcmp uno",
3700 .@"icmp eq",
3701 .@"icmp ne",
3702 .@"icmp sge",
3703 .@"icmp sgt",
3704 .@"icmp sle",
3705 .@"icmp slt",
3706 .@"icmp uge",
3707 .@"icmp ugt",
3708 .@"icmp ule",
3709 .@"icmp ult",
3710 => assert(lhs.typeOfWip(self) == rhs.typeOfWip(self)),
3711 else => unreachable,
3712 }
3713 _ = try lhs.typeOfWip(self).changeScalar(.i1, self.builder);
3714 try self.ensureUnusedExtraCapacity(1, Instruction.Binary, 0);
3715 const instruction = try self.addInst(name, .{
3716 .tag = tag,
3717 .data = self.addExtraAssumeCapacity(Instruction.Binary{
3718 .lhs = lhs,
3719 .rhs = rhs,
3720 }),
3721 });
3722 if (self.builder.useLibLlvm()) {
3723 switch (tag) {
3724 .@"fcmp false",
3725 .@"fcmp oeq",
3726 .@"fcmp oge",
3727 .@"fcmp ogt",
3728 .@"fcmp ole",
3729 .@"fcmp olt",
3730 .@"fcmp one",
3731 .@"fcmp ord",
3732 .@"fcmp true",
3733 .@"fcmp ueq",
3734 .@"fcmp uge",
3735 .@"fcmp ugt",
3736 .@"fcmp ule",
3737 .@"fcmp ult",
3738 .@"fcmp une",
3739 .@"fcmp uno",
3740 => self.llvm.builder.setFastMath(false),
3741 .@"fcmp fast false",
3742 .@"fcmp fast oeq",
3743 .@"fcmp fast oge",
3744 .@"fcmp fast ogt",
3745 .@"fcmp fast ole",
3746 .@"fcmp fast olt",
3747 .@"fcmp fast one",
3748 .@"fcmp fast ord",
3749 .@"fcmp fast true",
3750 .@"fcmp fast ueq",
3751 .@"fcmp fast uge",
3752 .@"fcmp fast ugt",
3753 .@"fcmp fast ule",
3754 .@"fcmp fast ult",
3755 .@"fcmp fast une",
3756 .@"fcmp fast uno",
3757 => self.llvm.builder.setFastMath(true),
3758 .@"icmp eq",
3759 .@"icmp ne",
3760 .@"icmp sge",
3761 .@"icmp sgt",
3762 .@"icmp sle",
3763 .@"icmp slt",
3764 .@"icmp uge",
3765 .@"icmp ugt",
3766 .@"icmp ule",
3767 .@"icmp ult",
3768 => {},
3769 else => unreachable,
3770 }
3771 self.llvm.instructions.appendAssumeCapacity(switch (tag) {
3772 .@"fcmp false",
3773 .@"fcmp fast false",
3774 .@"fcmp fast oeq",
3775 .@"fcmp fast oge",
3776 .@"fcmp fast ogt",
3777 .@"fcmp fast ole",
3778 .@"fcmp fast olt",
3779 .@"fcmp fast one",
3780 .@"fcmp fast ord",
3781 .@"fcmp fast true",
3782 .@"fcmp fast ueq",
3783 .@"fcmp fast uge",
3784 .@"fcmp fast ugt",
3785 .@"fcmp fast ule",
3786 .@"fcmp fast ult",
3787 .@"fcmp fast une",
3788 .@"fcmp fast uno",
3789 .@"fcmp oeq",
3790 .@"fcmp oge",
3791 .@"fcmp ogt",
3792 .@"fcmp ole",
3793 .@"fcmp olt",
3794 .@"fcmp one",
3795 .@"fcmp ord",
3796 .@"fcmp true",
3797 .@"fcmp ueq",
3798 .@"fcmp uge",
3799 .@"fcmp ugt",
3800 .@"fcmp ule",
3801 .@"fcmp ult",
3802 .@"fcmp une",
3803 .@"fcmp uno",
3804 => self.llvm.builder.buildFCmp(
3805 @enumFromInt(cond),
3806 lhs.toLlvm(self),
3807 rhs.toLlvm(self),
3808 instruction.llvmName(self),
3809 ),
3810 .@"icmp eq",
3811 .@"icmp ne",
3812 .@"icmp sge",
3813 .@"icmp sgt",
3814 .@"icmp sle",
3815 .@"icmp slt",
3816 .@"icmp uge",
3817 .@"icmp ugt",
3818 .@"icmp ule",
3819 .@"icmp ult",
3820 => self.llvm.builder.buildICmp(
3821 @enumFromInt(cond),
3822 lhs.toLlvm(self),
3823 rhs.toLlvm(self),
3824 instruction.llvmName(self),
3825 ),
3826 else => unreachable,
3827 });
3828 }
3829 return instruction.toValue();
3830 }
3831
3832 fn phiTag(
3833 self: *WipFunction,
3834 tag: Instruction.Tag,
3835 ty: Type,
3836 name: []const u8,
3837 ) Allocator.Error!WipPhi {
3838 switch (tag) {
3839 .phi, .@"phi fast" => assert(try ty.isSized(self.builder)),
3840 else => unreachable,
3841 }
3842 const incoming = self.cursor.block.ptrConst(self).incoming;
3843 assert(incoming > 0);
3844 try self.ensureUnusedExtraCapacity(1, Instruction.WipPhi, incoming * 2);
3845 const instruction = try self.addInst(name, .{
3846 .tag = tag,
3847 .data = self.addExtraAssumeCapacity(Instruction.WipPhi{ .type = ty }),
3848 });
3849 _ = self.extra.addManyAsSliceAssumeCapacity(incoming * 2);
3850 if (self.builder.useLibLlvm()) {
3851 switch (tag) {
3852 .phi => self.llvm.builder.setFastMath(false),
3853 .@"phi fast" => self.llvm.builder.setFastMath(true),
3854 else => unreachable,
3855 }
3856 self.llvm.instructions.appendAssumeCapacity(
3857 self.llvm.builder.buildPhi(ty.toLlvm(self.builder), instruction.llvmName(self)),
3858 );
3859 }
3860 return .{ .block = self.cursor.block, .instruction = instruction };
3861 }
3862
3863 fn selectTag(
3864 self: *WipFunction,
3865 tag: Instruction.Tag,
3866 cond: Value,
3867 lhs: Value,
3868 rhs: Value,
3869 name: []const u8,
3870 ) Allocator.Error!Value {
3871 switch (tag) {
3872 .select, .@"select fast" => {
3873 assert(cond.typeOfWip(self).scalarType(self.builder) == .i1);
3874 assert(lhs.typeOfWip(self) == rhs.typeOfWip(self));
3875 },
3876 else => unreachable,
3877 }
3878 try self.ensureUnusedExtraCapacity(1, Instruction.Select, 0);
3879 const instruction = try self.addInst(name, .{
3880 .tag = tag,
3881 .data = self.addExtraAssumeCapacity(Instruction.Select{
3882 .cond = cond,
3883 .lhs = lhs,
3884 .rhs = rhs,
3885 }),
3886 });
3887 if (self.builder.useLibLlvm()) {
3888 switch (tag) {
3889 .select => self.llvm.builder.setFastMath(false),
3890 .@"select fast" => self.llvm.builder.setFastMath(true),
3891 else => unreachable,
3892 }
3893 self.llvm.instructions.appendAssumeCapacity(self.llvm.builder.buildSelect(
3894 cond.toLlvm(self),
3895 lhs.toLlvm(self),
3896 rhs.toLlvm(self),
3897 instruction.llvmName(self),
3898 ));
3899 }
3900 return instruction.toValue();
3901 }
3902
3903 fn ensureUnusedExtraCapacity(
3904 self: *WipFunction,
3905 count: usize,
3906 comptime Extra: type,
3907 trail_len: usize,
3908 ) Allocator.Error!void {
3909 try self.extra.ensureUnusedCapacity(
3910 self.builder.gpa,
3911 count * (@typeInfo(Extra).Struct.fields.len + trail_len),
3912 );
3913 }
3914
12153915 fn addInst(
12163916 self: *WipFunction,
3917 name: ?[]const u8,
12173918 instruction: Instruction,
1218 name: String,
12193919 ) Allocator.Error!Instruction.Index {
1220 const block_instructions = &self.blocks.items[@intFromEnum(self.cursor.block)].instructions;
3920 const block_instructions = &self.cursor.block.ptr(self).instructions;
12213921 try self.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
1222 try self.names.ensureUnusedCapacity(self.builder.gpa, 1);
3922 if (!self.builder.strip) try self.names.ensureUnusedCapacity(self.builder.gpa, 1);
12233923 try block_instructions.ensureUnusedCapacity(self.builder.gpa, 1);
1224 if (self.builder.useLibLlvm()) {
3924 if (self.builder.useLibLlvm())
12253925 try self.llvm.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
1226
1227 self.llvm.builder.positionBuilder(
1228 self.cursor.block.toLlvm(self),
1229 if (self.cursor.instruction < block_instructions.items.len)
1230 self.llvm.instructions.items[
1231 @intFromEnum(block_instructions.items[self.cursor.instruction])
1232 ]
1233 else
1234 null,
1235 );
1236 }
3926 const final_name = if (name) |n|
3927 if (self.builder.strip) .empty else try self.builder.string(n)
3928 else
3929 .none;
3930
3931 if (self.builder.useLibLlvm()) self.llvm.builder.positionBuilder(
3932 self.cursor.block.toLlvm(self),
3933 for (block_instructions.items[self.cursor.instruction..]) |instruction_index| {
3934 const llvm_instruction =
3935 self.llvm.instructions.items[@intFromEnum(instruction_index)];
3936 // TODO: remove when constant propagation is implemented
3937 if (!llvm_instruction.isConstant().toBool()) break llvm_instruction;
3938 } else null,
3939 );
12373940
12383941 const index: Instruction.Index = @enumFromInt(self.instructions.len);
12393942 self.instructions.appendAssumeCapacity(instruction);
1240 self.names.appendAssumeCapacity(name);
3943 if (!self.builder.strip) self.names.appendAssumeCapacity(final_name);
12413944 block_instructions.insertAssumeCapacity(self.cursor.instruction, index);
12423945 self.cursor.instruction += 1;
12433946 return index;
12443947 }
3948
3949 fn addExtraAssumeCapacity(self: *WipFunction, extra: anytype) Instruction.ExtraIndex {
3950 const result: Instruction.ExtraIndex = @intCast(self.extra.items.len);
3951 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
3952 const value = @field(extra, field.name);
3953 self.extra.appendAssumeCapacity(switch (field.type) {
3954 u32 => value,
3955 Alignment, AtomicOrdering, Block.Index, Type, Value => @intFromEnum(value),
3956 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
3957 else => @compileError("bad field type: " ++ @typeName(field.type)),
3958 });
3959 }
3960 return result;
3961 }
3962
3963 fn extraDataTrail(
3964 self: *const WipFunction,
3965 comptime T: type,
3966 index: Instruction.ExtraIndex,
3967 ) struct { data: T, end: Instruction.ExtraIndex } {
3968 var result: T = undefined;
3969 const fields = @typeInfo(T).Struct.fields;
3970 inline for (fields, self.extra.items[index..][0..fields.len]) |field, value|
3971 @field(result, field.name) = switch (field.type) {
3972 u32 => value,
3973 Alignment, AtomicOrdering, Block.Index, Type, Value => @enumFromInt(value),
3974 MemoryAccessInfo, Instruction.Alloca.Info => @bitCast(value),
3975 else => @compileError("bad field type: " ++ @typeName(field.type)),
3976 };
3977 return .{ .data = result, .end = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) };
3978 }
3979
3980 fn extraData(self: *const WipFunction, comptime T: type, index: Instruction.ExtraIndex) T {
3981 return self.extraDataTrail(T, index).data;
3982 }
12453983};
12463984
12473985pub const FloatCondition = enum(u4) {
......@@ -1274,6 +4012,73 @@ pub const IntegerCondition = enum(u6) {
12744012 sle = 41,
12754013};
12764014
4015pub const MemoryAccessKind = enum(u1) {
4016 normal,
4017 @"volatile",
4018};
4019
4020pub const SyncScope = enum(u1) {
4021 singlethread,
4022 system,
4023
4024 pub fn format(
4025 self: SyncScope,
4026 comptime prefix: []const u8,
4027 _: std.fmt.FormatOptions,
4028 writer: anytype,
4029 ) @TypeOf(writer).Error!void {
4030 if (self != .system) try writer.print(
4031 \\{s} syncscope("{s}")
4032 , .{ prefix, @tagName(self) });
4033 }
4034};
4035
4036pub const AtomicOrdering = enum(u3) {
4037 none = 0,
4038 unordered = 1,
4039 monotonic = 2,
4040 acquire = 4,
4041 release = 5,
4042 acq_rel = 6,
4043 seq_cst = 7,
4044
4045 pub fn format(
4046 self: AtomicOrdering,
4047 comptime prefix: []const u8,
4048 _: std.fmt.FormatOptions,
4049 writer: anytype,
4050 ) @TypeOf(writer).Error!void {
4051 if (self != .none) try writer.print("{s} {s}", .{ prefix, @tagName(self) });
4052 }
4053};
4054
4055const MemoryAccessInfo = packed struct(u32) {
4056 scope: SyncScope,
4057 ordering: AtomicOrdering,
4058 alignment: Alignment,
4059 _: u22 = undefined,
4060};
4061
4062pub const FastMath = packed struct(u32) {
4063 nnan: bool = false,
4064 ninf: bool = false,
4065 nsz: bool = false,
4066 arcp: bool = false,
4067 contract: bool = false,
4068 afn: bool = false,
4069 reassoc: bool = false,
4070
4071 pub const fast = FastMath{
4072 .nnan = true,
4073 .ninf = true,
4074 .nsz = true,
4075 .arcp = true,
4076 .contract = true,
4077 .afn = true,
4078 .realloc = true,
4079 };
4080};
4081
12774082pub const Constant = enum(u32) {
12784083 false,
12794084 true,
......@@ -1379,6 +4184,7 @@ pub const Constant = enum(u32) {
13794184
13804185 pub const Aggregate = struct {
13814186 type: Type,
4187 //fields: [type.aggregateLen(builder)]Constant,
13824188 };
13834189
13844190 pub const Splat = extern struct {
......@@ -1391,12 +4197,8 @@ pub const Constant = enum(u32) {
13914197 block: Function.Block.Index,
13924198 };
13934199
1394 pub const FunctionReference = struct {
1395 function: Function.Index,
1396 };
1397
13984200 pub const Cast = extern struct {
1399 arg: Constant,
4201 val: Constant,
14004202 type: Type,
14014203
14024204 pub const Signedness = enum { unsigned, signed, unneeded };
......@@ -1405,9 +4207,12 @@ pub const Constant = enum(u32) {
14054207 pub const GetElementPtr = struct {
14064208 type: Type,
14074209 base: Constant,
1408 indices_len: u32,
4210 info: Info,
4211 //indices: [info.indices_len]Constant,
14094212
14104213 pub const Kind = enum { normal, inbounds };
4214 pub const InRangeIndex = enum(u16) { none = std.math.maxInt(u16), _ };
4215 pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
14114216 };
14124217
14134218 pub const Compare = extern struct {
......@@ -1417,12 +4222,12 @@ pub const Constant = enum(u32) {
14174222 };
14184223
14194224 pub const ExtractElement = extern struct {
1420 arg: Constant,
4225 val: Constant,
14214226 index: Constant,
14224227 };
14234228
14244229 pub const InsertElement = extern struct {
1425 arg: Constant,
4230 val: Constant,
14264231 elem: Constant,
14274232 index: Constant,
14284233 };
......@@ -1448,6 +4253,10 @@ pub const Constant = enum(u32) {
14484253 .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
14494254 }
14504255
4256 pub fn toValue(self: Constant) Value {
4257 return @enumFromInt(@intFromEnum(Value.first_constant) + @intFromEnum(self));
4258 }
4259
14514260 pub fn typeOf(self: Constant, builder: *Builder) Type {
14524261 switch (self.unwrap()) {
14534262 .constant => |constant| {
......@@ -1491,10 +4300,8 @@ pub const Constant = enum(u32) {
14914300 ),
14924301 .dso_local_equivalent,
14934302 .no_cfi,
1494 => builder.ptrTypeAssumeCapacity(
1495 builder.constantExtraData(FunctionReference, item.data)
1496 .function.ptrConst(builder).global.ptrConst(builder).addr_space,
1497 ),
4303 => builder.ptrTypeAssumeCapacity(@as(Function.Index, @enumFromInt(item.data))
4304 .ptrConst(builder).global.ptrConst(builder).addr_space),
14984305 .trunc,
14994306 .zext,
15004307 .sext,
......@@ -1514,42 +4321,29 @@ pub const Constant = enum(u32) {
15144321 => {
15154322 const extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
15164323 const indices: []const Constant = @ptrCast(builder.constant_extra
1517 .items[extra.end..][0..extra.data.indices_len]);
4324 .items[extra.end..][0..extra.data.info.indices_len]);
15184325 const base_ty = extra.data.base.typeOf(builder);
15194326 if (!base_ty.isVector(builder)) for (indices) |index| {
15204327 const index_ty = index.typeOf(builder);
15214328 if (!index_ty.isVector(builder)) continue;
1522 switch (index_ty.vectorKind(builder)) {
1523 inline else => |kind| return builder.vectorTypeAssumeCapacity(
1524 kind,
1525 index_ty.vectorLen(builder),
1526 base_ty,
1527 ),
1528 }
4329 return index_ty.changeScalarAssumeCapacity(base_ty, builder);
15294330 };
15304331 return base_ty;
15314332 },
1532 .icmp, .fcmp => {
1533 const ty = builder.constantExtraData(Compare, item.data).lhs.typeOf(builder);
1534 return if (ty.isVector(builder)) switch (ty.vectorKind(builder)) {
1535 inline else => |kind| builder
1536 .vectorTypeAssumeCapacity(kind, ty.vectorLen(builder), .i1),
1537 } else ty;
1538 },
4333 .icmp,
4334 .fcmp,
4335 => builder.constantExtraData(Compare, item.data).lhs.typeOf(builder)
4336 .changeScalarAssumeCapacity(.i1, builder),
15394337 .extractelement => builder.constantExtraData(ExtractElement, item.data)
1540 .arg.typeOf(builder).childType(builder),
4338 .val.typeOf(builder).childType(builder),
15414339 .insertelement => builder.constantExtraData(InsertElement, item.data)
1542 .arg.typeOf(builder),
4340 .val.typeOf(builder),
15434341 .shufflevector => {
15444342 const extra = builder.constantExtraData(ShuffleVector, item.data);
1545 const ty = extra.lhs.typeOf(builder);
1546 return switch (ty.vectorKind(builder)) {
1547 inline else => |kind| builder.vectorTypeAssumeCapacity(
1548 kind,
1549 extra.mask.typeOf(builder).vectorLen(builder),
1550 ty.childType(builder),
1551 ),
1552 };
4343 return extra.lhs.typeOf(builder).changeLengthAssumeCapacity(
4344 extra.mask.typeOf(builder).vectorLen(builder),
4345 builder,
4346 );
15534347 },
15544348 .add,
15554349 .@"add nsw",
......@@ -1617,7 +4411,42 @@ pub const Constant = enum(u32) {
16174411 }
16184412 }
16194413
1620 pub const FormatData = struct {
4414 pub fn getBase(self: Constant, builder: *const Builder) Global.Index {
4415 var cur = self;
4416 while (true) switch (cur.unwrap()) {
4417 .constant => |constant| {
4418 const item = builder.constant_items.get(constant);
4419 switch (item.tag) {
4420 .ptrtoint,
4421 .inttoptr,
4422 .bitcast,
4423 => cur = builder.constantExtraData(Cast, item.data).val,
4424 .getelementptr => cur = builder.constantExtraData(GetElementPtr, item.data).base,
4425 .add => {
4426 const extra = builder.constantExtraData(Binary, item.data);
4427 const lhs_base = extra.lhs.getBase(builder);
4428 const rhs_base = extra.rhs.getBase(builder);
4429 return if (lhs_base != .none and rhs_base != .none)
4430 .none
4431 else if (lhs_base != .none) lhs_base else rhs_base;
4432 },
4433 .sub => {
4434 const extra = builder.constantExtraData(Binary, item.data);
4435 if (extra.rhs.getBase(builder) != .none) return .none;
4436 cur = extra.lhs;
4437 },
4438 else => return .none,
4439 }
4440 },
4441 .global => |global| switch (global.ptrConst(builder).kind) {
4442 .alias => |alias| cur = alias.ptrConst(builder).init,
4443 .variable, .function => return global,
4444 .replaced => unreachable,
4445 },
4446 };
4447 }
4448
4449 const FormatData = struct {
16214450 constant: Constant,
16224451 builder: *Builder,
16234452 };
......@@ -1627,12 +4456,18 @@ pub const Constant = enum(u32) {
16274456 _: std.fmt.FormatOptions,
16284457 writer: anytype,
16294458 ) @TypeOf(writer).Error!void {
1630 if (comptime std.mem.eql(u8, fmt_str, "%")) {
1631 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
1632 } else if (comptime std.mem.eql(u8, fmt_str, " ")) {
4459 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
4460 @compileError("invalid format string: '" ++ fmt_str ++ "'");
4461 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
4462 if (data.constant == .no_init) return;
4463 try writer.writeByte(',');
4464 }
4465 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
16334466 if (data.constant == .no_init) return;
16344467 try writer.writeByte(' ');
16354468 }
4469 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null)
4470 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
16364471 assert(data.constant != .no_init);
16374472 if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
16384473 switch (data.constant.unwrap()) {
......@@ -1770,10 +4605,10 @@ pub const Constant = enum(u32) {
17704605 .dso_local_equivalent,
17714606 .no_cfi,
17724607 => |tag| {
1773 const extra = data.builder.constantExtraData(FunctionReference, item.data);
4608 const function: Function.Index = @enumFromInt(item.data);
17744609 try writer.print("{s} {}", .{
17754610 @tagName(tag),
1776 extra.function.ptrConst(data.builder).global.fmt(data.builder),
4611 function.ptrConst(data.builder).global.fmt(data.builder),
17774612 });
17784613 },
17794614 .trunc,
......@@ -1793,7 +4628,7 @@ pub const Constant = enum(u32) {
17934628 const extra = data.builder.constantExtraData(Cast, item.data);
17944629 try writer.print("{s} ({%} to {%})", .{
17954630 @tagName(tag),
1796 extra.arg.fmt(data.builder),
4631 extra.val.fmt(data.builder),
17974632 extra.type.fmt(data.builder),
17984633 });
17994634 },
......@@ -1802,7 +4637,7 @@ pub const Constant = enum(u32) {
18024637 => |tag| {
18034638 const extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
18044639 const indices: []const Constant = @ptrCast(data.builder.constant_extra
1805 .items[extra.end..][0..extra.data.indices_len]);
4640 .items[extra.end..][0..extra.data.info.indices_len]);
18064641 try writer.print("{s} ({%}, {%}", .{
18074642 @tagName(tag),
18084643 extra.data.type.fmt(data.builder),
......@@ -1830,7 +4665,7 @@ pub const Constant = enum(u32) {
18304665 const extra = data.builder.constantExtraData(ExtractElement, item.data);
18314666 try writer.print("{s} ({%}, {%})", .{
18324667 @tagName(tag),
1833 extra.arg.fmt(data.builder),
4668 extra.val.fmt(data.builder),
18344669 extra.index.fmt(data.builder),
18354670 });
18364671 },
......@@ -1838,7 +4673,7 @@ pub const Constant = enum(u32) {
18384673 const extra = data.builder.constantExtraData(InsertElement, item.data);
18394674 try writer.print("{s} ({%}, {%}, {%})", .{
18404675 @tagName(tag),
1841 extra.arg.fmt(data.builder),
4676 extra.val.fmt(data.builder),
18424677 extra.elem.fmt(data.builder),
18434678 extra.index.fmt(data.builder),
18444679 });
......@@ -1894,6 +4729,7 @@ pub const Constant = enum(u32) {
18944729};
18954730
18964731pub const Value = enum(u32) {
4732 none = std.math.maxInt(u31),
18974733 _,
18984734
18994735 const first_constant: Value = @enumFromInt(1 << 31);
......@@ -1903,10 +4739,65 @@ pub const Value = enum(u32) {
19034739 constant: Constant,
19044740 } {
19054741 return if (@intFromEnum(self) < @intFromEnum(first_constant))
1906 .{ .instruction = @intFromEnum(self) }
4742 .{ .instruction = @enumFromInt(@intFromEnum(self)) }
19074743 else
19084744 .{ .constant = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_constant)) };
19094745 }
4746
4747 pub fn typeOfWip(self: Value, wip: *const WipFunction) Type {
4748 return switch (self.unwrap()) {
4749 .instruction => |instruction| instruction.typeOfWip(wip),
4750 .constant => |constant| constant.typeOf(wip.builder),
4751 };
4752 }
4753
4754 pub fn typeOf(self: Value, function: Function.Index, builder: *Builder) Type {
4755 return switch (self.unwrap()) {
4756 .instruction => |instruction| instruction.typeOf(function, builder),
4757 .constant => |constant| constant.typeOf(builder),
4758 };
4759 }
4760
4761 pub fn toConst(self: Value) ?Constant {
4762 return switch (self.unwrap()) {
4763 .instruction => null,
4764 .constant => |constant| constant,
4765 };
4766 }
4767
4768 const FormatData = struct {
4769 value: Value,
4770 function: Function.Index,
4771 builder: *Builder,
4772 };
4773 fn format(
4774 data: FormatData,
4775 comptime fmt_str: []const u8,
4776 fmt_opts: std.fmt.FormatOptions,
4777 writer: anytype,
4778 ) @TypeOf(writer).Error!void {
4779 switch (data.value.unwrap()) {
4780 .instruction => |instruction| try Function.Instruction.Index.format(.{
4781 .instruction = instruction,
4782 .function = data.function,
4783 .builder = data.builder,
4784 }, fmt_str, fmt_opts, writer),
4785 .constant => |constant| try Constant.format(.{
4786 .constant = constant,
4787 .builder = data.builder,
4788 }, fmt_str, fmt_opts, writer),
4789 }
4790 }
4791 pub fn fmt(self: Value, function: Function.Index, builder: *Builder) std.fmt.Formatter(format) {
4792 return .{ .data = .{ .value = self, .function = function, .builder = builder } };
4793 }
4794
4795 pub fn toLlvm(self: Value, wip: *const WipFunction) *llvm.Value {
4796 return switch (self.unwrap()) {
4797 .instruction => |instruction| instruction.toLlvm(wip),
4798 .constant => |constant| constant.toLlvm(wip.builder),
4799 };
4800 }
19104801};
19114802
19124803pub const Metadata = enum(u32) { _ };
......@@ -2297,12 +5188,12 @@ pub fn fnType(
22975188}
22985189
22995190pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
2300 try self.ensureUnusedTypeCapacity(1, null, 0);
5191 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
23015192 return self.intTypeAssumeCapacity(bits);
23025193}
23035194
23045195pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {
2305 try self.ensureUnusedTypeCapacity(1, null, 0);
5196 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
23065197 return self.ptrTypeAssumeCapacity(addr_space);
23075198}
23085199
......@@ -2376,7 +5267,7 @@ pub fn namedTypeSetBody(
23765267
23775268pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
23785269 assert(!name.isAnon());
2379 try self.ensureUnusedTypeCapacity(1, null, 0);
5270 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
23805271 try self.ensureUnusedGlobalCapacity(name);
23815272 return self.addGlobalAssumeCapacity(name, global);
23825273}
......@@ -2422,6 +5313,10 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta
24225313 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());
24235314}
24245315
5316pub fn intValue(self: *Builder, ty: Type, value: anytype) Allocator.Error!Value {
5317 return (try self.intConst(ty, value)).toValue();
5318}
5319
24255320pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Constant {
24265321 try self.constant_map.ensureUnusedCapacity(self.gpa, 1);
24275322 try self.constant_items.ensureUnusedCapacity(self.gpa, 1);
......@@ -2430,6 +5325,10 @@ pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allo
24305325 return self.bigIntConstAssumeCapacity(ty, value);
24315326}
24325327
5328pub fn bigIntValue(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Value {
5329 return (try self.bigIntConst(ty, value)).toValue();
5330}
5331
24335332pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator.Error!Constant {
24345333 return switch (ty) {
24355334 .half => try self.halfConst(val),
......@@ -2438,88 +5337,169 @@ pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator
24385337 .double => try self.doubleConst(val),
24395338 .fp128 => try self.fp128Const(val),
24405339 .x86_fp80 => try self.x86_fp80Const(val),
2441 .ppc_fp128 => try self.ppc_fp128Const(.{ val, 0 }),
5340 .ppc_fp128 => try self.ppc_fp128Const(.{ val, -0.0 }),
5341 else => unreachable,
5342 };
5343}
5344
5345pub fn fpValue(self: *Builder, ty: Type, comptime value: comptime_float) Allocator.Error!Value {
5346 return (try self.fpConst(ty, value)).toValue();
5347}
5348
5349pub fn nanConst(self: *Builder, ty: Type) Allocator.Error!Constant {
5350 return switch (ty) {
5351 .half => try self.halfConst(std.math.nan(f16)),
5352 .bfloat => try self.bfloatConst(std.math.nan(f32)),
5353 .float => try self.floatConst(std.math.nan(f32)),
5354 .double => try self.doubleConst(std.math.nan(f64)),
5355 .fp128 => try self.fp128Const(std.math.nan(f128)),
5356 .x86_fp80 => try self.x86_fp80Const(std.math.nan(f80)),
5357 .ppc_fp128 => try self.ppc_fp128Const(.{std.math.nan(f64)} ** 2),
24425358 else => unreachable,
24435359 };
24445360}
24455361
5362pub fn nanValue(self: *Builder, ty: Type) Allocator.Error!Value {
5363 return (try self.nanConst(ty)).toValue();
5364}
5365
24465366pub fn halfConst(self: *Builder, val: f16) Allocator.Error!Constant {
2447 try self.ensureUnusedConstantCapacity(1, null, 0);
5367 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
24485368 return self.halfConstAssumeCapacity(val);
24495369}
24505370
5371pub fn halfValue(self: *Builder, ty: Type, value: f16) Allocator.Error!Value {
5372 return (try self.halfConst(ty, value)).toValue();
5373}
5374
24515375pub fn bfloatConst(self: *Builder, val: f32) Allocator.Error!Constant {
2452 try self.ensureUnusedConstantCapacity(1, null, 0);
5376 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
24535377 return self.bfloatConstAssumeCapacity(val);
24545378}
24555379
5380pub fn bfloatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
5381 return (try self.bfloatConst(ty, value)).toValue();
5382}
5383
24565384pub fn floatConst(self: *Builder, val: f32) Allocator.Error!Constant {
2457 try self.ensureUnusedConstantCapacity(1, null, 0);
5385 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
24585386 return self.floatConstAssumeCapacity(val);
24595387}
24605388
5389pub fn floatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
5390 return (try self.floatConst(ty, value)).toValue();
5391}
5392
24615393pub fn doubleConst(self: *Builder, val: f64) Allocator.Error!Constant {
24625394 try self.ensureUnusedConstantCapacity(1, Constant.Double, 0);
24635395 return self.doubleConstAssumeCapacity(val);
24645396}
24655397
5398pub fn doubleValue(self: *Builder, ty: Type, value: f64) Allocator.Error!Value {
5399 return (try self.doubleConst(ty, value)).toValue();
5400}
5401
24665402pub fn fp128Const(self: *Builder, val: f128) Allocator.Error!Constant {
24675403 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
24685404 return self.fp128ConstAssumeCapacity(val);
24695405}
24705406
5407pub fn fp128Value(self: *Builder, ty: Type, value: f128) Allocator.Error!Value {
5408 return (try self.fp128Const(ty, value)).toValue();
5409}
5410
24715411pub fn x86_fp80Const(self: *Builder, val: f80) Allocator.Error!Constant {
24725412 try self.ensureUnusedConstantCapacity(1, Constant.Fp80, 0);
24735413 return self.x86_fp80ConstAssumeCapacity(val);
24745414}
24755415
5416pub fn x86_fp80Value(self: *Builder, ty: Type, value: f80) Allocator.Error!Value {
5417 return (try self.x86_fp80Const(ty, value)).toValue();
5418}
5419
24765420pub fn ppc_fp128Const(self: *Builder, val: [2]f64) Allocator.Error!Constant {
24775421 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
24785422 return self.ppc_fp128ConstAssumeCapacity(val);
24795423}
24805424
5425pub fn ppc_fp128Value(self: *Builder, ty: Type, value: [2]f64) Allocator.Error!Value {
5426 return (try self.ppc_fp128Const(ty, value)).toValue();
5427}
5428
24815429pub fn nullConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2482 try self.ensureUnusedConstantCapacity(1, null, 0);
5430 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
24835431 return self.nullConstAssumeCapacity(ty);
24845432}
24855433
5434pub fn nullValue(self: *Builder, ty: Type) Allocator.Error!Value {
5435 return (try self.nullConst(ty)).toValue();
5436}
5437
24865438pub fn noneConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2487 try self.ensureUnusedConstantCapacity(1, null, 0);
5439 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
24885440 return self.noneConstAssumeCapacity(ty);
24895441}
24905442
5443pub fn noneValue(self: *Builder, ty: Type) Allocator.Error!Value {
5444 return (try self.noneConst(ty)).toValue();
5445}
5446
24915447pub fn structConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
24925448 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
24935449 return self.structConstAssumeCapacity(ty, vals);
24945450}
24955451
5452pub fn structValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
5453 return (try self.structConst(ty, vals)).toValue();
5454}
5455
24965456pub fn arrayConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
24975457 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
24985458 return self.arrayConstAssumeCapacity(ty, vals);
24995459}
25005460
5461pub fn arrayValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
5462 return (try self.arrayConst(ty, vals)).toValue();
5463}
5464
25015465pub fn stringConst(self: *Builder, val: String) Allocator.Error!Constant {
25025466 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
2503 try self.ensureUnusedConstantCapacity(1, null, 0);
5467 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
25045468 return self.stringConstAssumeCapacity(val);
25055469}
25065470
5471pub fn stringValue(self: *Builder, val: String) Allocator.Error!Value {
5472 return (try self.stringConst(val)).toValue();
5473}
5474
25075475pub fn stringNullConst(self: *Builder, val: String) Allocator.Error!Constant {
25085476 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
2509 try self.ensureUnusedConstantCapacity(1, null, 0);
5477 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
25105478 return self.stringNullConstAssumeCapacity(val);
25115479}
25125480
5481pub fn stringNullValue(self: *Builder, val: String) Allocator.Error!Value {
5482 return (try self.stringNullConst(val)).toValue();
5483}
5484
25135485pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
25145486 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
25155487 return self.vectorConstAssumeCapacity(ty, vals);
25165488}
25175489
5490pub fn vectorValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
5491 return (try self.vectorConst(ty, vals)).toValue();
5492}
5493
25185494pub fn splatConst(self: *Builder, ty: Type, val: Constant) Allocator.Error!Constant {
25195495 try self.ensureUnusedConstantCapacity(1, Constant.Splat, 0);
25205496 return self.splatConstAssumeCapacity(ty, val);
25215497}
25225498
5499pub fn splatValue(self: *Builder, ty: Type, val: Constant) Allocator.Error!Value {
5500 return (try self.splatConst(ty, val)).toValue();
5501}
5502
25235503pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
25245504 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
25255505 try self.constant_limbs.ensureUnusedCapacity(
......@@ -2529,16 +5509,28 @@ pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
25295509 return self.zeroInitConstAssumeCapacity(ty);
25305510}
25315511
5512pub fn zeroInitValue(self: *Builder, ty: Type) Allocator.Error!Value {
5513 return (try self.zeroInitConst(ty)).toValue();
5514}
5515
25325516pub fn undefConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2533 try self.ensureUnusedConstantCapacity(1, null, 0);
5517 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
25345518 return self.undefConstAssumeCapacity(ty);
25355519}
25365520
5521pub fn undefValue(self: *Builder, ty: Type) Allocator.Error!Value {
5522 return (try self.undefConst(ty)).toValue();
5523}
5524
25375525pub fn poisonConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2538 try self.ensureUnusedConstantCapacity(1, null, 0);
5526 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
25395527 return self.poisonConstAssumeCapacity(ty);
25405528}
25415529
5530pub fn poisonValue(self: *Builder, ty: Type) Allocator.Error!Value {
5531 return (try self.poisonConst(ty)).toValue();
5532}
5533
25425534pub fn blockAddrConst(
25435535 self: *Builder,
25445536 function: Function.Index,
......@@ -2548,29 +5540,58 @@ pub fn blockAddrConst(
25485540 return self.blockAddrConstAssumeCapacity(function, block);
25495541}
25505542
5543pub fn blockAddrValue(
5544 self: *Builder,
5545 function: Function.Index,
5546 block: Function.Block.Index,
5547) Allocator.Error!Value {
5548 return (try self.blockAddrConst(function, block)).toValue();
5549}
5550
25515551pub fn dsoLocalEquivalentConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
2552 try self.ensureUnusedConstantCapacity(1, Constant.FunctionReference, 0);
5552 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
25535553 return self.dsoLocalEquivalentConstAssumeCapacity(function);
25545554}
25555555
5556pub fn dsoLocalEquivalentValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
5557 return (try self.dsoLocalEquivalentConst(function)).toValue();
5558}
5559
25565560pub fn noCfiConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
2557 try self.ensureUnusedConstantCapacity(1, Constant.FunctionReference, 0);
5561 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
25585562 return self.noCfiConstAssumeCapacity(function);
25595563}
25605564
5565pub fn noCfiValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
5566 return (try self.noCfiConst(function)).toValue();
5567}
5568
25615569pub fn convConst(
25625570 self: *Builder,
25635571 signedness: Constant.Cast.Signedness,
2564 arg: Constant,
5572 val: Constant,
25655573 ty: Type,
25665574) Allocator.Error!Constant {
25675575 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
2568 return self.convConstAssumeCapacity(signedness, arg, ty);
5576 return self.convConstAssumeCapacity(signedness, val, ty);
5577}
5578
5579pub fn convValue(
5580 self: *Builder,
5581 signedness: Constant.Cast.Signedness,
5582 val: Constant,
5583 ty: Type,
5584) Allocator.Error!Value {
5585 return (try self.convConst(signedness, val, ty)).toValue();
25695586}
25705587
2571pub fn castConst(self: *Builder, tag: Constant.Tag, arg: Constant, ty: Type) Allocator.Error!Constant {
5588pub fn castConst(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Allocator.Error!Constant {
25725589 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
2573 return self.castConstAssumeCapacity(tag, arg, ty);
5590 return self.castConstAssumeCapacity(tag, val, ty);
5591}
5592
5593pub fn castValue(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Allocator.Error!Value {
5594 return (try self.castConst(tag, val, ty)).toValue();
25745595}
25755596
25765597pub fn gepConst(
......@@ -2578,11 +5599,23 @@ pub fn gepConst(
25785599 comptime kind: Constant.GetElementPtr.Kind,
25795600 ty: Type,
25805601 base: Constant,
5602 inrange: ?u16,
25815603 indices: []const Constant,
25825604) Allocator.Error!Constant {
25835605 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
25845606 try self.ensureUnusedConstantCapacity(1, Constant.GetElementPtr, indices.len);
2585 return self.gepConstAssumeCapacity(kind, ty, base, indices);
5607 return self.gepConstAssumeCapacity(kind, ty, base, inrange, indices);
5608}
5609
5610pub fn gepValue(
5611 self: *Builder,
5612 comptime kind: Constant.GetElementPtr.Kind,
5613 ty: Type,
5614 base: Constant,
5615 inrange: ?u16,
5616 indices: []const Constant,
5617) Allocator.Error!Value {
5618 return (try self.gepConst(kind, ty, base, inrange, indices)).toValue();
25865619}
25875620
25885621pub fn icmpConst(
......@@ -2595,6 +5628,15 @@ pub fn icmpConst(
25955628 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
25965629}
25975630
5631pub fn icmpValue(
5632 self: *Builder,
5633 cond: IntegerCondition,
5634 lhs: Constant,
5635 rhs: Constant,
5636) Allocator.Error!Value {
5637 return (try self.icmpConst(cond, lhs, rhs)).toValue();
5638}
5639
25985640pub fn fcmpConst(
25995641 self: *Builder,
26005642 cond: FloatCondition,
......@@ -2605,19 +5647,41 @@ pub fn fcmpConst(
26055647 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
26065648}
26075649
2608pub fn extractElementConst(self: *Builder, arg: Constant, index: Constant) Allocator.Error!Constant {
5650pub fn fcmpValue(
5651 self: *Builder,
5652 cond: FloatCondition,
5653 lhs: Constant,
5654 rhs: Constant,
5655) Allocator.Error!Value {
5656 return (try self.fcmpConst(cond, lhs, rhs)).toValue();
5657}
5658
5659pub fn extractElementConst(self: *Builder, val: Constant, index: Constant) Allocator.Error!Constant {
26095660 try self.ensureUnusedConstantCapacity(1, Constant.ExtractElement, 0);
2610 return self.extractElementConstAssumeCapacity(arg, index);
5661 return self.extractElementConstAssumeCapacity(val, index);
5662}
5663
5664pub fn extractElementValue(self: *Builder, val: Constant, index: Constant) Allocator.Error!Value {
5665 return (try self.extractElementConst(val, index)).toValue();
26115666}
26125667
26135668pub fn insertElementConst(
26145669 self: *Builder,
2615 arg: Constant,
5670 val: Constant,
26165671 elem: Constant,
26175672 index: Constant,
26185673) Allocator.Error!Constant {
26195674 try self.ensureUnusedConstantCapacity(1, Constant.InsertElement, 0);
2620 return self.insertElementConstAssumeCapacity(arg, elem, index);
5675 return self.insertElementConstAssumeCapacity(val, elem, index);
5676}
5677
5678pub fn insertElementValue(
5679 self: *Builder,
5680 val: Constant,
5681 elem: Constant,
5682 index: Constant,
5683) Allocator.Error!Value {
5684 return (try self.insertElementConst(val, elem, index)).toValue();
26215685}
26225686
26235687pub fn shuffleVectorConst(
......@@ -2626,10 +5690,20 @@ pub fn shuffleVectorConst(
26265690 rhs: Constant,
26275691 mask: Constant,
26285692) Allocator.Error!Constant {
5693 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
26295694 try self.ensureUnusedConstantCapacity(1, Constant.ShuffleVector, 0);
26305695 return self.shuffleVectorConstAssumeCapacity(lhs, rhs, mask);
26315696}
26325697
5698pub fn shuffleVectorValue(
5699 self: *Builder,
5700 lhs: Constant,
5701 rhs: Constant,
5702 mask: Constant,
5703) Allocator.Error!Value {
5704 return (try self.shuffleVectorConst(lhs, rhs, mask)).toValue();
5705}
5706
26335707pub fn binConst(
26345708 self: *Builder,
26355709 tag: Constant.Tag,
......@@ -2640,6 +5714,10 @@ pub fn binConst(
26405714 return self.binConstAssumeCapacity(tag, lhs, rhs);
26415715}
26425716
5717pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant) Allocator.Error!Value {
5718 return (try self.binConst(tag, lhs, rhs)).toValue();
5719}
5720
26435721pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void {
26445722 if (self.source_filename != .none) try writer.print(
26455723 \\; ModuleID = '{s}'
......@@ -2679,17 +5757,15 @@ pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator
26795757 @tagName(variable.mutability),
26805758 global.type.fmt(self),
26815759 variable.init.fmt(self),
2682 global.alignment,
5760 variable.alignment,
26835761 });
26845762 }
26855763 try writer.writeByte('\n');
2686 for (self.functions.items) |function| {
5764 for (0.., self.functions.items) |function_i, function| {
5765 const function_index: Function.Index = @enumFromInt(function_i);
26875766 if (function.global.getReplacement(self) != .none) continue;
26885767 const global = function.global.ptrConst(self);
2689 const item = self.type_items.items[@intFromEnum(global.type)];
2690 const extra = self.typeExtraDataTrail(Type.Function, item.data);
2691 const params: []const Type =
2692 @ptrCast(self.type_extra.items[extra.end..][0..extra.data.params_len]);
5768 const params_len = global.type.functionParameters(self).len;
26935769 try writer.print(
26945770 \\{s}{}{}{}{} {} {}(
26955771 , .{
......@@ -2698,31 +5774,398 @@ pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator
26985774 global.preemption,
26995775 global.visibility,
27005776 global.dll_storage_class,
2701 extra.data.ret.fmt(self),
5777 global.type.functionReturn(self).fmt(self),
27025778 function.global.fmt(self),
27035779 });
2704 for (params, 0..) |param, index| {
2705 if (index > 0) try writer.writeAll(", ");
2706 try writer.print("{%} %{d}", .{ param.fmt(self), index });
5780 for (0..params_len) |arg| {
5781 if (arg > 0) try writer.writeAll(", ");
5782 try writer.print("{%}", .{function.arg(@intCast(arg)).fmt(function_index, self)});
27075783 }
2708 switch (item.tag) {
2709 .function => {},
2710 .vararg_function => {
2711 if (params.len > 0) try writer.writeAll(", ");
5784 switch (global.type.functionKind(self)) {
5785 .normal => {},
5786 .vararg => {
5787 if (params_len > 0) try writer.writeAll(", ");
27125788 try writer.writeAll("...");
27135789 },
2714 else => unreachable,
27155790 }
2716 try writer.print("){}{}", .{ global.unnamed_addr, global.alignment });
5791 try writer.print("){}{}", .{ global.unnamed_addr, function.alignment });
27175792 if (function.instructions.len > 0) {
27185793 try writer.writeAll(" {\n");
2719 for (0..function.instructions.len) |index| {
2720 const instruction_index: Function.Instruction.Index = @enumFromInt(index);
2721 const instruction = function.instructions.get(index);
5794 for (params_len..function.instructions.len) |instruction_i| {
5795 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
5796 const instruction = function.instructions.get(@intFromEnum(instruction_index));
27225797 switch (instruction.tag) {
2723 .block => try writer.print("{}:\n", .{instruction_index.name(&function).fmt(self)}),
2724 .@"ret void" => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),
2725 else => unreachable,
5798 .add,
5799 .@"add nsw",
5800 .@"add nuw",
5801 .@"add nuw nsw",
5802 .@"and",
5803 .ashr,
5804 .@"ashr exact",
5805 .fadd,
5806 .@"fadd fast",
5807 .@"fcmp false",
5808 .@"fcmp fast false",
5809 .@"fcmp fast oeq",
5810 .@"fcmp fast oge",
5811 .@"fcmp fast ogt",
5812 .@"fcmp fast ole",
5813 .@"fcmp fast olt",
5814 .@"fcmp fast one",
5815 .@"fcmp fast ord",
5816 .@"fcmp fast true",
5817 .@"fcmp fast ueq",
5818 .@"fcmp fast uge",
5819 .@"fcmp fast ugt",
5820 .@"fcmp fast ule",
5821 .@"fcmp fast ult",
5822 .@"fcmp fast une",
5823 .@"fcmp fast uno",
5824 .@"fcmp oeq",
5825 .@"fcmp oge",
5826 .@"fcmp ogt",
5827 .@"fcmp ole",
5828 .@"fcmp olt",
5829 .@"fcmp one",
5830 .@"fcmp ord",
5831 .@"fcmp true",
5832 .@"fcmp ueq",
5833 .@"fcmp uge",
5834 .@"fcmp ugt",
5835 .@"fcmp ule",
5836 .@"fcmp ult",
5837 .@"fcmp une",
5838 .@"fcmp uno",
5839 .fdiv,
5840 .@"fdiv fast",
5841 .fmul,
5842 .@"fmul fast",
5843 .frem,
5844 .@"frem fast",
5845 .fsub,
5846 .@"fsub fast",
5847 .@"icmp eq",
5848 .@"icmp ne",
5849 .@"icmp sge",
5850 .@"icmp sgt",
5851 .@"icmp sle",
5852 .@"icmp slt",
5853 .@"icmp uge",
5854 .@"icmp ugt",
5855 .@"icmp ule",
5856 .@"icmp ult",
5857 .lshr,
5858 .@"lshr exact",
5859 .mul,
5860 .@"mul nsw",
5861 .@"mul nuw",
5862 .@"mul nuw nsw",
5863 .@"or",
5864 .sdiv,
5865 .@"sdiv exact",
5866 .srem,
5867 .shl,
5868 .@"shl nsw",
5869 .@"shl nuw",
5870 .@"shl nuw nsw",
5871 .sub,
5872 .@"sub nsw",
5873 .@"sub nuw",
5874 .@"sub nuw nsw",
5875 .udiv,
5876 .@"udiv exact",
5877 .urem,
5878 .xor,
5879 => |tag| {
5880 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
5881 try writer.print(" %{} = {s} {%}, {}\n", .{
5882 instruction_index.name(&function).fmt(self),
5883 @tagName(tag),
5884 extra.lhs.fmt(function_index, self),
5885 extra.rhs.fmt(function_index, self),
5886 });
5887 },
5888 .addrspacecast,
5889 .bitcast,
5890 .fpext,
5891 .fptosi,
5892 .fptoui,
5893 .fptrunc,
5894 .inttoptr,
5895 .ptrtoint,
5896 .sext,
5897 .sitofp,
5898 .trunc,
5899 .uitofp,
5900 .zext,
5901 => |tag| {
5902 const extra = function.extraData(Function.Instruction.Cast, instruction.data);
5903 try writer.print(" %{} = {s} {%} to {%}\n", .{
5904 instruction_index.name(&function).fmt(self),
5905 @tagName(tag),
5906 extra.val.fmt(function_index, self),
5907 extra.type.fmt(self),
5908 });
5909 },
5910 .alloca,
5911 .@"alloca inalloca",
5912 => |tag| {
5913 const extra = function.extraData(Function.Instruction.Alloca, instruction.data);
5914 try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{
5915 instruction_index.name(&function).fmt(self),
5916 @tagName(tag),
5917 extra.type.fmt(self),
5918 extra.len.fmt(function_index, self),
5919 extra.info.alignment,
5920 extra.info.addr_space,
5921 });
5922 },
5923 .arg => unreachable,
5924 .block => {
5925 const name = instruction_index.name(&function);
5926 if (@intFromEnum(instruction_index) > params_len) try writer.writeByte('\n');
5927 try writer.print("{}:\n", .{name.fmt(self)});
5928 },
5929 .br => |tag| {
5930 const target: Function.Block.Index = @enumFromInt(instruction.data);
5931 try writer.print(" {s} {%}\n", .{
5932 @tagName(tag), target.toInst(&function).fmt(function_index, self),
5933 });
5934 },
5935 .br_cond => {
5936 const extra = function.extraData(Function.Instruction.BrCond, instruction.data);
5937 try writer.print(" br {%}, {%}, {%}\n", .{
5938 extra.cond.fmt(function_index, self),
5939 extra.then.toInst(&function).fmt(function_index, self),
5940 extra.@"else".toInst(&function).fmt(function_index, self),
5941 });
5942 },
5943 .extractelement => |tag| {
5944 const extra =
5945 function.extraData(Function.Instruction.ExtractElement, instruction.data);
5946 try writer.print(" %{} = {s} {%}, {%}\n", .{
5947 instruction_index.name(&function).fmt(self),
5948 @tagName(tag),
5949 extra.val.fmt(function_index, self),
5950 extra.index.fmt(function_index, self),
5951 });
5952 },
5953 .extractvalue => |tag| {
5954 const extra =
5955 function.extraDataTrail(Function.Instruction.ExtractValue, instruction.data);
5956 const indices: []const u32 =
5957 function.extra[extra.end..][0..extra.data.indices_len];
5958 try writer.print(" %{} = {s} {%}", .{
5959 instruction_index.name(&function).fmt(self),
5960 @tagName(tag),
5961 extra.data.val.fmt(function_index, self),
5962 });
5963 for (indices) |index| try writer.print(", {d}", .{index});
5964 try writer.writeByte('\n');
5965 },
5966 .fence => |tag| {
5967 const info: MemoryAccessInfo = @bitCast(instruction.data);
5968 try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering });
5969 },
5970 .fneg,
5971 .@"fneg fast",
5972 .ret,
5973 => |tag| {
5974 const val: Value = @enumFromInt(instruction.data);
5975 try writer.print(" {s} {%}\n", .{
5976 @tagName(tag),
5977 val.fmt(function_index, self),
5978 });
5979 },
5980 .getelementptr,
5981 .@"getelementptr inbounds",
5982 => |tag| {
5983 const extra = function.extraDataTrail(
5984 Function.Instruction.GetElementPtr,
5985 instruction.data,
5986 );
5987 const indices: []const Value =
5988 @ptrCast(function.extra[extra.end..][0..extra.data.indices_len]);
5989 try writer.print(" %{} = {s} {%}, {%}", .{
5990 instruction_index.name(&function).fmt(self),
5991 @tagName(tag),
5992 extra.data.type.fmt(self),
5993 extra.data.base.fmt(function_index, self),
5994 });
5995 for (indices) |index| try writer.print(", {%}", .{
5996 index.fmt(function_index, self),
5997 });
5998 try writer.writeByte('\n');
5999 },
6000 .insertelement => |tag| {
6001 const extra =
6002 function.extraData(Function.Instruction.InsertElement, instruction.data);
6003 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6004 instruction_index.name(&function).fmt(self),
6005 @tagName(tag),
6006 extra.val.fmt(function_index, self),
6007 extra.elem.fmt(function_index, self),
6008 extra.index.fmt(function_index, self),
6009 });
6010 },
6011 .insertvalue => |tag| {
6012 const extra =
6013 function.extraDataTrail(Function.Instruction.InsertValue, instruction.data);
6014 const indices: []const u32 =
6015 function.extra[extra.end..][0..extra.data.indices_len];
6016 try writer.print(" %{} = {s} {%}, {%}", .{
6017 instruction_index.name(&function).fmt(self),
6018 @tagName(tag),
6019 extra.data.val.fmt(function_index, self),
6020 extra.data.elem.fmt(function_index, self),
6021 });
6022 for (indices) |index| try writer.print(", {d}", .{index});
6023 try writer.writeByte('\n');
6024 },
6025 .@"llvm.maxnum.",
6026 .@"llvm.minnum.",
6027 .@"llvm.sadd.sat.",
6028 .@"llvm.smax.",
6029 .@"llvm.smin.",
6030 .@"llvm.smul.fix.sat.",
6031 .@"llvm.sshl.sat.",
6032 .@"llvm.ssub.sat.",
6033 .@"llvm.uadd.sat.",
6034 .@"llvm.umax.",
6035 .@"llvm.umin.",
6036 .@"llvm.umul.fix.sat.",
6037 .@"llvm.ushl.sat.",
6038 .@"llvm.usub.sat.",
6039 => |tag| {
6040 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
6041 const ty = instruction_index.typeOf(function_index, self);
6042 try writer.print(" %{} = call {%} @{s}{m}({%}, {%})\n", .{
6043 instruction_index.name(&function).fmt(self),
6044 ty.fmt(self),
6045 @tagName(tag),
6046 ty.fmt(self),
6047 extra.lhs.fmt(function_index, self),
6048 extra.rhs.fmt(function_index, self),
6049 });
6050 },
6051 .load,
6052 .@"load atomic",
6053 .@"load atomic volatile",
6054 .@"load volatile",
6055 => |tag| {
6056 const extra = function.extraData(Function.Instruction.Load, instruction.data);
6057 try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{
6058 instruction_index.name(&function).fmt(self),
6059 @tagName(tag),
6060 extra.type.fmt(self),
6061 extra.ptr.fmt(function_index, self),
6062 extra.info.scope,
6063 extra.info.ordering,
6064 extra.info.alignment,
6065 });
6066 },
6067 .phi,
6068 .@"phi fast",
6069 => |tag| {
6070 const extra =
6071 function.extraDataTrail(Function.Instruction.Phi, instruction.data);
6072 const vals: []const Value =
6073 @ptrCast(function.extra[extra.end..][0..extra.data.incoming_len]);
6074 const blocks: []const Function.Block.Index = @ptrCast(function.extra[extra.end +
6075 extra.data.incoming_len ..][0..extra.data.incoming_len]);
6076 try writer.print(" %{} = {s} {%} ", .{
6077 instruction_index.name(&function).fmt(self),
6078 @tagName(tag),
6079 vals[0].typeOf(function_index, self).fmt(self),
6080 });
6081 for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
6082 if (incoming_index > 0) try writer.writeAll(", ");
6083 try writer.print("[ {}, {} ]", .{
6084 incoming_val.fmt(function_index, self),
6085 incoming_block.toInst(&function).fmt(function_index, self),
6086 });
6087 }
6088 try writer.writeByte('\n');
6089 },
6090 .@"ret void",
6091 .@"unreachable",
6092 => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),
6093 .select,
6094 .@"select fast",
6095 => |tag| {
6096 const extra = function.extraData(Function.Instruction.Select, instruction.data);
6097 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6098 instruction_index.name(&function).fmt(self),
6099 @tagName(tag),
6100 extra.cond.fmt(function_index, self),
6101 extra.lhs.fmt(function_index, self),
6102 extra.rhs.fmt(function_index, self),
6103 });
6104 },
6105 .shufflevector => |tag| {
6106 const extra =
6107 function.extraData(Function.Instruction.ShuffleVector, instruction.data);
6108 try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{
6109 instruction_index.name(&function).fmt(self),
6110 @tagName(tag),
6111 extra.lhs.fmt(function_index, self),
6112 extra.rhs.fmt(function_index, self),
6113 extra.mask.fmt(function_index, self),
6114 });
6115 },
6116 .store,
6117 .@"store atomic",
6118 .@"store atomic volatile",
6119 .@"store volatile",
6120 => |tag| {
6121 const extra = function.extraData(Function.Instruction.Store, instruction.data);
6122 try writer.print(" {s} {%}, {%}{}{}{,}\n", .{
6123 @tagName(tag),
6124 extra.val.fmt(function_index, self),
6125 extra.ptr.fmt(function_index, self),
6126 extra.info.scope,
6127 extra.info.ordering,
6128 extra.info.alignment,
6129 });
6130 },
6131 .@"switch" => |tag| {
6132 const extra =
6133 function.extraDataTrail(Function.Instruction.Switch, instruction.data);
6134 const vals: []const Constant =
6135 @ptrCast(function.extra[extra.end..][0..extra.data.cases_len]);
6136 const blocks: []const Function.Block.Index = @ptrCast(function.extra[extra.end +
6137 extra.data.cases_len ..][0..extra.data.cases_len]);
6138 try writer.print(" {s} {%}, {%} [", .{
6139 @tagName(tag),
6140 extra.data.val.fmt(function_index, self),
6141 extra.data.default.toInst(&function).fmt(function_index, self),
6142 });
6143 for (vals, blocks) |case_val, case_block| try writer.print(" {%}, {%}\n", .{
6144 case_val.fmt(self),
6145 case_block.toInst(&function).fmt(function_index, self),
6146 });
6147 try writer.writeAll(" ]\n");
6148 },
6149 .unimplemented => |tag| {
6150 const ty: Type = @enumFromInt(instruction.data);
6151 try writer.writeAll(" ");
6152 switch (ty) {
6153 .none, .void => {},
6154 else => try writer.print("%{} = ", .{
6155 instruction_index.name(&function).fmt(self),
6156 }),
6157 }
6158 try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
6159 },
6160 .va_arg => |tag| {
6161 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
6162 try writer.print(" %{} = {s} {%}, {%}\n", .{
6163 instruction_index.name(&function).fmt(self),
6164 @tagName(tag),
6165 extra.list.fmt(function_index, self),
6166 extra.type.fmt(self),
6167 });
6168 },
27266169 }
27276170 }
27286171 try writer.writeByte('}');
......@@ -2731,6 +6174,12 @@ pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator
27316174 }
27326175}
27336176
6177pub inline fn useLibLlvm(self: *const Builder) bool {
6178 return build_options.have_llvm and self.use_lib_llvm;
6179}
6180
6181const NoExtra = struct {};
6182
27346183fn isValidIdentifier(id: []const u8) bool {
27356184 for (id, 0..) |character, index| switch (character) {
27366185 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
......@@ -3048,15 +6497,15 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
30486497fn ensureUnusedTypeCapacity(
30496498 self: *Builder,
30506499 count: usize,
3051 comptime Extra: ?type,
6500 comptime Extra: type,
30526501 trail_len: usize,
30536502) Allocator.Error!void {
30546503 try self.type_map.ensureUnusedCapacity(self.gpa, count);
30556504 try self.type_items.ensureUnusedCapacity(self.gpa, count);
3056 if (Extra) |E| try self.type_extra.ensureUnusedCapacity(
6505 try self.type_extra.ensureUnusedCapacity(
30576506 self.gpa,
3058 count * (@typeInfo(E).Struct.fields.len + trail_len),
3059 ) else assert(trail_len == 0);
6507 count * (@typeInfo(Extra).Struct.fields.len + trail_len),
6508 );
30606509 if (self.useLibLlvm()) try self.llvm.types.ensureUnusedCapacity(self.gpa, count);
30616510}
30626511
......@@ -3104,10 +6553,10 @@ fn typeExtraDataTrail(
31046553) struct { data: T, end: Type.Item.ExtraIndex } {
31056554 var result: T = undefined;
31066555 const fields = @typeInfo(T).Struct.fields;
3107 inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, data|
6556 inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, value|
31086557 @field(result, field.name) = switch (field.type) {
3109 u32 => data,
3110 String, Type => @enumFromInt(data),
6558 u32 => value,
6559 String, Type => @enumFromInt(value),
31116560 else => @compileError("bad field type: " ++ @typeName(field.type)),
31126561 };
31136562 return .{ .data = result, .end = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) };
......@@ -3519,13 +6968,13 @@ fn arrayConstAssumeCapacity(
35196968) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
35206969 const type_item = self.type_items.items[@intFromEnum(ty)];
35216970 const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) {
3522 .small_array => extra: {
3523 const extra = self.typeExtraData(Type.Vector, type_item.data);
3524 break :extra .{ .len = extra.len, .child = extra.child };
3525 },
3526 .array => extra: {
3527 const extra = self.typeExtraData(Type.Array, type_item.data);
3528 break :extra .{ .len = extra.len(), .child = extra.child };
6971 inline .small_array, .array => |kind| extra: {
6972 const extra = self.typeExtraData(switch (kind) {
6973 .small_array => Type.Vector,
6974 .array => Type.Array,
6975 else => unreachable,
6976 }, type_item.data);
6977 break :extra .{ .len = extra.length(), .child = extra.child };
35296978 },
35306979 else => unreachable,
35316980 };
......@@ -3738,7 +7187,7 @@ fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant {
37387187 .{ .tag = .poison, .data = @intFromEnum(ty) },
37397188 );
37407189 if (self.useLibLlvm() and result.new)
3741 self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).getUndef());
7190 self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).getPoison());
37427191 return result.constant;
37437192}
37447193
......@@ -3794,17 +7243,17 @@ fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
37947243 return result.constant;
37957244}
37967245
3797fn convConstAssumeCapacity(
7246fn convTag(
37987247 self: *Builder,
7248 comptime Tag: type,
37997249 signedness: Constant.Cast.Signedness,
3800 arg: Constant,
7250 val_ty: Type,
38017251 ty: Type,
3802) Constant {
3803 const arg_ty = arg.typeOf(self);
3804 if (arg_ty == ty) return arg;
3805 return self.castConstAssumeCapacity(switch (arg_ty.scalarTag(self)) {
7252) Tag {
7253 assert(val_ty != ty);
7254 return switch (val_ty.scalarTag(self)) {
38067255 .simple => switch (ty.scalarTag(self)) {
3807 .simple => switch (std.math.order(arg_ty.scalarBits(self), ty.scalarBits(self))) {
7256 .simple => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
38087257 .lt => .fpext,
38097258 .eq => unreachable,
38107259 .gt => .fptrunc,
......@@ -3816,13 +7265,13 @@ fn convConstAssumeCapacity(
38167265 },
38177266 else => unreachable,
38187267 },
3819 .integer => switch (ty.tag(self)) {
7268 .integer => switch (ty.scalarTag(self)) {
38207269 .simple => switch (signedness) {
38217270 .unsigned => .uitofp,
38227271 .signed => .sitofp,
38237272 .unneeded => unreachable,
38247273 },
3825 .integer => switch (std.math.order(arg_ty.scalarBits(self), ty.scalarBits(self))) {
7274 .integer => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
38267275 .lt => switch (signedness) {
38277276 .unsigned => .zext,
38287277 .signed => .sext,
......@@ -3834,16 +7283,27 @@ fn convConstAssumeCapacity(
38347283 .pointer => .inttoptr,
38357284 else => unreachable,
38367285 },
3837 .pointer => switch (ty.tag(self)) {
7286 .pointer => switch (ty.scalarTag(self)) {
38387287 .integer => .ptrtoint,
38397288 .pointer => .addrspacecast,
38407289 else => unreachable,
38417290 },
38427291 else => unreachable,
3843 }, arg, ty);
7292 };
7293}
7294
7295fn convConstAssumeCapacity(
7296 self: *Builder,
7297 signedness: Constant.Cast.Signedness,
7298 val: Constant,
7299 ty: Type,
7300) Constant {
7301 const val_ty = val.typeOf(self);
7302 if (val_ty == ty) return val;
7303 return self.castConstAssumeCapacity(self.convTag(Constant.Tag, signedness, val_ty, ty), val, ty);
38447304}
38457305
3846fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty: Type) Constant {
7306fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Constant {
38477307 const Key = struct { tag: Constant.Tag, cast: Constant.Cast };
38487308 const Adapter = struct {
38497309 builder: *const Builder,
......@@ -3860,7 +7320,7 @@ fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty:
38607320 return std.meta.eql(lhs_key.cast, rhs_extra);
38617321 }
38627322 };
3863 const data = Key{ .tag = tag, .cast = .{ .arg = arg, .type = ty } };
7323 const data = Key{ .tag = tag, .cast = .{ .val = val, .type = ty } };
38647324 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
38657325 if (!gop.found_existing) {
38667326 gop.key_ptr.* = {};
......@@ -3883,7 +7343,7 @@ fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty:
38837343 .inttoptr => &llvm.Value.constIntToPtr,
38847344 .bitcast => &llvm.Value.constBitCast,
38857345 else => unreachable,
3886 }(arg.toLlvm(self), ty.toLlvm(self)));
7346 }(val.toLlvm(self), ty.toLlvm(self)));
38877347 }
38887348 return @enumFromInt(gop.index);
38897349}
......@@ -3893,6 +7353,7 @@ fn gepConstAssumeCapacity(
38937353 comptime kind: Constant.GetElementPtr.Kind,
38947354 ty: Type,
38957355 base: Constant,
7356 inrange: ?u16,
38967357 indices: []const Constant,
38977358) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
38987359 const tag: Constant.Tag = switch (kind) {
......@@ -3929,13 +7390,19 @@ fn gepConstAssumeCapacity(
39297390 inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty),
39307391 };
39317392
3932 const Key = struct { type: Type, base: Constant, indices: []const Constant };
7393 const Key = struct {
7394 type: Type,
7395 base: Constant,
7396 inrange: Constant.GetElementPtr.InRangeIndex,
7397 indices: []const Constant,
7398 };
39337399 const Adapter = struct {
39347400 builder: *const Builder,
39357401 pub fn hash(_: @This(), key: Key) u32 {
39367402 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
39377403 hasher.update(std.mem.asBytes(&key.type));
39387404 hasher.update(std.mem.asBytes(&key.base));
7405 hasher.update(std.mem.asBytes(&key.inrange));
39397406 hasher.update(std.mem.sliceAsBytes(key.indices));
39407407 return @truncate(hasher.final());
39417408 }
......@@ -3944,12 +7411,18 @@ fn gepConstAssumeCapacity(
39447411 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
39457412 const rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data);
39467413 const rhs_indices: []const Constant = @ptrCast(ctx.builder.constant_extra
3947 .items[rhs_extra.end..][0..rhs_extra.data.indices_len]);
7414 .items[rhs_extra.end..][0..rhs_extra.data.info.indices_len]);
39487415 return lhs_key.type == rhs_extra.data.type and lhs_key.base == rhs_extra.data.base and
7416 lhs_key.inrange == rhs_extra.data.info.inrange and
39497417 std.mem.eql(Constant, lhs_key.indices, rhs_indices);
39507418 }
39517419 };
3952 const data = Key{ .type = ty, .base = base, .indices = indices };
7420 const data = Key{
7421 .type = ty,
7422 .base = base,
7423 .inrange = if (inrange) |index| @enumFromInt(index) else .none,
7424 .indices = indices,
7425 };
39537426 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
39547427 if (!gop.found_existing) {
39557428 gop.key_ptr.* = {};
......@@ -3959,7 +7432,7 @@ fn gepConstAssumeCapacity(
39597432 .data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{
39607433 .type = ty,
39617434 .base = base,
3962 .indices_len = @intCast(indices.len),
7435 .info = .{ .indices_len = @intCast(indices.len), .inrange = data.inrange },
39637436 }),
39647437 });
39657438 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices));
......@@ -3976,7 +7449,7 @@ fn gepConstAssumeCapacity(
39767449 self.llvm.constants.appendAssumeCapacity(switch (kind) {
39777450 .normal => &llvm.Type.constGEP,
39787451 .inbounds => &llvm.Type.constInBoundsGEP,
3979 }(ty.toLlvm(self), base.toLlvm(self), llvm_indices.ptr, @intCast(indices.len)));
7452 }(ty.toLlvm(self), base.toLlvm(self), llvm_indices.ptr, @intCast(llvm_indices.len)));
39807453 }
39817454 }
39827455 return @enumFromInt(gop.index);
......@@ -4058,7 +7531,7 @@ fn fcmpConstAssumeCapacity(
40587531
40597532fn extractElementConstAssumeCapacity(
40607533 self: *Builder,
4061 arg: Constant,
7534 val: Constant,
40627535 index: Constant,
40637536) Constant {
40647537 const Adapter = struct {
......@@ -4076,7 +7549,7 @@ fn extractElementConstAssumeCapacity(
40767549 return std.meta.eql(lhs_key, rhs_extra);
40777550 }
40787551 };
4079 const data = Constant.ExtractElement{ .arg = arg, .index = index };
7552 const data = Constant.ExtractElement{ .val = val, .index = index };
40807553 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
40817554 if (!gop.found_existing) {
40827555 gop.key_ptr.* = {};
......@@ -4086,7 +7559,7 @@ fn extractElementConstAssumeCapacity(
40867559 .data = self.addConstantExtraAssumeCapacity(data),
40877560 });
40887561 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
4089 arg.toLlvm(self).constExtractElement(index.toLlvm(self)),
7562 val.toLlvm(self).constExtractElement(index.toLlvm(self)),
40907563 );
40917564 }
40927565 return @enumFromInt(gop.index);
......@@ -4094,7 +7567,7 @@ fn extractElementConstAssumeCapacity(
40947567
40957568fn insertElementConstAssumeCapacity(
40967569 self: *Builder,
4097 arg: Constant,
7570 val: Constant,
40987571 elem: Constant,
40997572 index: Constant,
41007573) Constant {
......@@ -4113,7 +7586,7 @@ fn insertElementConstAssumeCapacity(
41137586 return std.meta.eql(lhs_key, rhs_extra);
41147587 }
41157588 };
4116 const data = Constant.InsertElement{ .arg = arg, .elem = elem, .index = index };
7589 const data = Constant.InsertElement{ .val = val, .elem = elem, .index = index };
41177590 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
41187591 if (!gop.found_existing) {
41197592 gop.key_ptr.* = {};
......@@ -4123,7 +7596,7 @@ fn insertElementConstAssumeCapacity(
41237596 .data = self.addConstantExtraAssumeCapacity(data),
41247597 });
41257598 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
4126 arg.toLlvm(self).constInsertElement(elem.toLlvm(self), index.toLlvm(self)),
7599 val.toLlvm(self).constInsertElement(elem.toLlvm(self), index.toLlvm(self)),
41277600 );
41287601 }
41297602 return @enumFromInt(gop.index);
......@@ -4135,6 +7608,10 @@ fn shuffleVectorConstAssumeCapacity(
41357608 rhs: Constant,
41367609 mask: Constant,
41377610) Constant {
7611 assert(lhs.typeOf(self).isVector(self.builder));
7612 assert(lhs.typeOf(self) == rhs.typeOf(self));
7613 assert(mask.typeOf(self).scalarType(self).isInteger(self));
7614 _ = lhs.typeOf(self).changeLengthAssumeCapacity(mask.typeOf(self).vectorLen(self), self);
41387615 const Adapter = struct {
41397616 builder: *const Builder,
41407617 pub fn hash(_: @This(), key: Constant.ShuffleVector) u32 {
......@@ -4235,15 +7712,15 @@ fn binConstAssumeCapacity(
42357712fn ensureUnusedConstantCapacity(
42367713 self: *Builder,
42377714 count: usize,
4238 comptime Extra: ?type,
7715 comptime Extra: type,
42397716 trail_len: usize,
42407717) Allocator.Error!void {
42417718 try self.constant_map.ensureUnusedCapacity(self.gpa, count);
42427719 try self.constant_items.ensureUnusedCapacity(self.gpa, count);
4243 if (Extra) |E| try self.constant_extra.ensureUnusedCapacity(
7720 try self.constant_extra.ensureUnusedCapacity(
42447721 self.gpa,
4245 count * (@typeInfo(E).Struct.fields.len + trail_len),
4246 ) else assert(trail_len == 0);
7722 count * (@typeInfo(Extra).Struct.fields.len + trail_len),
7723 );
42477724 if (self.useLibLlvm()) try self.llvm.constants.ensureUnusedCapacity(self.gpa, count);
42487725}
42497726
......@@ -4323,11 +7800,8 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.
43237800 const value = @field(extra, field.name);
43247801 self.constant_extra.appendAssumeCapacity(switch (field.type) {
43257802 u32 => value,
4326 Type,
4327 Constant,
4328 Function.Index,
4329 Function.Block.Index,
4330 => @intFromEnum(value),
7803 Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
7804 Constant.GetElementPtr.Info => @bitCast(value),
43317805 else => @compileError("bad field type: " ++ @typeName(field.type)),
43327806 });
43337807 }
......@@ -4341,14 +7815,11 @@ fn constantExtraDataTrail(
43417815) struct { data: T, end: Constant.Item.ExtraIndex } {
43427816 var result: T = undefined;
43437817 const fields = @typeInfo(T).Struct.fields;
4344 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, data|
7818 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|
43457819 @field(result, field.name) = switch (field.type) {
4346 u32 => data,
4347 Type,
4348 Constant,
4349 Function.Index,
4350 Function.Block.Index,
4351 => @enumFromInt(data),
7820 u32 => value,
7821 Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
7822 Constant.GetElementPtr.Info => @bitCast(value),
43527823 else => @compileError("bad field type: " ++ @typeName(field.type)),
43537824 };
43547825 return .{ .data = result, .end = index + @as(Constant.Item.ExtraIndex, @intCast(fields.len)) };
......@@ -4358,10 +7829,6 @@ fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Ite
43587829 return self.constantExtraDataTrail(T, index).data;
43597830}
43607831
4361pub inline fn useLibLlvm(self: *const Builder) bool {
4362 return build_options.have_llvm and self.use_lib_llvm;
4363}
4364
43657832const assert = std.debug.assert;
43667833const build_options = @import("build_options");
43677834const builtin = @import("builtin");
src/codegen/llvm/bindings.zig+20-73
......@@ -135,9 +135,6 @@ pub const Value = opaque {
135135 pub const getNextInstruction = LLVMGetNextInstruction;
136136 extern fn LLVMGetNextInstruction(Inst: *Value) ?*Value;
137137
138 pub const typeOf = LLVMTypeOf;
139 extern fn LLVMTypeOf(Val: *Value) *Type;
140
141138 pub const setGlobalConstant = LLVMSetGlobalConstant;
142139 extern fn LLVMSetGlobalConstant(GlobalVar: *Value, IsConstant: Bool) void;
143140
......@@ -291,6 +288,9 @@ pub const Value = opaque {
291288 MaskConstant: *Value,
292289 ) *Value;
293290
291 pub const isConstant = LLVMIsConstant;
292 extern fn LLVMIsConstant(Val: *Value) Bool;
293
294294 pub const blockAddress = LLVMBlockAddress;
295295 extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;
296296
......@@ -303,6 +303,9 @@ pub const Value = opaque {
303303 pub const setVolatile = LLVMSetVolatile;
304304 extern fn LLVMSetVolatile(MemoryAccessInst: *Value, IsVolatile: Bool) void;
305305
306 pub const setAtomicSingleThread = LLVMSetAtomicSingleThread;
307 extern fn LLVMSetAtomicSingleThread(AtomicInst: *Value, SingleThread: Bool) void;
308
306309 pub const setAlignment = LLVMSetAlignment;
307310 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;
308311
......@@ -348,17 +351,9 @@ pub const Value = opaque {
348351 pub const addCase = LLVMAddCase;
349352 extern fn LLVMAddCase(Switch: *Value, OnVal: *Value, Dest: *BasicBlock) void;
350353
351 pub inline fn isPoison(Val: *Value) bool {
352 return LLVMIsPoison(Val).toBool();
353 }
354 extern fn LLVMIsPoison(Val: *Value) Bool;
355
356354 pub const replaceAllUsesWith = LLVMReplaceAllUsesWith;
357355 extern fn LLVMReplaceAllUsesWith(OldVal: *Value, NewVal: *Value) void;
358356
359 pub const globalGetValueType = LLVMGlobalGetValueType;
360 extern fn LLVMGlobalGetValueType(Global: *Value) *Type;
361
362357 pub const getLinkage = LLVMGetLinkage;
363358 extern fn LLVMGetLinkage(Global: *Value) Linkage;
364359
......@@ -410,6 +405,9 @@ pub const Type = opaque {
410405 pub const getUndef = LLVMGetUndef;
411406 extern fn LLVMGetUndef(Ty: *Type) *Value;
412407
408 pub const getPoison = LLVMGetPoison;
409 extern fn LLVMGetPoison(Ty: *Type) *Value;
410
413411 pub const arrayType = LLVMArrayType;
414412 extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) *Type;
415413
......@@ -427,24 +425,6 @@ pub const Type = opaque {
427425 Packed: Bool,
428426 ) void;
429427
430 pub const structGetTypeAtIndex = LLVMStructGetTypeAtIndex;
431 extern fn LLVMStructGetTypeAtIndex(StructTy: *Type, i: c_uint) *Type;
432
433 pub const getTypeKind = LLVMGetTypeKind;
434 extern fn LLVMGetTypeKind(Ty: *Type) TypeKind;
435
436 pub const getElementType = LLVMGetElementType;
437 extern fn LLVMGetElementType(Ty: *Type) *Type;
438
439 pub const countStructElementTypes = LLVMCountStructElementTypes;
440 extern fn LLVMCountStructElementTypes(StructTy: *Type) c_uint;
441
442 pub const isOpaqueStruct = LLVMIsOpaqueStruct;
443 extern fn LLVMIsOpaqueStruct(StructTy: *Type) Bool;
444
445 pub const isSized = LLVMTypeIsSized;
446 extern fn LLVMTypeIsSized(Ty: *Type) Bool;
447
448428 pub const constGEP = LLVMConstGEP2;
449429 extern fn LLVMConstGEP2(
450430 Ty: *Type,
......@@ -815,6 +795,16 @@ pub const Builder = opaque {
815795 pub const buildBitCast = LLVMBuildBitCast;
816796 extern fn LLVMBuildBitCast(*Builder, Val: *Value, DestTy: *Type, Name: [*:0]const u8) *Value;
817797
798 pub const buildGEP = LLVMBuildGEP2;
799 extern fn LLVMBuildGEP2(
800 B: *Builder,
801 Ty: *Type,
802 Pointer: *Value,
803 Indices: [*]const *Value,
804 NumIndices: c_uint,
805 Name: [*:0]const u8,
806 ) *Value;
807
818808 pub const buildInBoundsGEP = LLVMBuildInBoundsGEP2;
819809 extern fn LLVMBuildInBoundsGEP2(
820810 B: *Builder,
......@@ -868,14 +858,6 @@ pub const Builder = opaque {
868858 Name: [*:0]const u8,
869859 ) *Value;
870860
871 pub const buildVectorSplat = LLVMBuildVectorSplat;
872 extern fn LLVMBuildVectorSplat(
873 *Builder,
874 ElementCount: c_uint,
875 EltVal: *Value,
876 Name: [*:0]const u8,
877 ) *Value;
878
879861 pub const buildPtrToInt = LLVMBuildPtrToInt;
880862 extern fn LLVMBuildPtrToInt(
881863 *Builder,
......@@ -892,15 +874,6 @@ pub const Builder = opaque {
892874 Name: [*:0]const u8,
893875 ) *Value;
894876
895 pub const buildStructGEP = LLVMBuildStructGEP2;
896 extern fn LLVMBuildStructGEP2(
897 B: *Builder,
898 Ty: *Type,
899 Pointer: *Value,
900 Idx: c_uint,
901 Name: [*:0]const u8,
902 ) *Value;
903
904877 pub const buildTrunc = LLVMBuildTrunc;
905878 extern fn LLVMBuildTrunc(
906879 *Builder,
......@@ -1156,9 +1129,6 @@ pub const RealPredicate = enum(c_uint) {
11561129pub const BasicBlock = opaque {
11571130 pub const deleteBasicBlock = LLVMDeleteBasicBlock;
11581131 extern fn LLVMDeleteBasicBlock(BB: *BasicBlock) void;
1159
1160 pub const getFirstInstruction = LLVMGetFirstInstruction;
1161 extern fn LLVMGetFirstInstruction(BB: *BasicBlock) ?*Value;
11621132};
11631133
11641134pub const TargetMachine = opaque {
......@@ -1580,29 +1550,6 @@ pub const AtomicRMWBinOp = enum(c_int) {
15801550 FMin,
15811551};
15821552
1583pub const TypeKind = enum(c_int) {
1584 Void,
1585 Half,
1586 Float,
1587 Double,
1588 X86_FP80,
1589 FP128,
1590 PPC_FP128,
1591 Label,
1592 Integer,
1593 Function,
1594 Struct,
1595 Array,
1596 Pointer,
1597 Vector,
1598 Metadata,
1599 X86_MMX,
1600 Token,
1601 ScalableVector,
1602 BFloat,
1603 X86_AMX,
1604};
1605
16061553pub const CallConv = enum(c_uint) {
16071554 C = 0,
16081555 Fast = 8,
......@@ -1729,7 +1676,7 @@ pub const address_space = struct {
17291676 pub const constant_buffer_15: c_uint = 23;
17301677 };
17311678
1732 // See llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
1679 // See llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypetilities.h
17331680 pub const wasm = struct {
17341681 pub const variable: c_uint = 1;
17351682 pub const externref: c_uint = 10;
src/zig_llvm.cpp-4
......@@ -560,10 +560,6 @@ LLVMValueRef ZigLLVMBuildUShlSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRe
560560 return wrap(call_inst);
561561}
562562
563LLVMValueRef LLVMBuildVectorSplat(LLVMBuilderRef B, unsigned elem_count, LLVMValueRef V, const char *Name) {
564 return wrap(unwrap(B)->CreateVectorSplat(elem_count, unwrap(V), Name));
565}
566
567563void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) {
568564 assert( isa<Function>(unwrap(fn)) );
569565 Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn));