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 {...@@ -549,7 +549,6 @@ pub const Object = struct {
549 /// - *Module.Decl (Non-Fn) => *DIGlobalVariable549 /// - *Module.Decl (Non-Fn) => *DIGlobalVariable
550 di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode),550 di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode),
551 di_compile_unit: ?*llvm.DICompileUnit,551 di_compile_unit: ?*llvm.DICompileUnit,
552 context: *llvm.Context,
553 target_machine: *llvm.TargetMachine,552 target_machine: *llvm.TargetMachine,
554 target_data: *llvm.TargetData,553 target_data: *llvm.TargetData,
555 target: std.Target,554 target: std.Target,
...@@ -727,7 +726,6 @@ pub const Object = struct {...@@ -727,7 +726,6 @@ pub const Object = struct {
727 .di_map = .{},726 .di_map = .{},
728 .di_builder = builder.llvm.di_builder,727 .di_builder = builder.llvm.di_builder,
729 .di_compile_unit = builder.llvm.di_compile_unit,728 .di_compile_unit = builder.llvm.di_compile_unit,
730 .context = builder.llvm.context,
731 .target_machine = target_machine,729 .target_machine = target_machine,
732 .target_data = target_data,730 .target_data = target_data,
733 .target = options.target,731 .target = options.target,
...@@ -803,13 +801,13 @@ pub const Object = struct {...@@ -803,13 +801,13 @@ pub const Object = struct {
803 .linkage = .private,801 .linkage = .private,
804 .unnamed_addr = .unnamed_addr,802 .unnamed_addr = .unnamed_addr,
805 .type = str_ty,803 .type = str_ty,
806 .alignment = comptime Builder.Alignment.fromByteUnits(1),
807 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },804 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
808 };805 };
809 var str_variable = Builder.Variable{806 var str_variable = Builder.Variable{
810 .global = @enumFromInt(o.builder.globals.count()),807 .global = @enumFromInt(o.builder.globals.count()),
811 .mutability = .constant,808 .mutability = .constant,
812 .init = str_init,809 .init = str_init,
810 .alignment = comptime Builder.Alignment.fromByteUnits(1),
813 };811 };
814 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);812 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);
815 const global_index = try o.builder.addGlobal(.empty, str_global);813 const global_index = try o.builder.addGlobal(.empty, str_global);
...@@ -833,13 +831,13 @@ pub const Object = struct {...@@ -833,13 +831,13 @@ pub const Object = struct {
833 .linkage = .private,831 .linkage = .private,
834 .unnamed_addr = .unnamed_addr,832 .unnamed_addr = .unnamed_addr,
835 .type = llvm_table_ty,833 .type = llvm_table_ty,
836 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
837 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },834 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
838 };835 };
839 var variable = Builder.Variable{836 var variable = Builder.Variable{
840 .global = @enumFromInt(o.builder.globals.count()),837 .global = @enumFromInt(o.builder.globals.count()),
841 .mutability = .constant,838 .mutability = .constant,
842 .init = error_name_table_init,839 .init = error_name_table_init,
840 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
843 };841 };
844 try o.builder.llvm.globals.append(o.gpa, error_name_table_global);842 try o.builder.llvm.globals.append(o.gpa, error_name_table_global);
845 _ = try o.builder.addGlobal(.empty, global);843 _ = try o.builder.addGlobal(.empty, global);
...@@ -857,25 +855,19 @@ pub const Object = struct {...@@ -857,25 +855,19 @@ pub const Object = struct {
857 const mod = o.module;855 const mod = o.module;
858 const errors_len = mod.global_error_set.count();856 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);
861 defer wip.deinit();859 defer wip.deinit();
862860 wip.cursor = .{ .block = try wip.block(0, "Entry") };
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();
868861
869 // Example source of the following LLVM IR:862 // Example source of the following LLVM IR:
870 // fn __zig_lt_errors_len(index: u16) bool {863 // fn __zig_lt_errors_len(index: u16) bool {
871 // return index < total_errors_len;864 // return index < total_errors_len;
872 // }865 // }
873866
874 const lhs = llvm_fn.toLlvm(&o.builder).getParam(0);867 const lhs = wip.arg(0);
875 const rhs = try o.builder.intConst(Builder.Type.err_int, errors_len);868 const rhs = try o.builder.intValue(Builder.Type.err_int, errors_len);
876 const is_lt = builder.buildICmp(.ULT, lhs, rhs.toLlvm(&o.builder), "");869 const is_lt = try wip.icmp(.ult, lhs, rhs, "");
877 _ = builder.buildRet(is_lt);870 _ = try wip.ret(is_lt);
878
879 try wip.finish();871 try wip.finish();
880 }872 }
881873
...@@ -1148,29 +1140,26 @@ pub const Object = struct {...@@ -1148,29 +1140,26 @@ pub const Object = struct {
1148 }1140 }
11491141
1150 if (ip.stringToSliceUnwrap(decl.@"linksection")) |section| {1142 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);
1152 llvm_func.setSection(section);1144 llvm_func.setSection(section);
1153 }1145 }
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
1161 var deinit_wip = true;1147 var deinit_wip = true;
1162 var wip = Builder.WipFunction.init(&o.builder, function);1148 var wip = try Builder.WipFunction.init(&o.builder, function);
1163 defer if (deinit_wip) wip.deinit();1149 defer if (deinit_wip) wip.deinit();
1150 wip.cursor = .{ .block = try wip.block(0, "Entry") };
11641151
1165 const builder = wip.llvm.builder;1152 const builder = wip.llvm.builder;
1166 const entry_block = try wip.block("Entry");1153 var llvm_arg_i: u32 = 0;
1167 wip.cursor = .{ .block = entry_block };
1168 builder.positionBuilderAtEnd(entry_block.toLlvm(&wip));
11691154
1170 // This gets the LLVM values from the function and stores them in `dg.args`.1155 // This gets the LLVM values from the function and stores them in `dg.args`.
1171 const fn_info = mod.typeToFunc(decl.ty).?;1156 const fn_info = mod.typeToFunc(decl.ty).?;
1172 const sret = firstParamSRet(fn_info, mod);1157 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;
1174 const gpa = o.gpa;1163 const gpa = o.gpa;
11751164
1176 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {1165 if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) {
...@@ -1181,205 +1170,183 @@ pub const Object = struct {...@@ -1181,205 +1170,183 @@ pub const Object = struct {
1181 const err_return_tracing = fn_info.return_type.toType().isError(mod) and1170 const err_return_tracing = fn_info.return_type.toType().isError(mod) and
1182 mod.comp.bin_file.options.error_return_tracing;1171 mod.comp.bin_file.options.error_return_tracing;
11831172
1184 const err_ret_trace = if (err_return_tracing)1173 const err_ret_trace: Builder.Value = if (err_return_tracing) param: {
1185 llvm_func.getParam(@intFromBool(ret_ptr != null))1174 const param = wip.arg(llvm_arg_i);
1186 else1175 llvm_arg_i += 1;
1187 null;1176 break :param param;
1177 } else .none;
11881178
1189 // This is the list of args we will use that correspond directly to the AIR arg1179 // This is the list of args we will use that correspond directly to the AIR arg
1190 // instructions. Depending on the calling convention, this list is not necessarily1180 // instructions. Depending on the calling convention, this list is not necessarily
1191 // a bijection with the actual LLVM parameters of the function.1181 // a bijection with the actual LLVM parameters of the function.
1192 var args = std.ArrayList(*llvm.Value).init(gpa);1182 var args: std.ArrayListUnmanaged(Builder.Value) = .{};
1193 defer args.deinit();1183 defer args.deinit(gpa);
11941184
1195 {1185 {
1196 var llvm_arg_i = @as(c_uint, @intFromBool(ret_ptr != null)) + @intFromBool(err_return_tracing);
1197 var it = iterateParamTypes(o, fn_info);1186 var it = iterateParamTypes(o, fn_info);
1198 while (try it.next()) |lowering| switch (lowering) {1187 while (try it.next()) |lowering| {
1199 .no_bits => continue,1188 try args.ensureUnusedCapacity(gpa, 1);
1200 .byval => {1189
1201 assert(!it.byval_attr);1190 switch (lowering) {
1202 const param_index = it.zig_index - 1;1191 .no_bits => continue,
1203 const param_ty = fn_info.param_types.get(ip)[param_index].toType();1192 .byval => {
1204 const param = llvm_func.getParam(llvm_arg_i);1193 assert(!it.byval_attr);
1205 try args.ensureUnusedCapacity(1);1194 const param_index = it.zig_index - 1;
12061195 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
1207 if (isByRef(param_ty, mod)) {1196 const param = wip.arg(llvm_arg_i);
1208 const alignment = param_ty.abiAlignment(mod);1197
1209 const param_llvm_ty = param.typeOf();1198 if (isByRef(param_ty, mod)) {
1210 const arg_ptr = try o.buildAllocaInner(&wip, builder, llvm_func, false, param_llvm_ty, alignment, target);1199 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1211 const store_inst = builder.buildStore(param, arg_ptr);1200 const param_llvm_ty = param.typeOfWip(&wip);
1212 store_inst.setAlignment(alignment);1201 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1213 args.appendAssumeCapacity(arg_ptr);1202 _ = try wip.store(.normal, param, arg_ptr, alignment);
1214 } else {1203 args.appendAssumeCapacity(arg_ptr);
1215 args.appendAssumeCapacity(param);1204 } else {
12161205 args.appendAssumeCapacity(param);
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);
12451206
1246 o.addArgAttr(llvm_func, llvm_arg_i, "noundef");1207 o.addByValParamAttrs(llvm_func, param_ty, param_index, fn_info, @intCast(llvm_arg_i));
1247 llvm_arg_i += 1;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)) {1220 if (isByRef(param_ty, mod)) {
1252 args.appendAssumeCapacity(param);1221 args.appendAssumeCapacity(param);
1253 } else {1222 } else {
1254 const load_inst = builder.buildLoad(param_llvm_ty, param, "");1223 args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
1255 load_inst.setAlignment(alignment);1224 }
1256 args.appendAssumeCapacity(load_inst);1225 },
1257 }1226 .byref_mut => {
1258 },1227 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1259 .abi_sized_int => {1228 const param_llvm_ty = try o.lowerType(param_ty);
1260 assert(!it.byval_attr);1229 const param = wip.arg(llvm_arg_i);
1261 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();1230 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1262 const param = llvm_func.getParam(llvm_arg_i);
1263 llvm_arg_i += 1;
12641231
1265 const param_llvm_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);1232 o.addArgAttr(llvm_func, @intCast(llvm_arg_i), "noundef");
1266 const int_llvm_ty = (try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8))).toLlvm(&o.builder);1233 llvm_arg_i += 1;
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);
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)) {1247 const param_llvm_ty = try o.lowerType(param_ty);
1278 args.appendAssumeCapacity(arg_ptr);1248 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
1279 } else {1249 const alignment = Builder.Alignment.fromByteUnits(@max(
1280 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");1250 param_ty.abiAlignment(mod),
1281 load_inst.setAlignment(alignment);1251 o.target_data.abiAlignmentOfType(int_llvm_ty.toLlvm(&o.builder)),
1282 args.appendAssumeCapacity(load_inst);1252 ));
1283 }1253 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1284 },1254 _ = try wip.store(.normal, param, arg_ptr, alignment);
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);
12891255
1290 if (math.cast(u5, it.zig_index - 1)) |i| {1256 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1291 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {1257 arg_ptr
1292 o.addArgAttr(llvm_func, llvm_arg_i, "noalias");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);
1293 }1304 }
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);1306 const is_by_ref = isByRef(param_ty, mod);
1331 const loaded = if (is_by_ref) arg_ptr else l: {1307 args.appendAssumeCapacity(if (is_by_ref)
1332 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");1308 arg_ptr
1333 load_inst.setAlignment(param_alignment);1309 else
1334 break :l load_inst;1310 try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment, ""));
1335 };1311 },
1336 try args.append(loaded);1312 .as_u16 => {
1337 },1313 assert(!it.byval_attr);
1338 .as_u16 => {1314 const param = wip.arg(llvm_arg_i);
1339 assert(!it.byval_attr);1315 llvm_arg_i += 1;
1340 const param = llvm_func.getParam(llvm_arg_i);1316 args.appendAssumeCapacity(try wip.cast(.bitcast, param, .half, ""));
1341 llvm_arg_i += 1;1317 },
1342 const casted = builder.buildBitCast(param, Builder.Type.half.toLlvm(&o.builder), "");1318 .float_array => {
1343 try args.ensureUnusedCapacity(1);1319 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1344 args.appendAssumeCapacity(casted);1320 const param_llvm_ty = try o.lowerType(param_ty);
1345 },1321 const param = wip.arg(llvm_arg_i);
1346 .float_array => {1322 llvm_arg_i += 1;
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;
13511323
1352 const alignment = param_ty.abiAlignment(mod);1324 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1353 const arg_ptr = try o.buildAllocaInner(&wip, builder, llvm_func, false, param_llvm_ty, alignment, target);1325 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1354 _ = builder.buildStore(param, arg_ptr);1326 _ = try wip.store(.normal, param, arg_ptr, alignment);
13551327
1356 if (isByRef(param_ty, mod)) {1328 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1357 try args.append(arg_ptr);1329 arg_ptr
1358 } else {1330 else
1359 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");1331 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1360 load_inst.setAlignment(alignment);1332 },
1361 try args.append(load_inst);1333 .i32_array, .i64_array => {
1362 }1334 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1363 },1335 const param_llvm_ty = try o.lowerType(param_ty);
1364 .i32_array, .i64_array => {1336 const param = wip.arg(llvm_arg_i);
1365 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();1337 llvm_arg_i += 1;
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;
13691338
1370 const alignment = param_ty.abiAlignment(mod);1339 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1371 const arg_ptr = try o.buildAllocaInner(&wip, builder, llvm_func, false, param_llvm_ty, alignment, target);1340 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1372 _ = builder.buildStore(param, arg_ptr);1341 _ = try wip.store(.normal, param, arg_ptr, alignment);
13731342
1374 if (isByRef(param_ty, mod)) {1343 args.appendAssumeCapacity(if (isByRef(param_ty, mod))
1375 try args.append(arg_ptr);1344 arg_ptr
1376 } else {1345 else
1377 const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");1346 try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
1378 load_inst.setAlignment(alignment);1347 },
1379 try args.append(load_inst);1348 }
1380 }1349 }
1381 },
1382 };
1383 }1350 }
13841351
1385 var di_file: ?*llvm.DIFile = null;1352 var di_file: ?*llvm.DIFile = null;
...@@ -1421,7 +1388,6 @@ pub const Object = struct {...@@ -1421,7 +1388,6 @@ pub const Object = struct {
1421 .gpa = gpa,1388 .gpa = gpa,
1422 .air = air,1389 .air = air,
1423 .liveness = liveness,1390 .liveness = liveness,
1424 .context = o.context,
1425 .dg = &dg,1391 .dg = &dg,
1426 .wip = wip,1392 .wip = wip,
1427 .builder = builder,1393 .builder = builder,
...@@ -1429,9 +1395,8 @@ pub const Object = struct {...@@ -1429,9 +1395,8 @@ pub const Object = struct {
1429 .args = args.items,1395 .args = args.items,
1430 .arg_index = 0,1396 .arg_index = 0,
1431 .func_inst_table = .{},1397 .func_inst_table = .{},
1432 .llvm_func = llvm_func,
1433 .blocks = .{},1398 .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,
1435 .di_scope = di_scope,1400 .di_scope = di_scope,
1436 .di_file = di_file,1401 .di_file = di_file,
1437 .base_line = dg.decl.src_line,1402 .base_line = dg.decl.src_line,
...@@ -1523,11 +1488,11 @@ pub const Object = struct {...@@ -1523,11 +1488,11 @@ pub const Object = struct {
1523 const decl_name_slice = decl_name.toSlice(&self.builder).?;1488 const decl_name_slice = decl_name.toSlice(&self.builder).?;
1524 if (try decl.isFunction(mod)) {1489 if (try decl.isFunction(mod)) {
1525 const di_func: *llvm.DISubprogram = @ptrCast(di_node);1490 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);
1527 di_func.replaceLinkageName(linkage_name);1492 di_func.replaceLinkageName(linkage_name);
1528 } else {1493 } else {
1529 const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);1494 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);
1531 di_global.replaceLinkageName(linkage_name);1496 di_global.replaceLinkageName(linkage_name);
1532 }1497 }
1533 }1498 }
...@@ -1560,11 +1525,11 @@ pub const Object = struct {...@@ -1560,11 +1525,11 @@ pub const Object = struct {
1560 const exp_name_slice = exp_name.toSlice(&self.builder).?;1525 const exp_name_slice = exp_name.toSlice(&self.builder).?;
1561 if (try decl.isFunction(mod)) {1526 if (try decl.isFunction(mod)) {
1562 const di_func: *llvm.DISubprogram = @ptrCast(di_node);1527 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);
1564 di_func.replaceLinkageName(linkage_name);1529 di_func.replaceLinkageName(linkage_name);
1565 } else {1530 } else {
1566 const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);1531 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);
1568 di_global.replaceLinkageName(linkage_name);1533 di_global.replaceLinkageName(linkage_name);
1569 }1534 }
1570 }1535 }
...@@ -1598,7 +1563,11 @@ pub const Object = struct {...@@ -1598,7 +1563,11 @@ pub const Object = struct {
1598 },1563 },
1599 }1564 }
1600 if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| {1565 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 }
1602 llvm_global.setSection(section);1571 llvm_global.setSection(section);
1603 }1572 }
1604 if (decl.val.getVariable(mod)) |decl_var| {1573 if (decl.val.getVariable(mod)) |decl_var| {
...@@ -1623,7 +1592,7 @@ pub const Object = struct {...@@ -1623,7 +1592,7 @@ pub const Object = struct {
1623 alias.setAliasee(llvm_global);1592 alias.setAliasee(llvm_global);
1624 } else {1593 } else {
1625 _ = self.llvm_module.addAlias(1594 _ = self.llvm_module.addAlias(
1626 llvm_global.globalGetValueType(),1595 global.ptrConst(&self.builder).type.toLlvm(&self.builder),
1627 0,1596 0,
1628 llvm_global,1597 llvm_global,
1629 exp_name_z,1598 exp_name_z,
...@@ -2773,7 +2742,7 @@ pub const Object = struct {...@@ -2773,7 +2742,7 @@ pub const Object = struct {
2773 }2742 }
27742743
2775 if (fn_info.alignment.toByteUnitsOptional()) |a| {2744 if (fn_info.alignment.toByteUnitsOptional()) |a| {
2776 global.alignment = Builder.Alignment.fromByteUnits(a);2745 function.alignment = Builder.Alignment.fromByteUnits(a);
2777 llvm_fn.setAlignment(@intCast(a));2746 llvm_fn.setAlignment(@intCast(a));
2778 }2747 }
27792748
...@@ -2944,7 +2913,7 @@ pub const Object = struct {...@@ -2944,7 +2913,7 @@ pub const Object = struct {
2944 const llvm_ty = ty.toLlvm(&o.builder);2913 const llvm_ty = ty.toLlvm(&o.builder);
2945 if (t.zigTypeTag(mod) == .Opaque) break :check;2914 if (t.zigTypeTag(mod) == .Opaque) break :check;
2946 if (!t.hasRuntimeBits(mod)) break :check;2915 if (!t.hasRuntimeBits(mod)) break :check;
2947 if (!llvm_ty.isSized().toBool()) break :check;2916 if (!try ty.isSized(&o.builder)) break :check;
29482917
2949 const zig_size = t.abiSize(mod);2918 const zig_size = t.abiSize(mod);
2950 const llvm_size = o.target_data.abiSizeOfType(llvm_ty);2919 const llvm_size = o.target_data.abiSizeOfType(llvm_ty);
...@@ -3807,7 +3776,7 @@ pub const Object = struct {...@@ -3807,7 +3776,7 @@ pub const Object = struct {
3807 }3776 }
3808 assert(llvm_index == llvm_len);3777 assert(llvm_index == llvm_len);
38093778
3810 return try o.builder.structConst(if (need_unnamed)3779 return o.builder.structConst(if (need_unnamed)
3811 try o.builder.structType(struct_ty.structKind(&o.builder), fields)3780 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
3812 else3781 else
3813 struct_ty, vals);3782 struct_ty, vals);
...@@ -3904,7 +3873,7 @@ pub const Object = struct {...@@ -3904,7 +3873,7 @@ pub const Object = struct {
3904 }3873 }
3905 assert(llvm_index == llvm_len);3874 assert(llvm_index == llvm_len);
39063875
3907 return try o.builder.structConst(if (need_unnamed)3876 return o.builder.structConst(if (need_unnamed)
3908 try o.builder.structType(struct_ty.structKind(&o.builder), fields)3877 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
3909 else3878 else
3910 struct_ty, vals);3879 struct_ty, vals);
...@@ -3978,7 +3947,7 @@ pub const Object = struct {...@@ -3978,7 +3947,7 @@ pub const Object = struct {
3978 vals[2] = try o.builder.undefConst(fields[2]);3947 vals[2] = try o.builder.undefConst(fields[2]);
3979 len = 3;3948 len = 3;
3980 }3949 }
3981 return try o.builder.structConst(if (need_unnamed)3950 return o.builder.structConst(if (need_unnamed)
3982 try o.builder.structType(union_ty.structKind(&o.builder), fields[0..len])3951 try o.builder.structType(union_ty.structKind(&o.builder), fields[0..len])
3983 else3952 else
3984 union_ty, vals[0..len]);3953 union_ty, vals[0..len]);
...@@ -4012,7 +3981,7 @@ pub const Object = struct {...@@ -4012,7 +3981,7 @@ pub const Object = struct {
40123981
4013 const ParentPtr = struct {3982 const ParentPtr = struct {
4014 ty: Type,3983 ty: Type,
4015 llvm_ptr: *llvm.Value,3984 llvm_ptr: Builder.Value,
4016 };3985 };
40173986
4018 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {3987 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
...@@ -4040,12 +4009,10 @@ pub const Object = struct {...@@ -4040,12 +4009,10 @@ pub const Object = struct {
4040 return parent_ptr;4009 return parent_ptr;
4041 }4010 }
40424011
4043 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, &.{4012 const index: u32 =
4044 try o.builder.intConst(.i32, 0),4013 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1;
4045 try o.builder.intConst(.i32, @as(4014 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{
4046 i32,4015 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index),
4047 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1,
4048 )),
4049 });4016 });
4050 },4017 },
4051 .opt_payload => |opt_ptr| {4018 .opt_payload => |opt_ptr| {
...@@ -4061,16 +4028,16 @@ pub const Object = struct {...@@ -4061,16 +4028,16 @@ pub const Object = struct {
4061 return parent_ptr;4028 return parent_ptr;
4062 }4029 }
40634030
4064 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, &(.{4031 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, null, &.{
4065 try o.builder.intConst(.i32, 0),4032 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, 0),
4066 } ** 2));4033 });
4067 },4034 },
4068 .comptime_field => unreachable,4035 .comptime_field => unreachable,
4069 .elem => |elem_ptr| {4036 .elem => |elem_ptr| {
4070 const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true);4037 const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true);
4071 const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);4038 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, &.{
4074 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),4041 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),
4075 });4042 });
4076 },4043 },
...@@ -4092,9 +4059,9 @@ pub const Object = struct {...@@ -4092,9 +4059,9 @@ pub const Object = struct {
4092 return parent_ptr;4059 return parent_ptr;
4093 }4060 }
40944061
4095 return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{4062 const parent_llvm_ty = try o.lowerType(parent_ty);
4096 try o.builder.intConst(.i32, 0),4063 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4097 try o.builder.intConst(.i32, @intFromBool(4064 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, @intFromBool(
4098 layout.tag_size > 0 and layout.tag_align >= layout.payload_align,4065 layout.tag_size > 0 and layout.tag_align >= layout.payload_align,
4099 )),4066 )),
4100 });4067 });
...@@ -4109,7 +4076,8 @@ pub const Object = struct {...@@ -4109,7 +4076,8 @@ pub const Object = struct {
4109 const prev_bits = b: {4076 const prev_bits = b: {
4110 var b: usize = 0;4077 var b: usize = 0;
4111 for (parent_ty.structFields(mod).values()[0..field_index]) |field| {4078 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;
4113 b += @intCast(field.ty.bitSize(mod));4081 b += @intCast(field.ty.bitSize(mod));
4114 }4082 }
4115 break :b b;4083 break :b b;
...@@ -4123,6 +4091,7 @@ pub const Object = struct {...@@ -4123,6 +4091,7 @@ pub const Object = struct {
4123 .inbounds,4091 .inbounds,
4124 try o.lowerType(parent_ty),4092 try o.lowerType(parent_ty),
4125 parent_ptr,4093 parent_ptr,
4094 null,
4126 if (llvmField(parent_ty, field_index, mod)) |llvm_field| &.{4095 if (llvmField(parent_ty, field_index, mod)) |llvm_field| &.{
4127 try o.builder.intConst(.i32, 0),4096 try o.builder.intConst(.i32, 0),
4128 try o.builder.intConst(.i32, llvm_field.index),4097 try o.builder.intConst(.i32, llvm_field.index),
...@@ -4135,9 +4104,9 @@ pub const Object = struct {...@@ -4135,9 +4104,9 @@ pub const Object = struct {
4135 },4104 },
4136 .Pointer => {4105 .Pointer => {
4137 assert(parent_ty.isSlice(mod));4106 assert(parent_ty.isSlice(mod));
4138 return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{4107 const parent_llvm_ty = try o.lowerType(parent_ty);
4139 try o.builder.intConst(.i32, 0),4108 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4140 try o.builder.intConst(.i32, field_index),4109 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, field_index),
4141 });4110 });
4142 },4111 },
4143 else => unreachable,4112 else => unreachable,
...@@ -4167,8 +4136,7 @@ pub const Object = struct {...@@ -4167,8 +4136,7 @@ pub const Object = struct {
41674136
4168 const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn;4137 const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn;
4169 if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or4138 if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or
4170 (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic))4139 (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) return o.lowerPtrToVoid(ty);
4171 return o.lowerPtrToVoid(ty);
41724140
4173 try mod.markDeclAlive(decl);4141 try mod.markDeclAlive(decl);
41744142
...@@ -4240,7 +4208,7 @@ pub const Object = struct {...@@ -4240,7 +4208,7 @@ pub const Object = struct {
4240 ) void {4208 ) void {
4241 const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);4209 const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
4242 assert(kind_id != 0);4210 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);
4244 val.addAttributeAtIndex(index, llvm_attr);4212 val.addAttributeAtIndex(index, llvm_attr);
4245 }4213 }
42464214
...@@ -4251,7 +4219,7 @@ pub const Object = struct {...@@ -4251,7 +4219,7 @@ pub const Object = struct {
4251 name: []const u8,4219 name: []const u8,
4252 value: []const u8,4220 value: []const u8,
4253 ) void {4221 ) void {
4254 const llvm_attr = o.context.createStringAttribute(4222 const llvm_attr = o.builder.llvm.context.createStringAttribute(
4255 name.ptr,4223 name.ptr,
4256 @intCast(name.len),4224 @intCast(name.len),
4257 value.ptr,4225 value.ptr,
...@@ -4346,51 +4314,6 @@ pub const Object = struct {...@@ -4346,51 +4314,6 @@ pub const Object = struct {
4346 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));4314 llvm_fn.addByValAttr(llvm_arg_i, param_llvm_ty.toLlvm(&o.builder));
4347 }4315 }
4348 }4316 }
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 }
4394};4317};
43954318
4396pub const DeclGen = struct {4319pub const DeclGen = struct {
...@@ -4424,10 +4347,10 @@ pub const DeclGen = struct {...@@ -4424,10 +4347,10 @@ pub const DeclGen = struct {
4424 const variable = try o.resolveGlobalDecl(decl_index);4347 const variable = try o.resolveGlobalDecl(decl_index);
4425 const global = variable.ptrConst(&o.builder).global;4348 const global = variable.ptrConst(&o.builder).global;
4426 var llvm_global = global.toLlvm(&o.builder);4349 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));
4428 llvm_global.setAlignment(decl.getAlignment(mod));4351 llvm_global.setAlignment(decl.getAlignment(mod));
4429 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| {4352 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);
4431 llvm_global.setSection(section);4354 llvm_global.setSection(section);
4432 }4355 }
4433 assert(decl.has_tv);4356 assert(decl.has_tv);
...@@ -4439,10 +4362,7 @@ pub const DeclGen = struct {...@@ -4439,10 +4362,7 @@ pub const DeclGen = struct {
4439 if (init_val != .none) {4362 if (init_val != .none) {
4440 const llvm_init = try o.lowerValue(init_val);4363 const llvm_init = try o.lowerValue(init_val);
4441 const llvm_init_ty = llvm_init.typeOf(&o.builder);4364 const llvm_init_ty = llvm_init.typeOf(&o.builder);
4442 global.ptr(&o.builder).type = llvm_init_ty;4365 if (global.ptrConst(&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)) {
4446 llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));4366 llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));
4447 } else {4367 } else {
4448 // LLVM does not allow us to change the type of globals. So we must4368 // LLVM does not allow us to change the type of globals. So we must
...@@ -4477,7 +4397,10 @@ pub const DeclGen = struct {...@@ -4477,7 +4397,10 @@ pub const DeclGen = struct {
4477 new_global;4397 new_global;
4478 llvm_global.deleteGlobal();4398 llvm_global.deleteGlobal();
4479 llvm_global = new_global;4399 llvm_global = new_global;
4400 variable.ptr(&o.builder).mutability = .global;
4401 global.ptr(&o.builder).type = llvm_init_ty;
4480 }4402 }
4403 variable.ptr(&o.builder).init = llvm_init;
4481 }4404 }
44824405
4483 if (o.di_builder) |dib| {4406 if (o.di_builder) |dib| {
...@@ -4508,7 +4431,6 @@ pub const FuncGen = struct {...@@ -4508,7 +4431,6 @@ pub const FuncGen = struct {
4508 air: Air,4431 air: Air,
4509 liveness: Liveness,4432 liveness: Liveness,
4510 wip: Builder.WipFunction,4433 wip: Builder.WipFunction,
4511 context: *llvm.Context,
4512 builder: *llvm.Builder,4434 builder: *llvm.Builder,
4513 di_scope: ?*llvm.DIScope,4435 di_scope: ?*llvm.DIScope,
4514 di_file: ?*llvm.DIFile,4436 di_file: ?*llvm.DIFile,
...@@ -4525,26 +4447,24 @@ pub const FuncGen = struct {...@@ -4525,26 +4447,24 @@ pub const FuncGen = struct {
45254447
4526 /// This stores the LLVM values used in a function, such that they can be referred to4448 /// This stores the LLVM values used in a function, such that they can be referred to
4527 /// in other instructions. This table is cleared before every function is generated.4449 /// 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
4530 /// If the return type is sret, this is the result pointer. Otherwise null.4452 /// If the return type is sret, this is the result pointer. Otherwise null.
4531 /// Note that this can disagree with isByRef for the return type in the case4453 /// Note that this can disagree with isByRef for the return type in the case
4532 /// of C ABI functions.4454 /// of C ABI functions.
4533 ret_ptr: ?*llvm.Value,4455 ret_ptr: Builder.Value,
4534 /// Any function that needs to perform Valgrind client requests needs an array alloca4456 /// Any function that needs to perform Valgrind client requests needs an array alloca
4535 /// instruction, however a maximum of one per function is needed.4457 /// 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,
4537 /// These fields are used to refer to the LLVM value of the function parameters4459 /// These fields are used to refer to the LLVM value of the function parameters
4538 /// in an Arg instruction.4460 /// in an Arg instruction.
4539 /// This list may be shorter than the list according to the zig type system;4461 /// This list may be shorter than the list according to the zig type system;
4540 /// it omits 0-bit types. If the function uses sret as the first parameter,4462 /// it omits 0-bit types. If the function uses sret as the first parameter,
4541 /// this slice does not include it.4463 /// this slice does not include it.
4542 args: []const *llvm.Value,4464 args: []const Builder.Value,
4543 arg_index: c_uint,4465 arg_index: usize,
45444466
4545 llvm_func: *llvm.Value,4467 err_ret_trace: Builder.Value = .none,
4546
4547 err_ret_trace: ?*llvm.Value = null,
45484468
4549 /// This data structure is used to implement breaking to blocks.4469 /// This data structure is used to implement breaking to blocks.
4550 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {4470 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
...@@ -4552,13 +4472,16 @@ pub const FuncGen = struct {...@@ -4552,13 +4472,16 @@ pub const FuncGen = struct {
4552 breaks: *BreakList,4472 breaks: *BreakList,
4553 }),4473 }),
45544474
4555 single_threaded: bool,4475 sync_scope: Builder.SyncScope,
45564476
4557 const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };4477 const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };
4558 const BreakList = std.MultiArrayList(struct {4478 const BreakList = union {
4559 bb: *llvm.BasicBlock,4479 list: std.MultiArrayList(struct {
4560 val: *llvm.Value,4480 bb: Builder.Function.Block.Index,
4561 });4481 val: Builder.Value,
4482 }),
4483 len: usize,
4484 };
45624485
4563 fn deinit(self: *FuncGen) void {4486 fn deinit(self: *FuncGen) void {
4564 self.wip.deinit();4487 self.wip.deinit();
...@@ -4573,7 +4496,7 @@ pub const FuncGen = struct {...@@ -4573,7 +4496,7 @@ pub const FuncGen = struct {
4573 return self.dg.todo(format, args);4496 return self.dg.todo(format, args);
4574 }4497 }
45754498
4576 fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !*llvm.Value {4499 fn resolveInst(self: *FuncGen, inst: Air.Inst.Ref) !Builder.Value {
4577 const gpa = self.gpa;4500 const gpa = self.gpa;
4578 const gop = try self.func_inst_table.getOrPut(gpa, inst);4501 const gop = try self.func_inst_table.getOrPut(gpa, inst);
4579 if (gop.found_existing) return gop.value_ptr.*;4502 if (gop.found_existing) return gop.value_ptr.*;
...@@ -4584,8 +4507,8 @@ pub const FuncGen = struct {...@@ -4584,8 +4507,8 @@ pub const FuncGen = struct {
4584 .ty = self.typeOf(inst),4507 .ty = self.typeOf(inst),
4585 .val = (try self.air.value(inst, mod)).?,4508 .val = (try self.air.value(inst, mod)).?,
4586 });4509 });
4587 gop.value_ptr.* = llvm_val.toLlvm(&o.builder);4510 gop.value_ptr.* = llvm_val.toValue();
4588 return gop.value_ptr.*;4511 return llvm_val.toValue();
4589 }4512 }
45904513
4591 fn resolveValue(self: *FuncGen, tv: TypedValue) Error!Builder.Constant {4514 fn resolveValue(self: *FuncGen, tv: TypedValue) Error!Builder.Constant {
...@@ -4613,19 +4536,19 @@ pub const FuncGen = struct {...@@ -4613,19 +4536,19 @@ pub const FuncGen = struct {
4613 .unnamed_addr = .unnamed_addr,4536 .unnamed_addr = .unnamed_addr,
4614 .addr_space = llvm_actual_addrspace,4537 .addr_space = llvm_actual_addrspace,
4615 .type = llvm_ty,4538 .type = llvm_ty,
4616 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),
4617 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },4539 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
4618 };4540 };
4619 var variable = Builder.Variable{4541 var variable = Builder.Variable{
4620 .global = @enumFromInt(o.builder.globals.count()),4542 .global = @enumFromInt(o.builder.globals.count()),
4621 .mutability = .constant,4543 .mutability = .constant,
4622 .init = llvm_val,4544 .init = llvm_val,
4545 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),
4623 };4546 };
4624 try o.builder.llvm.globals.append(o.gpa, llvm_global);4547 try o.builder.llvm.globals.append(o.gpa, llvm_global);
4625 const global_index = try o.builder.addGlobal(.empty, global);4548 const global_index = try o.builder.addGlobal(.empty, global);
4626 try o.builder.variables.append(o.gpa, variable);4549 try o.builder.variables.append(o.gpa, variable);
46274550
4628 return try o.builder.convConst(4551 return o.builder.convConst(
4629 .unneeded,4552 .unneeded,
4630 global_index.toConst(),4553 global_index.toConst(),
4631 try o.builder.ptrType(llvm_wanted_addrspace),4554 try o.builder.ptrType(llvm_wanted_addrspace),
...@@ -4651,10 +4574,9 @@ pub const FuncGen = struct {...@@ -4651,10 +4574,9 @@ pub const FuncGen = struct {
4651 const ip = &mod.intern_pool;4574 const ip = &mod.intern_pool;
4652 const air_tags = self.air.instructions.items(.tag);4575 const air_tags = self.air.instructions.items(.tag);
4653 for (body, 0..) |inst, i| {4576 for (body, 0..) |inst, i| {
4654 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip))4577 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;
4655 continue;
46564578
4657 const opt_value: ?*llvm.Value = switch (air_tags[inst]) {4579 const val: Builder.Value = switch (air_tags[inst]) {
4658 // zig fmt: off4580 // zig fmt: off
4659 .add => try self.airAdd(inst, false),4581 .add => try self.airAdd(inst, false),
4660 .add_optimized => try self.airAdd(inst, true),4582 .add_optimized => try self.airAdd(inst, true),
...@@ -4745,15 +4667,15 @@ pub const FuncGen = struct {...@@ -4745,15 +4667,15 @@ pub const FuncGen = struct {
4745 .cmp_vector_optimized => try self.airCmpVector(inst, true),4667 .cmp_vector_optimized => try self.airCmpVector(inst, true),
4746 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),4668 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
47474669
4748 .is_non_null => try self.airIsNonNull(inst, false, .NE),4670 .is_non_null => try self.airIsNonNull(inst, false, .ne),
4749 .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE),4671 .is_non_null_ptr => try self.airIsNonNull(inst, true , .ne),
4750 .is_null => try self.airIsNonNull(inst, false, .EQ),4672 .is_null => try self.airIsNonNull(inst, false, .eq),
4751 .is_null_ptr => try self.airIsNonNull(inst, true , .EQ),4673 .is_null_ptr => try self.airIsNonNull(inst, true , .eq),
47524674
4753 .is_non_err => try self.airIsErr(inst, .EQ, false),4675 .is_non_err => try self.airIsErr(inst, .eq, false),
4754 .is_non_err_ptr => try self.airIsErr(inst, .EQ, true),4676 .is_non_err_ptr => try self.airIsErr(inst, .eq, true),
4755 .is_err => try self.airIsErr(inst, .NE, false),4677 .is_err => try self.airIsErr(inst, .ne, false),
4756 .is_err_ptr => try self.airIsErr(inst, .NE, true),4678 .is_err_ptr => try self.airIsErr(inst, .ne, true),
47574679
4758 .alloc => try self.airAlloc(inst),4680 .alloc => try self.airAlloc(inst),
4759 .ret_ptr => try self.airRetPtr(inst),4681 .ret_ptr => try self.airRetPtr(inst),
...@@ -4830,10 +4752,10 @@ pub const FuncGen = struct {...@@ -4830,10 +4752,10 @@ pub const FuncGen = struct {
4830 .reduce => try self.airReduce(inst, false),4752 .reduce => try self.airReduce(inst, false),
4831 .reduce_optimized => try self.airReduce(inst, true),4753 .reduce_optimized => try self.airReduce(inst, true),
48324754
4833 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),4755 .atomic_store_unordered => try self.airAtomicStore(inst, .unordered),
4834 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),4756 .atomic_store_monotonic => try self.airAtomicStore(inst, .monotonic),
4835 .atomic_store_release => try self.airAtomicStore(inst, .Release),4757 .atomic_store_release => try self.airAtomicStore(inst, .release),
4836 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SequentiallyConsistent),4758 .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst),
48374759
4838 .struct_field_ptr => try self.airStructFieldPtr(inst),4760 .struct_field_ptr => try self.airStructFieldPtr(inst),
4839 .struct_field_val => try self.airStructFieldVal(body[i..]),4761 .struct_field_val => try self.airStructFieldVal(body[i..]),
...@@ -4875,8 +4797,8 @@ pub const FuncGen = struct {...@@ -4875,8 +4797,8 @@ pub const FuncGen = struct {
48754797
4876 .inferred_alloc, .inferred_alloc_comptime => unreachable,4798 .inferred_alloc, .inferred_alloc_comptime => unreachable,
48774799
4878 .unreach => self.airUnreach(inst),4800 .unreach => try self.airUnreach(inst),
4879 .dbg_stmt => self.airDbgStmt(inst),4801 .dbg_stmt => try self.airDbgStmt(inst),
4880 .dbg_inline_begin => try self.airDbgInlineBegin(inst),4802 .dbg_inline_begin => try self.airDbgInlineBegin(inst),
4881 .dbg_inline_end => try self.airDbgInlineEnd(inst),4803 .dbg_inline_end => try self.airDbgInlineEnd(inst),
4882 .dbg_block_begin => try self.airDbgBlockBegin(),4804 .dbg_block_begin => try self.airDbgBlockBegin(),
...@@ -4894,14 +4816,11 @@ pub const FuncGen = struct {...@@ -4894,14 +4816,11 @@ pub const FuncGen = struct {
4894 .work_group_id => try self.airWorkGroupId(inst),4816 .work_group_id => try self.airWorkGroupId(inst),
4895 // zig fmt: on4817 // zig fmt: on
4896 };4818 };
4897 if (opt_value) |val| {4819 if (val != .none) try self.func_inst_table.putNoClobber(self.gpa, Air.indexToRef(inst), val);
4898 const ref = Air.indexToRef(inst);
4899 try self.func_inst_table.putNoClobber(self.gpa, ref, val);
4900 }
4901 }4820 }
4902 }4821 }
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 {
4905 const pl_op = self.air.instructions.items(.data)[inst].pl_op;4824 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4906 const extra = self.air.extraData(Air.Call, pl_op.payload);4825 const extra = self.air.extraData(Air.Call, pl_op.payload);
4907 const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);4826 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 {...@@ -4924,16 +4843,18 @@ pub const FuncGen = struct {
4924 defer llvm_args.deinit();4843 defer llvm_args.deinit();
49254844
4926 const ret_ptr = if (!sret) null else blk: {4845 const ret_ptr = if (!sret) null else blk: {
4927 const llvm_ret_ty = (try o.lowerType(return_type)).toLlvm(&o.builder);4846 const llvm_ret_ty = try o.lowerType(return_type);
4928 const ret_ptr = try self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(mod));4847 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
4929 try llvm_args.append(ret_ptr);4848 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
4849 try llvm_args.append(ret_ptr.toLlvm(&self.wip));
4930 break :blk ret_ptr;4850 break :blk ret_ptr;
4931 };4851 };
49324852
4933 const err_return_tracing = return_type.isError(mod) and4853 const err_return_tracing = return_type.isError(mod) and
4934 o.module.comp.bin_file.options.error_return_tracing;4854 o.module.comp.bin_file.options.error_return_tracing;
4935 if (err_return_tracing) {4855 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));
4937 }4858 }
49384859
4939 var it = iterateParamTypes(o, fn_info);4860 var it = iterateParamTypes(o, fn_info);
...@@ -4943,14 +4864,13 @@ pub const FuncGen = struct {...@@ -4943,14 +4864,13 @@ pub const FuncGen = struct {
4943 const arg = args[it.zig_index - 1];4864 const arg = args[it.zig_index - 1];
4944 const param_ty = self.typeOf(arg);4865 const param_ty = self.typeOf(arg);
4945 const llvm_arg = try self.resolveInst(arg);4866 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);
4947 if (isByRef(param_ty, mod)) {4868 if (isByRef(param_ty, mod)) {
4948 const alignment = param_ty.abiAlignment(mod);4869 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4949 const load_inst = self.builder.buildLoad(llvm_param_ty, llvm_arg, "");4870 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
4950 load_inst.setAlignment(alignment);4871 try llvm_args.append(loaded.toLlvm(&self.wip));
4951 try llvm_args.append(load_inst);
4952 } else {4872 } else {
4953 try llvm_args.append(llvm_arg);4873 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
4954 }4874 }
4955 },4875 },
4956 .byref => {4876 .byref => {
...@@ -4958,14 +4878,13 @@ pub const FuncGen = struct {...@@ -4958,14 +4878,13 @@ pub const FuncGen = struct {
4958 const param_ty = self.typeOf(arg);4878 const param_ty = self.typeOf(arg);
4959 const llvm_arg = try self.resolveInst(arg);4879 const llvm_arg = try self.resolveInst(arg);
4960 if (isByRef(param_ty, mod)) {4880 if (isByRef(param_ty, mod)) {
4961 try llvm_args.append(llvm_arg);4881 try llvm_args.append(llvm_arg.toLlvm(&self.wip));
4962 } else {4882 } else {
4963 const alignment = param_ty.abiAlignment(mod);4883 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4964 const param_llvm_ty = llvm_arg.typeOf();4884 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
4965 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);4885 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
4966 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);4886 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
4967 store_inst.setAlignment(alignment);4887 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
4968 try llvm_args.append(arg_ptr);
4969 }4888 }
4970 },4889 },
4971 .byref_mut => {4890 .byref_mut => {
...@@ -4973,56 +4892,46 @@ pub const FuncGen = struct {...@@ -4973,56 +4892,46 @@ pub const FuncGen = struct {
4973 const param_ty = self.typeOf(arg);4892 const param_ty = self.typeOf(arg);
4974 const llvm_arg = try self.resolveInst(arg);4893 const llvm_arg = try self.resolveInst(arg);
49754894
4976 const alignment = param_ty.abiAlignment(mod);4895 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4977 const param_llvm_ty = (try o.lowerType(param_ty)).toLlvm(&o.builder);4896 const param_llvm_ty = try o.lowerType(param_ty);
4978 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);4897 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
4979 if (isByRef(param_ty, mod)) {4898 if (isByRef(param_ty, mod)) {
4980 const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, "");4899 const loaded = try self.wip.load(.normal, param_llvm_ty, llvm_arg, alignment, "");
4981 load_inst.setAlignment(alignment);4900 _ = try self.wip.store(.normal, loaded, arg_ptr, 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);
4986 } else {4901 } else {
4987 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);4902 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
4988 store_inst.setAlignment(alignment);
4989 try llvm_args.append(arg_ptr);
4990 }4903 }
4904 try llvm_args.append(arg_ptr.toLlvm(&self.wip));
4991 },4905 },
4992 .abi_sized_int => {4906 .abi_sized_int => {
4993 const arg = args[it.zig_index - 1];4907 const arg = args[it.zig_index - 1];
4994 const param_ty = self.typeOf(arg);4908 const param_ty = self.typeOf(arg);
4995 const llvm_arg = try self.resolveInst(arg);4909 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
4998 if (isByRef(param_ty, mod)) {4912 if (isByRef(param_ty, mod)) {
4999 const alignment = param_ty.abiAlignment(mod);4913 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5000 const load_inst = self.builder.buildLoad(int_llvm_ty, llvm_arg, "");4914 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
5001 load_inst.setAlignment(alignment);4915 try llvm_args.append(loaded.toLlvm(&self.wip));
5002 try llvm_args.append(load_inst);
5003 } else {4916 } else {
5004 // LLVM does not allow bitcasting structs so we must allocate4917 // LLVM does not allow bitcasting structs so we must allocate
5005 // a local, store as one type, and then load as another type.4918 // a local, store as one type, and then load as another type.
5006 const alignment = @max(4919 const alignment = Builder.Alignment.fromByteUnits(@max(
5007 param_ty.abiAlignment(mod),4920 param_ty.abiAlignment(mod),
5008 o.target_data.abiAlignmentOfType(int_llvm_ty),4921 o.target_data.abiAlignmentOfType(int_llvm_ty.toLlvm(&o.builder)),
5009 );4922 ));
5010 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);4923 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
5011 const store_inst = self.builder.buildStore(llvm_arg, int_ptr);4924 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
5012 store_inst.setAlignment(alignment);4925 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
5013 const load_inst = self.builder.buildLoad(int_llvm_ty, int_ptr, "");4926 try llvm_args.append(loaded.toLlvm(&self.wip));
5014 load_inst.setAlignment(alignment);
5015 try llvm_args.append(load_inst);
5016 }4927 }
5017 },4928 },
5018 .slice => {4929 .slice => {
5019 const arg = args[it.zig_index - 1];4930 const arg = args[it.zig_index - 1];
5020 const llvm_arg = try self.resolveInst(arg);4931 const llvm_arg = try self.resolveInst(arg);
5021 const ptr = self.builder.buildExtractValue(llvm_arg, 0, "");4932 const ptr = try self.wip.extractValue(llvm_arg, &.{0}, "");
5022 const len = self.builder.buildExtractValue(llvm_arg, 1, "");4933 const len = try self.wip.extractValue(llvm_arg, &.{1}, "");
5023 try llvm_args.ensureUnusedCapacity(2);4934 try llvm_args.appendSlice(&.{ ptr.toLlvm(&self.wip), len.toLlvm(&self.wip) });
5024 llvm_args.appendAssumeCapacity(ptr);
5025 llvm_args.appendAssumeCapacity(len);
5026 },4935 },
5027 .multiple_llvm_types => {4936 .multiple_llvm_types => {
5028 const arg = args[it.zig_index - 1];4937 const arg = args[it.zig_index - 1];
...@@ -5030,75 +4939,77 @@ pub const FuncGen = struct {...@@ -5030,75 +4939,77 @@ pub const FuncGen = struct {
5030 const llvm_types = it.types_buffer[0..it.types_len];4939 const llvm_types = it.types_buffer[0..it.types_len];
5031 const llvm_arg = try self.resolveInst(arg);4940 const llvm_arg = try self.resolveInst(arg);
5032 const is_by_ref = isByRef(param_ty, mod);4941 const is_by_ref = isByRef(param_ty, mod);
5033 const arg_ptr = if (is_by_ref) llvm_arg else p: {4942 const arg_ptr = if (is_by_ref) llvm_arg else ptr: {
5034 const p = try self.buildAlloca(llvm_arg.typeOf(), null);4943 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5035 const store_inst = self.builder.buildStore(llvm_arg, p);4944 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
5036 store_inst.setAlignment(param_ty.abiAlignment(mod));4945 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
5037 break :p p;4946 break :ptr ptr;
5038 };4947 };
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);
5041 try llvm_args.ensureUnusedCapacity(it.types_len);4950 try llvm_args.ensureUnusedCapacity(it.types_len);
5042 for (llvm_types, 0..) |field_ty, i| {4951 for (llvm_types, 0..) |field_ty, i| {
5043 const field_ptr = self.builder.buildStructGEP(llvm_ty, arg_ptr, @intCast(i), "");4952 const alignment =
5044 const load_inst = self.builder.buildLoad(field_ty.toLlvm(&o.builder), field_ptr, "");4953 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
5045 load_inst.setAlignment(target.ptrBitWidth() / 8);4954 const field_ptr = try self.wip.gepStruct(llvm_ty, arg_ptr, i, "");
5046 llvm_args.appendAssumeCapacity(load_inst);4955 const loaded = try self.wip.load(.normal, field_ty, field_ptr, alignment, "");
4956 llvm_args.appendAssumeCapacity(loaded.toLlvm(&self.wip));
5047 }4957 }
5048 },4958 },
5049 .as_u16 => {4959 .as_u16 => {
5050 const arg = args[it.zig_index - 1];4960 const arg = args[it.zig_index - 1];
5051 const llvm_arg = try self.resolveInst(arg);4961 const llvm_arg = try self.resolveInst(arg);
5052 const casted = self.builder.buildBitCast(llvm_arg, Builder.Type.i16.toLlvm(&o.builder), "");4962 const casted = try self.wip.cast(.bitcast, llvm_arg, .i16, "");
5053 try llvm_args.append(casted);4963 try llvm_args.append(casted.toLlvm(&self.wip));
5054 },4964 },
5055 .float_array => |count| {4965 .float_array => |count| {
5056 const arg = args[it.zig_index - 1];4966 const arg = args[it.zig_index - 1];
5057 const arg_ty = self.typeOf(arg);4967 const arg_ty = self.typeOf(arg);
5058 var llvm_arg = try self.resolveInst(arg);4968 var llvm_arg = try self.resolveInst(arg);
4969 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
5059 if (!isByRef(arg_ty, mod)) {4970 if (!isByRef(arg_ty, mod)) {
5060 const p = try self.buildAlloca(llvm_arg.typeOf(), null);4971 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
5061 const store_inst = self.builder.buildStore(llvm_arg, p);4972 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
5062 store_inst.setAlignment(arg_ty.abiAlignment(mod));4973 llvm_arg = ptr;
5063 llvm_arg = store_inst;
5064 }4974 }
50654975
5066 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, mod).?);4976 const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, mod).?);
5067 const array_ty = try o.builder.arrayType(count, float_ty);4977 const array_ty = try o.builder.arrayType(count, float_ty);
50684978
5069 const alignment = arg_ty.abiAlignment(mod);4979 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5070 const load_inst = self.builder.buildLoad(array_ty.toLlvm(&o.builder), llvm_arg, "");4980 try llvm_args.append(loaded.toLlvm(&self.wip));
5071 load_inst.setAlignment(alignment);
5072 try llvm_args.append(load_inst);
5073 },4981 },
5074 .i32_array, .i64_array => |arr_len| {4982 .i32_array, .i64_array => |arr_len| {
5075 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;4983 const elem_size: u8 = if (lowering == .i32_array) 32 else 64;
5076 const arg = args[it.zig_index - 1];4984 const arg = args[it.zig_index - 1];
5077 const arg_ty = self.typeOf(arg);4985 const arg_ty = self.typeOf(arg);
5078 var llvm_arg = try self.resolveInst(arg);4986 var llvm_arg = try self.resolveInst(arg);
4987 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
5079 if (!isByRef(arg_ty, mod)) {4988 if (!isByRef(arg_ty, mod)) {
5080 const p = try self.buildAlloca(llvm_arg.typeOf(), null);4989 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
5081 const store_inst = self.builder.buildStore(llvm_arg, p);4990 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
5082 store_inst.setAlignment(arg_ty.abiAlignment(mod));4991 llvm_arg = ptr;
5083 llvm_arg = store_inst;
5084 }4992 }
50854993
5086 const array_ty = try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));4994 const array_ty =
5087 const alignment = arg_ty.abiAlignment(mod);4995 try o.builder.arrayType(arr_len, try o.builder.intType(@intCast(elem_size)));
5088 const load_inst = self.builder.buildLoad(array_ty.toLlvm(&o.builder), llvm_arg, "");4996 const loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, "");
5089 load_inst.setAlignment(alignment);4997 try llvm_args.append(loaded.toLlvm(&self.wip));
5090 try llvm_args.append(load_inst);
5091 },4998 },
5092 };4999 };
50935000
5094 const call = self.builder.buildCall(5001 const llvm_fn_ty = try o.lowerType(zig_fn_ty);
5095 (try o.lowerType(zig_fn_ty)).toLlvm(&o.builder),5002 const call = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
5096 llvm_fn,5003 self.builder.buildCall(
5097 llvm_args.items.ptr,5004 llvm_fn_ty.toLlvm(&o.builder),
5098 @intCast(llvm_args.items.len),5005 llvm_fn.toLlvm(&self.wip),
5099 toLlvmCallConv(fn_info.cc, target),5006 llvm_args.items.ptr,
5100 attr,5007 @intCast(llvm_args.items.len),
5101 "",5008 toLlvmCallConv(fn_info.cc, target),
5009 attr,
5010 "",
5011 ),
5012 &self.wip,
5102 );5013 );
51035014
5104 if (callee_ty.zigTypeTag(mod) == .Pointer) {5015 if (callee_ty.zigTypeTag(mod) == .Pointer) {
...@@ -5111,7 +5022,7 @@ pub const FuncGen = struct {...@@ -5111,7 +5022,7 @@ pub const FuncGen = struct {
5111 const param_index = it.zig_index - 1;5022 const param_index = it.zig_index - 1;
5112 const param_ty = fn_info.param_types.get(ip)[param_index].toType();5023 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
5113 if (!isByRef(param_ty, mod)) {5024 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);
5115 }5026 }
5116 },5027 },
5117 .byref => {5028 .byref => {
...@@ -5119,10 +5030,10 @@ pub const FuncGen = struct {...@@ -5119,10 +5030,10 @@ pub const FuncGen = struct {
5119 const param_ty = fn_info.param_types.get(ip)[param_index].toType();5030 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
5120 const param_llvm_ty = try o.lowerType(param_ty);5031 const param_llvm_ty = try o.lowerType(param_ty);
5121 const alignment = param_ty.abiAlignment(mod);5032 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);
5123 },5034 },
5124 .byref_mut => {5035 .byref_mut => {
5125 o.addArgAttr(call, it.llvm_index - 1, "noundef");5036 o.addArgAttr(call.toLlvm(&self.wip), it.llvm_index - 1, "noundef");
5126 },5037 },
5127 // No attributes needed for these.5038 // No attributes needed for these.
5128 .no_bits,5039 .no_bits,
...@@ -5142,70 +5053,63 @@ pub const FuncGen = struct {...@@ -5142,70 +5053,63 @@ pub const FuncGen = struct {
51425053
5143 if (math.cast(u5, it.zig_index - 1)) |i| {5054 if (math.cast(u5, it.zig_index - 1)) |i| {
5144 if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {5055 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");
5146 }5057 }
5147 }5058 }
5148 if (param_ty.zigTypeTag(mod) != .Optional) {5059 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");
5150 }5061 }
5151 if (ptr_info.flags.is_const) {5062 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");
5153 }5064 }
5154 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse5065 const elem_align = ptr_info.flags.alignment.toByteUnitsOptional() orelse
5155 @max(ptr_info.child.toType().abiAlignment(mod), 1);5066 @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);
5157 },5068 },
5158 };5069 };
5159 }5070 }
51605071
5161 if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {5072 if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) {
5162 return null;5073 return .none;
5163 }5074 }
51645075
5165 if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime(mod)) {5076 if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime(mod)) {
5166 return null;5077 return .none;
5167 }5078 }
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
5171 if (ret_ptr) |rp| {5082 if (ret_ptr) |rp| {
5172 call.setCallSret(llvm_ret_ty);5083 call.toLlvm(&self.wip).setCallSret(llvm_ret_ty.toLlvm(&o.builder));
5173 if (isByRef(return_type, mod)) {5084 if (isByRef(return_type, mod)) {
5174 return rp;5085 return rp;
5175 } else {5086 } else {
5176 // our by-ref status disagrees with sret so we must load.5087 // our by-ref status disagrees with sret so we must load.
5177 const loaded = self.builder.buildLoad(llvm_ret_ty, rp, "");5088 const return_alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
5178 loaded.setAlignment(return_type.abiAlignment(mod));5089 return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, "");
5179 return loaded;
5180 }5090 }
5181 }5091 }
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
5185 if (abi_ret_ty != llvm_ret_ty) {5095 if (abi_ret_ty != llvm_ret_ty) {
5186 // In this case the function return type is honoring the calling convention by having5096 // In this case the function return type is honoring the calling convention by having
5187 // a different LLVM type than the usual one. We solve this here at the callsite5097 // a different LLVM type than the usual one. We solve this here at the callsite
5188 // by using our canonical type, then loading it if necessary.5098 // by using our canonical type, then loading it if necessary.
5189 const alignment = o.target_data.abiAlignmentOfType(abi_ret_ty);5099 const rp = try self.buildAlloca(llvm_ret_ty, .default);
5190 const rp = try self.buildAlloca(llvm_ret_ty, alignment);5100 _ = try self.wip.store(.normal, call, rp, .default);
5191 const store_inst = self.builder.buildStore(call, rp);5101 return if (isByRef(return_type, mod))
5192 store_inst.setAlignment(alignment);5102 rp
5193 if (isByRef(return_type, mod)) {5103 else
5194 return rp;5104 try self.wip.load(.normal, llvm_ret_ty, rp, .default, "");
5195 } else {
5196 const load_inst = self.builder.buildLoad(llvm_ret_ty, rp, "");
5197 load_inst.setAlignment(alignment);
5198 return load_inst;
5199 }
5200 }5105 }
52015106
5202 if (isByRef(return_type, mod)) {5107 if (isByRef(return_type, mod)) {
5203 // our by-ref status disagrees with sret so we must allocate, store,5108 // our by-ref status disagrees with sret so we must allocate, store,
5204 // and return the allocation pointer.5109 // and return the allocation pointer.
5205 const alignment = return_type.abiAlignment(mod);5110 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
5206 const rp = try self.buildAlloca(llvm_ret_ty, alignment);5111 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5207 const store_inst = self.builder.buildStore(call, rp);5112 _ = try self.wip.store(.normal, call, rp, alignment);
5208 store_inst.setAlignment(alignment);
5209 return rp;5113 return rp;
5210 } else {5114 } else {
5211 return call;5115 return call;
...@@ -5239,7 +5143,7 @@ pub const FuncGen = struct {...@@ -5239,7 +5143,7 @@ pub const FuncGen = struct {
5239 const panic_decl = mod.declPtr(panic_func.owner_decl);5143 const panic_decl = mod.declPtr(panic_func.owner_decl);
5240 const fn_info = mod.typeToFunc(panic_decl.ty).?;5144 const fn_info = mod.typeToFunc(panic_decl.ty).?;
5241 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);5145 const panic_global = try o.resolveLlvmFunction(panic_func.owner_decl);
5242 _ = fg.builder.buildCall(5146 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildCall(
5243 (try o.lowerType(panic_decl.ty)).toLlvm(&o.builder),5147 (try o.lowerType(panic_decl.ty)).toLlvm(&o.builder),
5244 panic_global.toLlvm(&o.builder),5148 panic_global.toLlvm(&o.builder),
5245 &args,5149 &args,
...@@ -5247,21 +5151,21 @@ pub const FuncGen = struct {...@@ -5247,21 +5151,21 @@ pub const FuncGen = struct {
5247 toLlvmCallConv(fn_info.cc, target),5151 toLlvmCallConv(fn_info.cc, target),
5248 .Auto,5152 .Auto,
5249 "",5153 "",
5250 );5154 ), &fg.wip);
5251 _ = fg.builder.buildUnreachable();5155 _ = try fg.wip.@"unreachable"();
5252 }5156 }
52535157
5254 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5158 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5255 const o = self.dg.object;5159 const o = self.dg.object;
5256 const mod = o.module;5160 const mod = o.module;
5257 const un_op = self.air.instructions.items(.data)[inst].un_op;5161 const un_op = self.air.instructions.items(.data)[inst].un_op;
5258 const ret_ty = self.typeOf(un_op);5162 const ret_ty = self.typeOf(un_op);
5259 if (self.ret_ptr) |ret_ptr| {5163 if (self.ret_ptr != .none) {
5260 const operand = try self.resolveInst(un_op);5164 const operand = try self.resolveInst(un_op);
5261 const ptr_ty = try mod.singleMutPtrType(ret_ty);5165 const ptr_ty = try mod.singleMutPtrType(ret_ty);
5262 try self.store(ret_ptr, ptr_ty, operand, .NotAtomic);5166 try self.store(self.ret_ptr, ptr_ty, operand, .none);
5263 try self.wip.retVoid();5167 _ = try self.wip.retVoid();
5264 return null;5168 return .none;
5265 }5169 }
5266 const fn_info = mod.typeToFunc(self.dg.decl.ty).?;5170 const fn_info = mod.typeToFunc(self.dg.decl.ty).?;
5267 if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {5171 if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) {
...@@ -5269,43 +5173,37 @@ pub const FuncGen = struct {...@@ -5269,43 +5173,37 @@ pub const FuncGen = struct {
5269 // Functions with an empty error set are emitted with an error code5173 // Functions with an empty error set are emitted with an error code
5270 // return type and return zero so they can be function pointers coerced5174 // return type and return zero so they can be function pointers coerced
5271 // to functions that return anyerror.5175 // to functions that return anyerror.
5272 const int = try o.builder.intConst(Builder.Type.err_int, 0);5176 _ = try self.wip.ret(try o.builder.intValue(Builder.Type.err_int, 0));
5273 _ = self.builder.buildRet(int.toLlvm(&o.builder));
5274 } else {5177 } else {
5275 try self.wip.retVoid();5178 _ = try self.wip.retVoid();
5276 }5179 }
5277 return null;5180 return .none;
5278 }5181 }
52795182
5280 const abi_ret_ty = (try lowerFnRetTy(o, fn_info)).toLlvm(&o.builder);5183 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
5281 const operand = try self.resolveInst(un_op);5184 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
5284 if (isByRef(ret_ty, mod)) {5187 if (isByRef(ret_ty, mod)) {
5285 // operand is a pointer however self.ret_ptr is null so that means5188 // operand is a pointer however self.ret_ptr is null so that means
5286 // we need to return a value.5189 // we need to return a value.
5287 const load_inst = self.builder.buildLoad(abi_ret_ty, operand, "");5190 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, operand, alignment, ""));
5288 load_inst.setAlignment(alignment);5191 return .none;
5289 _ = self.builder.buildRet(load_inst);
5290 return null;
5291 }5192 }
52925193
5293 const llvm_ret_ty = operand.typeOf();5194 const llvm_ret_ty = operand.typeOfWip(&self.wip);
5294 if (abi_ret_ty == llvm_ret_ty) {5195 if (abi_ret_ty == llvm_ret_ty) {
5295 _ = self.builder.buildRet(operand);5196 _ = try self.wip.ret(operand);
5296 return null;5197 return .none;
5297 }5198 }
52985199
5299 const rp = try self.buildAlloca(llvm_ret_ty, alignment);5200 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5300 const store_inst = self.builder.buildStore(operand, rp);5201 _ = try self.wip.store(.normal, operand, rp, alignment);
5301 store_inst.setAlignment(alignment);5202 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, rp, alignment, ""));
5302 const load_inst = self.builder.buildLoad(abi_ret_ty, rp, "");5203 return .none;
5303 load_inst.setAlignment(alignment);
5304 _ = self.builder.buildRet(load_inst);
5305 return null;
5306 }5204 }
53075205
5308 fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5206 fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5309 const o = self.dg.object;5207 const o = self.dg.object;
5310 const mod = o.module;5208 const mod = o.module;
5311 const un_op = self.air.instructions.items(.data)[inst].un_op;5209 const un_op = self.air.instructions.items(.data)[inst].un_op;
...@@ -5317,106 +5215,121 @@ pub const FuncGen = struct {...@@ -5317,106 +5215,121 @@ pub const FuncGen = struct {
5317 // Functions with an empty error set are emitted with an error code5215 // Functions with an empty error set are emitted with an error code
5318 // return type and return zero so they can be function pointers coerced5216 // return type and return zero so they can be function pointers coerced
5319 // to functions that return anyerror.5217 // to functions that return anyerror.
5320 const int = try o.builder.intConst(Builder.Type.err_int, 0);5218 _ = try self.wip.ret(try o.builder.intValue(Builder.Type.err_int, 0));
5321 _ = self.builder.buildRet(int.toLlvm(&o.builder));
5322 } else {5219 } else {
5323 try self.wip.retVoid();5220 _ = try self.wip.retVoid();
5324 }5221 }
5325 return null;5222 return .none;
5326 }5223 }
5327 if (self.ret_ptr != null) {5224 if (self.ret_ptr != .none) {
5328 try self.wip.retVoid();5225 _ = try self.wip.retVoid();
5329 return null;5226 return .none;
5330 }5227 }
5331 const ptr = try self.resolveInst(un_op);5228 const ptr = try self.resolveInst(un_op);
5332 const abi_ret_ty = (try lowerFnRetTy(o, fn_info)).toLlvm(&o.builder);5229 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
5333 const loaded = self.builder.buildLoad(abi_ret_ty, ptr, "");5230 const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod));
5334 loaded.setAlignment(ret_ty.abiAlignment(mod));5231 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, ""));
5335 _ = self.builder.buildRet(loaded);5232 return .none;
5336 return null;
5337 }5233 }
53385234
5339 fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5235 fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5340 const o = self.dg.object;5236 const o = self.dg.object;
5341 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5237 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5342 const list = try self.resolveInst(ty_op.operand);5238 const list = try self.resolveInst(ty_op.operand);
5343 const arg_ty = self.air.getRefType(ty_op.ty);5239 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, "");
5347 }5243 }
53485244
5349 fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5245 fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5350 const o = self.dg.object;5246 const o = self.dg.object;
5351 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5247 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5352 const src_list = try self.resolveInst(ty_op.operand);5248 const src_list = try self.resolveInst(ty_op.operand);
5353 const va_list_ty = self.air.getRefType(ty_op.ty);5249 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);
5355 const mod = o.module;5251 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));
5358 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);5254 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
53595255
5360 const llvm_fn_name = "llvm.va_copy";5256 const llvm_fn_name = "llvm.va_copy";
5361 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {5257 const llvm_fn_ty = try o.builder.fnType(.void, &.{ .ptr, .ptr }, .normal);
5362 const fn_type = try o.builder.fnType(.void, &.{ .ptr, .ptr }, .normal);5258 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5363 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));5259 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
5364 };
53655260
5366 const args: [2]*llvm.Value = .{ dest_list, src_list };5261 const args: [2]*llvm.Value = .{ dest_list.toLlvm(&self.wip), src_list.toLlvm(&self.wip) };
5367 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");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)) {5272 return if (isByRef(va_list_ty, mod))
5370 return dest_list;5273 dest_list
5371 } else {5274 else
5372 const loaded = self.builder.buildLoad(llvm_va_list_ty, dest_list, "");5275 try self.wip.load(.normal, llvm_va_list_ty, dest_list, result_alignment, "");
5373 loaded.setAlignment(result_alignment);
5374 return loaded;
5375 }
5376 }5276 }
53775277
5378 fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5278 fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5379 const o = self.dg.object;5279 const o = self.dg.object;
5380 const un_op = self.air.instructions.items(.data)[inst].un_op;5280 const un_op = self.air.instructions.items(.data)[inst].un_op;
5381 const list = try self.resolveInst(un_op);5281 const list = try self.resolveInst(un_op);
53825282
5383 const llvm_fn_name = "llvm.va_end";5283 const llvm_fn_name = "llvm.va_end";
5384 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {5284 const llvm_fn_ty = try o.builder.fnType(.void, &.{.ptr}, .normal);
5385 const fn_type = try o.builder.fnType(.void, &.{.ptr}, .normal);5285 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5386 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));5286 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
5387 };5287
5388 const args: [1]*llvm.Value = .{list};5288 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5389 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");5289 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5390 return null;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;
5391 }5299 }
53925300
5393 fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5301 fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5394 const o = self.dg.object;5302 const o = self.dg.object;
5395 const mod = o.module;5303 const mod = o.module;
5396 const va_list_ty = self.typeOfIndex(inst);5304 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));
5400 const list = try self.buildAlloca(llvm_va_list_ty, result_alignment);5308 const list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
54015309
5402 const llvm_fn_name = "llvm.va_start";5310 const llvm_fn_name = "llvm.va_start";
5403 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {5311 const llvm_fn_ty = try o.builder.fnType(.void, &.{.ptr}, .normal);
5404 const fn_type = try o.builder.fnType(.void, &.{.ptr}, .normal);5312 const llvm_fn = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
5405 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));5313 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.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, "");
54095314
5410 if (isByRef(va_list_ty, mod)) {5315 const args: [1]*llvm.Value = .{list.toLlvm(&self.wip)};
5411 return list;5316 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
5412 } else {5317 llvm_fn_ty.toLlvm(&o.builder),
5413 const loaded = self.builder.buildLoad(llvm_va_list_ty, list, "");5318 llvm_fn,
5414 loaded.setAlignment(result_alignment);5319 &args,
5415 return loaded;5320 args.len,
5416 }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, "");
5417 }5330 }
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 {
5420 self.builder.setFastMath(want_fast_math);5333 self.builder.setFastMath(want_fast_math);
54215334
5422 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5335 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -5427,7 +5340,7 @@ pub const FuncGen = struct {...@@ -5427,7 +5340,7 @@ pub const FuncGen = struct {
5427 return self.cmp(lhs, rhs, operand_ty, op);5340 return self.cmp(lhs, rhs, operand_ty, op);
5428 }5341 }
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 {
5431 self.builder.setFastMath(want_fast_math);5344 self.builder.setFastMath(want_fast_math);
54325345
5433 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5346 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -5441,21 +5354,30 @@ pub const FuncGen = struct {...@@ -5441,21 +5354,30 @@ pub const FuncGen = struct {
5441 return self.cmp(lhs, rhs, vec_ty, cmp_op);5354 return self.cmp(lhs, rhs, vec_ty, cmp_op);
5442 }5355 }
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;
5445 const un_op = self.air.instructions.items(.data)[inst].un_op;5359 const un_op = self.air.instructions.items(.data)[inst].un_op;
5446 const operand = try self.resolveInst(un_op);5360 const operand = try self.resolveInst(un_op);
5447 const llvm_fn = try self.getCmpLtErrorsLenFunction();5361 const llvm_fn = try self.getCmpLtErrorsLenFunction();
5448 const args: [1]*llvm.Value = .{operand};5362 const args: [1]*llvm.Value = .{operand.toLlvm(&self.wip)};
5449 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");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);
5450 }5372 }
54515373
5452 fn cmp(5374 fn cmp(
5453 self: *FuncGen,5375 self: *FuncGen,
5454 lhs: *llvm.Value,5376 lhs: Builder.Value,
5455 rhs: *llvm.Value,5377 rhs: Builder.Value,
5456 operand_ty: Type,5378 operand_ty: Type,
5457 op: math.CompareOperator,5379 op: math.CompareOperator,
5458 ) Allocator.Error!*llvm.Value {5380 ) Allocator.Error!Builder.Value {
5459 const o = self.dg.object;5381 const o = self.dg.object;
5460 const mod = o.module;5382 const mod = o.module;
5461 const scalar_ty = operand_ty.scalarType(mod);5383 const scalar_ty = operand_ty.scalarType(mod);
...@@ -5472,50 +5394,48 @@ pub const FuncGen = struct {...@@ -5472,50 +5394,48 @@ pub const FuncGen = struct {
5472 // We need to emit instructions to check for equality/inequality5394 // We need to emit instructions to check for equality/inequality
5473 // of optionals that are not pointers.5395 // of optionals that are not pointers.
5474 const is_by_ref = isByRef(scalar_ty, mod);5396 const is_by_ref = isByRef(scalar_ty, mod);
5475 const opt_llvm_ty = (try o.lowerType(scalar_ty)).toLlvm(&o.builder);5397 const opt_llvm_ty = try o.lowerType(scalar_ty);
5476 const lhs_non_null = try self.optIsNonNull(opt_llvm_ty, lhs, is_by_ref);5398 const lhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, lhs, is_by_ref);
5477 const rhs_non_null = try self.optIsNonNull(opt_llvm_ty, rhs, is_by_ref);5399 const rhs_non_null = try self.optCmpNull(.ne, opt_llvm_ty, rhs, is_by_ref);
5478 const llvm_i2 = try o.builder.intType(2);5400 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), "");5401 const lhs_non_null_i2 = try self.wip.cast(.zext, lhs_non_null, llvm_i2, "");
5480 const rhs_non_null_i2 = self.builder.buildZExt(rhs_non_null, llvm_i2.toLlvm(&o.builder), "");5402 const rhs_non_null_i2 = try self.wip.cast(.zext, rhs_non_null, llvm_i2, "");
5481 const lhs_shifted = self.builder.buildShl(lhs_non_null_i2, (try o.builder.intConst(llvm_i2, 1)).toLlvm(&o.builder), "");5403 const lhs_shifted = try self.wip.bin(.shl, lhs_non_null_i2, try o.builder.intValue(llvm_i2, 1), "");
5482 const lhs_rhs_ored = self.builder.buildOr(lhs_shifted, rhs_non_null_i2, "");5404 const lhs_rhs_ored = try self.wip.bin(.@"or", lhs_shifted, rhs_non_null_i2, "");
5483 const both_null_block = try self.wip.block("BothNull");5405 const both_null_block = try self.wip.block(1, "BothNull");
5484 const mixed_block = try self.wip.block("Mixed");5406 const mixed_block = try self.wip.block(1, "Mixed");
5485 const both_pl_block = try self.wip.block("BothNonNull");5407 const both_pl_block = try self.wip.block(1, "BothNonNull");
5486 const end_block = try self.wip.block("End");5408 const end_block = try self.wip.block(3, "End");
5487 const llvm_switch = self.builder.buildSwitch(lhs_rhs_ored, mixed_block.toLlvm(&self.wip), 2);5409 var wip_switch = try self.wip.@"switch"(lhs_rhs_ored, mixed_block, 2);
5488 const llvm_i2_00 = try o.builder.intConst(llvm_i2, 0b00);5410 defer wip_switch.finish(&self.wip);
5489 const llvm_i2_11 = try o.builder.intConst(llvm_i2, 0b11);5411 try wip_switch.addCase(
5490 llvm_switch.addCase(llvm_i2_00.toLlvm(&o.builder), both_null_block.toLlvm(&self.wip));5412 try o.builder.intConst(llvm_i2, 0b00),
5491 llvm_switch.addCase(llvm_i2_11.toLlvm(&o.builder), both_pl_block.toLlvm(&self.wip));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
5493 self.wip.cursor = .{ .block = both_null_block };5422 self.wip.cursor = .{ .block = both_null_block };
5494 self.builder.positionBuilderAtEnd(both_null_block.toLlvm(&self.wip));5423 _ = try self.wip.br(end_block);
5495 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
54965424
5497 self.wip.cursor = .{ .block = mixed_block };5425 self.wip.cursor = .{ .block = mixed_block };
5498 self.builder.positionBuilderAtEnd(mixed_block.toLlvm(&self.wip));5426 _ = try self.wip.br(end_block);
5499 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
55005427
5501 self.wip.cursor = .{ .block = both_pl_block };5428 self.wip.cursor = .{ .block = both_pl_block };
5502 self.builder.positionBuilderAtEnd(both_pl_block.toLlvm(&self.wip));
5503 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty, true);5429 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty, true);
5504 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true);5430 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true);
5505 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);5431 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);
5506 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));5432 _ = try self.wip.br(end_block);
5507 const both_pl_block_end = self.builder.getInsertBlock();5433 const both_pl_block_end = self.wip.cursor.block;
55085434
5509 self.wip.cursor = .{ .block = end_block };5435 self.wip.cursor = .{ .block = end_block };
5510 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));5436 const llvm_i1_0 = try o.builder.intValue(.i1, 0);
5511 const incoming_blocks: [3]*llvm.BasicBlock = .{5437 const llvm_i1_1 = try o.builder.intValue(.i1, 1);
5512 both_null_block.toLlvm(&self.wip),5438 const incoming_values: [3]Builder.Value = .{
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 = .{
5519 switch (op) {5439 switch (op) {
5520 .eq => llvm_i1_1,5440 .eq => llvm_i1_1,
5521 .neq => llvm_i1_0,5441 .neq => llvm_i1_0,
...@@ -5529,31 +5449,30 @@ pub const FuncGen = struct {...@@ -5529,31 +5449,30 @@ pub const FuncGen = struct {
5529 payload_cmp,5449 payload_cmp,
5530 };5450 };
55315451
5532 const phi_node = self.builder.buildPhi(Builder.Type.i1.toLlvm(&o.builder), "");5452 const phi = try self.wip.phi(.i1, "");
5533 comptime assert(incoming_values.len == incoming_blocks.len);5453 try phi.finish(
5534 phi_node.addIncoming(
5535 &incoming_values,5454 &incoming_values,
5536 &incoming_blocks,5455 &.{ both_null_block, mixed_block, both_pl_block_end },
5537 incoming_values.len,5456 &self.wip,
5538 );5457 );
5539 return phi_node;5458 return phi.toValue();
5540 },5459 },
5541 .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }),5460 .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }),
5542 else => unreachable,5461 else => unreachable,
5543 };5462 };
5544 const is_signed = int_ty.isSignedInt(mod);5463 const is_signed = int_ty.isSignedInt(mod);
5545 const operation: llvm.IntPredicate = switch (op) {5464 const cond: Builder.IntegerCondition = switch (op) {
5546 .eq => .EQ,5465 .eq => .eq,
5547 .neq => .NE,5466 .neq => .ne,
5548 .lt => if (is_signed) llvm.IntPredicate.SLT else .ULT,5467 .lt => if (is_signed) .slt else .ult,
5549 .lte => if (is_signed) llvm.IntPredicate.SLE else .ULE,5468 .lte => if (is_signed) .sle else .ule,
5550 .gt => if (is_signed) llvm.IntPredicate.SGT else .UGT,5469 .gt => if (is_signed) .sgt else .ugt,
5551 .gte => if (is_signed) llvm.IntPredicate.SGE else .UGE,5470 .gte => if (is_signed) .sge else .uge,
5552 };5471 };
5553 return self.builder.buildICmp(operation, lhs, rhs, "");5472 return self.wip.icmp(cond, lhs, rhs, "");
5554 }5473 }
55555474
5556 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5475 fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5557 const o = self.dg.object;5476 const o = self.dg.object;
5558 const mod = o.module;5477 const mod = o.module;
5559 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5478 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -5563,13 +5482,15 @@ pub const FuncGen = struct {...@@ -5563,13 +5482,15 @@ pub const FuncGen = struct {
55635482
5564 if (inst_ty.isNoReturn(mod)) {5483 if (inst_ty.isNoReturn(mod)) {
5565 try self.genBody(body);5484 try self.genBody(body);
5566 return null;5485 return .none;
5567 }5486 }
55685487
5569 var breaks: BreakList = .{};5488 const have_block_result = inst_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod);
5570 defer breaks.deinit(self.gpa);
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");
5573 try self.blocks.putNoClobber(self.gpa, inst, .{5494 try self.blocks.putNoClobber(self.gpa, inst, .{
5574 .parent_bb = parent_bb,5495 .parent_bb = parent_bb,
5575 .breaks = &breaks,5496 .breaks = &breaks,
...@@ -5579,35 +5500,32 @@ pub const FuncGen = struct {...@@ -5579,35 +5500,32 @@ pub const FuncGen = struct {
5579 try self.genBody(body);5500 try self.genBody(body);
55805501
5581 self.wip.cursor = .{ .block = parent_bb };5502 self.wip.cursor = .{ .block = parent_bb };
5582 self.builder.positionBuilderAtEnd(parent_bb.toLlvm(&self.wip));
55835503
5584 // Create a phi node only if the block returns a value.5504 // Create a phi node only if the block returns a value.
5585 const is_body = inst_ty.zigTypeTag(mod) == .Fn;5505 if (have_block_result) {
5586 if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;5506 const raw_llvm_ty = try o.lowerType(inst_ty);
55875507 const llvm_ty: Builder.Type = ty: {
5588 const raw_llvm_ty = (try o.lowerType(inst_ty)).toLlvm(&o.builder);5508 // If the zig tag type is a function, this represents an actual function body; not
55895509 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
5590 const llvm_ty = ty: {5510 // of function pointers, however the phi makes it a runtime value and therefore
5591 // If the zig tag type is a function, this represents an actual function body; not5511 // the LLVM type has to be wrapped in a pointer.
5592 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead5512 if (inst_ty.zigTypeTag(mod) == .Fn or isByRef(inst_ty, mod)) {
5593 // of function pointers, however the phi makes it a runtime value and therefore5513 break :ty .ptr;
5594 // the LLVM type has to be wrapped in a pointer.5514 }
5595 if (is_body or isByRef(inst_ty, mod)) {5515 break :ty raw_llvm_ty;
5596 break :ty Builder.Type.ptr.toLlvm(&o.builder);5516 };
5597 }
5598 break :ty raw_llvm_ty;
5599 };
56005517
5601 const phi_node = self.builder.buildPhi(llvm_ty, "");5518 parent_bb.ptr(&self.wip).incoming = @intCast(breaks.list.len);
5602 phi_node.addIncoming(5519 const phi = try self.wip.phi(llvm_ty, "");
5603 breaks.items(.val).ptr,5520 try phi.finish(breaks.list.items(.val), breaks.list.items(.bb), &self.wip);
5604 breaks.items(.bb).ptr,5521 return phi.toValue();
5605 @intCast(breaks.len),5522 } else {
5606 );5523 parent_bb.ptr(&self.wip).incoming = @intCast(breaks.len);
5607 return phi_node;5524 return .none;
5525 }
5608 }5526 }
56095527
5610 fn airBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5528 fn airBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5611 const o = self.dg.object;5529 const o = self.dg.object;
5612 const branch = self.air.instructions.items(.data)[inst].br;5530 const branch = self.air.instructions.items(.data)[inst].br;
5613 const block = self.blocks.get(branch.block_inst).?;5531 const block = self.blocks.get(branch.block_inst).?;
...@@ -5615,44 +5533,39 @@ pub const FuncGen = struct {...@@ -5615,44 +5533,39 @@ pub const FuncGen = struct {
5615 // Add the values to the lists only if the break provides a value.5533 // Add the values to the lists only if the break provides a value.
5616 const operand_ty = self.typeOf(branch.operand);5534 const operand_ty = self.typeOf(branch.operand);
5617 const mod = o.module;5535 const mod = o.module;
5618 if (operand_ty.hasRuntimeBitsIgnoreComptime(mod) or operand_ty.zigTypeTag(mod) == .Fn) {5536 if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
5619 const val = try self.resolveInst(branch.operand);5537 const val = try self.resolveInst(branch.operand);
56205538
5621 // For the phi node, we need the basic blocks and the values of the5539 // For the phi node, we need the basic blocks and the values of the
5622 // break instructions.5540 // break instructions.
5623 try block.breaks.append(self.gpa, .{5541 try block.breaks.list.append(self.gpa, .{ .bb = self.wip.cursor.block, .val = val });
5624 .bb = self.builder.getInsertBlock(),5542 } else block.breaks.len += 1;
5625 .val = val,5543 _ = try self.wip.br(block.parent_bb);
5626 });5544 return .none;
5627 }
5628 _ = self.builder.buildBr(block.parent_bb.toLlvm(&self.wip));
5629 return null;
5630 }5545 }
56315546
5632 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5547 fn airCondBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5633 const pl_op = self.air.instructions.items(.data)[inst].pl_op;5548 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
5634 const cond = try self.resolveInst(pl_op.operand);5549 const cond = try self.resolveInst(pl_op.operand);
5635 const extra = self.air.extraData(Air.CondBr, pl_op.payload);5550 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
5636 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];5551 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
5637 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];5552 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");5554 const then_block = try self.wip.block(1, "Then");
5640 const else_block = try self.wip.block("Else");5555 const else_block = try self.wip.block(1, "Else");
5641 _ = self.builder.buildCondBr(cond, then_block.toLlvm(&self.wip), else_block.toLlvm(&self.wip));5556 _ = try self.wip.brCond(cond, then_block, else_block);
56425557
5643 self.wip.cursor = .{ .block = then_block };5558 self.wip.cursor = .{ .block = then_block };
5644 self.builder.positionBuilderAtEnd(then_block.toLlvm(&self.wip));
5645 try self.genBody(then_body);5559 try self.genBody(then_body);
56465560
5647 self.wip.cursor = .{ .block = else_block };5561 self.wip.cursor = .{ .block = else_block };
5648 self.builder.positionBuilderAtEnd(else_block.toLlvm(&self.wip));
5649 try self.genBody(else_body);5562 try self.genBody(else_body);
56505563
5651 // No need to reset the insert cursor since this instruction is noreturn.5564 // No need to reset the insert cursor since this instruction is noreturn.
5652 return null;5565 return .none;
5653 }5566 }
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 {
5656 const o = self.dg.object;5569 const o = self.dg.object;
5657 const mod = o.module;5570 const mod = o.module;
5658 const inst = body_tail[0];5571 const inst = body_tail[0];
...@@ -5667,7 +5580,7 @@ pub const FuncGen = struct {...@@ -5667,7 +5580,7 @@ pub const FuncGen = struct {
5667 return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused);5580 return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused);
5668 }5581 }
56695582
5670 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5583 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5671 const o = self.dg.object;5584 const o = self.dg.object;
5672 const mod = o.module;5585 const mod = o.module;
5673 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5586 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -5681,139 +5594,149 @@ pub const FuncGen = struct {...@@ -5681,139 +5594,149 @@ pub const FuncGen = struct {
56815594
5682 fn lowerTry(5595 fn lowerTry(
5683 fg: *FuncGen,5596 fg: *FuncGen,
5684 err_union: *llvm.Value,5597 err_union: Builder.Value,
5685 body: []const Air.Inst.Index,5598 body: []const Air.Inst.Index,
5686 err_union_ty: Type,5599 err_union_ty: Type,
5687 operand_is_ptr: bool,5600 operand_is_ptr: bool,
5688 can_elide_load: bool,5601 can_elide_load: bool,
5689 is_unused: bool,5602 is_unused: bool,
5690 ) !?*llvm.Value {5603 ) !Builder.Value {
5691 const o = fg.dg.object;5604 const o = fg.dg.object;
5692 const mod = o.module;5605 const mod = o.module;
5693 const payload_ty = err_union_ty.errorUnionPayload(mod);5606 const payload_ty = err_union_ty.errorUnionPayload(mod);
5694 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod);5607 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
5697 if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {5610 if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
5698 const is_err = err: {5611 const loaded = loaded: {
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);
5701 if (!payload_has_bits) {5612 if (!payload_has_bits) {
5702 // TODO add alignment to this load5613 // TODO add alignment to this load
5703 const loaded = if (operand_is_ptr)5614 break :loaded if (operand_is_ptr)
5704 fg.builder.buildLoad(err_set_ty, err_union, "")5615 try fg.wip.load(.normal, Builder.Type.err_int, err_union, .default, "")
5705 else5616 else
5706 err_union;5617 err_union;
5707 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
5708 }5618 }
5709 const err_field_index = errUnionErrorOffset(payload_ty, mod);5619 const err_field_index = errUnionErrorOffset(payload_ty, mod);
5710 if (operand_is_ptr or isByRef(err_union_ty, mod)) {5620 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, "");
5712 // TODO add alignment to this load5623 // TODO add alignment to this load
5713 const loaded = fg.builder.buildLoad(err_set_ty, err_field_ptr, "");5624 break :loaded try fg.wip.load(
5714 break :err fg.builder.buildICmp(.NE, loaded, zero, "");5625 .normal,
5626 Builder.Type.err_int,
5627 err_field_ptr,
5628 .default,
5629 "",
5630 );
5715 }5631 }
5716 const loaded = fg.builder.buildExtractValue(err_union, err_field_index, "");5632 break :loaded try fg.wip.extractValue(err_union, &.{err_field_index}, "");
5717 break :err fg.builder.buildICmp(.NE, loaded, zero, "");
5718 };5633 };
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");5637 const return_block = try fg.wip.block(1, "TryRet");
5721 const continue_block = try fg.wip.block("TryCont");5638 const continue_block = try fg.wip.block(1, "TryCont");
5722 _ = fg.builder.buildCondBr(is_err, return_block.toLlvm(&fg.wip), continue_block.toLlvm(&fg.wip));5639 _ = try fg.wip.brCond(is_err, return_block, continue_block);
57235640
5724 fg.wip.cursor = .{ .block = return_block };5641 fg.wip.cursor = .{ .block = return_block };
5725 fg.builder.positionBuilderAtEnd(return_block.toLlvm(&fg.wip));
5726 try fg.genBody(body);5642 try fg.genBody(body);
57275643
5728 fg.wip.cursor = .{ .block = continue_block };5644 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;
5736 }5645 }
5646 if (is_unused) return .none;
5647 if (!payload_has_bits) return if (operand_is_ptr) err_union else .none;
5737 const offset = errUnionPayloadOffset(payload_ty, mod);5648 const offset = errUnionPayloadOffset(payload_ty, mod);
5738 if (operand_is_ptr) {5649 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, "");
5740 } else if (isByRef(err_union_ty, mod)) {5651 } 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));
5742 if (isByRef(payload_ty, mod)) {5654 if (isByRef(payload_ty, mod)) {
5743 if (can_elide_load)5655 if (can_elide_load)
5744 return payload_ptr;5656 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);
5747 }5659 }
5748 const load_inst = fg.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, "");5660 const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
5749 load_inst.setAlignment(payload_ty.abiAlignment(mod));5661 return fg.wip.load(.normal, load_ty, payload_ptr, payload_alignment, "");
5750 return load_inst;
5751 }5662 }
5752 return fg.builder.buildExtractValue(err_union, offset, "");5663 return fg.wip.extractValue(err_union, &.{offset}, "");
5753 }5664 }
57545665
5755 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5666 fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5756 const o = self.dg.object;5667 const o = self.dg.object;
5757 const pl_op = self.air.instructions.items(.data)[inst].pl_op;5668 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
5758 const cond = try self.resolveInst(pl_op.operand);5669 const cond = try self.resolveInst(pl_op.operand);
5759 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);5670 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
5760 const else_block = try self.wip.block("Else");5671 const else_block = try self.wip.block(1, "Default");
5761 const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder);5672 const llvm_usize = try o.lowerType(Type.usize);
5762 const cond_int = if (cond.typeOf().getTypeKind() == .Pointer)5673 const cond_int = if (cond.typeOfWip(&self.wip).isPointer(&o.builder))
5763 self.builder.buildPtrToInt(cond, llvm_usize, "")5674 try self.wip.cast(.ptrtoint, cond, llvm_usize, "")
5764 else5675 else
5765 cond;5676 cond;
5766 const llvm_switch = self.builder.buildSwitch(cond_int, else_block.toLlvm(&self.wip), switch_br.data.cases_len);
57675677
5768 var extra_index: usize = switch_br.end;5678 var extra_index: usize = switch_br.end;
5769 var case_i: u32 = 0;5679 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;
5771 while (case_i < switch_br.data.cases_len) : (case_i += 1) {5696 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
5772 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);5697 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]);
5774 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];5700 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
5775 extra_index = case.end + case.data.items_len + case_body.len;5701 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
5779 for (items) |item| {5705 for (items) |item| {
5780 const llvm_item = try self.resolveInst(item);5706 const llvm_item = (try self.resolveInst(item)).toConst().?;
5781 const llvm_int_item = if (llvm_item.typeOf().getTypeKind() == .Pointer)5707 const llvm_int_item = if (llvm_item.typeOf(&o.builder).isPointer(&o.builder))
5782 llvm_item.constPtrToInt(llvm_usize)5708 try o.builder.castConst(.ptrtoint, llvm_item, llvm_usize)
5783 else5709 else
5784 llvm_item;5710 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);
5786 }5712 }
57875713
5788 self.wip.cursor = .{ .block = case_block };5714 self.wip.cursor = .{ .block = case_block };
5789 self.builder.positionBuilderAtEnd(case_block.toLlvm(&self.wip));
5790 try self.genBody(case_body);5715 try self.genBody(case_body);
5791 }5716 }
57925717
5793 self.wip.cursor = .{ .block = else_block };5718 self.wip.cursor = .{ .block = else_block };
5794 self.builder.positionBuilderAtEnd(else_block.toLlvm(&self.wip));
5795 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];5719 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
5796 if (else_body.len != 0) {5720 if (else_body.len != 0) {
5797 try self.genBody(else_body);5721 try self.genBody(else_body);
5798 } else {5722 } else {
5799 _ = self.builder.buildUnreachable();5723 _ = try self.wip.@"unreachable"();
5800 }5724 }
58015725
5802 // No need to reset the insert cursor since this instruction is noreturn.5726 // No need to reset the insert cursor since this instruction is noreturn.
5803 return null;5727 return .none;
5804 }5728 }
58055729
5806 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5730 fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5807 const o = self.dg.object;5731 const o = self.dg.object;
5808 const mod = o.module;5732 const mod = o.module;
5809 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5733 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5810 const loop = self.air.extraData(Air.Block, ty_pl.payload);5734 const loop = self.air.extraData(Air.Block, ty_pl.payload);
5811 const body = self.air.extra[loop.end..][0..loop.data.body_len];5735 const body = self.air.extra[loop.end..][0..loop.data.body_len];
5812 const loop_block = try self.wip.block("Loop");5736 const loop_block = try self.wip.block(2, "Loop");
5813 _ = self.builder.buildBr(loop_block.toLlvm(&self.wip));5737 _ = try self.wip.br(loop_block);
58145738
5815 self.wip.cursor = .{ .block = loop_block };5739 self.wip.cursor = .{ .block = loop_block };
5816 self.builder.positionBuilderAtEnd(loop_block.toLlvm(&self.wip));
5817 try self.genBody(body);5740 try self.genBody(body);
58185741
5819 // TODO instead of this logic, change AIR to have the property that5742 // TODO instead of this logic, change AIR to have the property that
...@@ -5823,35 +5746,30 @@ pub const FuncGen = struct {...@@ -5823,35 +5746,30 @@ pub const FuncGen = struct {
5823 // be while(true) instead of for(body), which will eliminate 1 branch on5746 // be while(true) instead of for(body), which will eliminate 1 branch on
5824 // a hot path.5747 // a hot path.
5825 if (body.len == 0 or !self.typeOfIndex(body[body.len - 1]).isNoReturn(mod)) {5748 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);
5827 }5750 }
5828 return null;5751 return .none;
5829 }5752 }
58305753
5831 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5754 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5832 const o = self.dg.object;5755 const o = self.dg.object;
5833 const mod = o.module;5756 const mod = o.module;
5834 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5757 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5835 const operand_ty = self.typeOf(ty_op.operand);5758 const operand_ty = self.typeOf(ty_op.operand);
5836 const array_ty = operand_ty.childType(mod);5759 const array_ty = operand_ty.childType(mod);
5837 const llvm_usize = try o.lowerType(Type.usize);5760 const llvm_usize = try o.lowerType(Type.usize);
5838 const len = (try o.builder.intConst(llvm_usize, array_ty.arrayLen(mod))).toLlvm(&o.builder);5761 const len = try o.builder.intValue(llvm_usize, array_ty.arrayLen(mod));
5839 const slice_llvm_ty = (try o.lowerType(self.typeOfIndex(inst))).toLlvm(&o.builder);5762 const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
5840 const operand = try self.resolveInst(ty_op.operand);5763 const operand = try self.resolveInst(ty_op.operand);
5841 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) {5764 if (!array_ty.hasRuntimeBitsIgnoreComptime(mod))
5842 const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), operand, 0, "");5765 return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, "");
5843 return self.builder.buildInsertValue(partial, len, 1, "");5766 const ptr = try self.wip.gep(.inbounds, try o.lowerType(array_ty), operand, &.{
5844 }5767 try o.builder.intValue(llvm_usize, 0), try o.builder.intValue(llvm_usize, 0),
5845 const indices: [2]*llvm.Value = .{5768 }, "");
5846 (try o.builder.intConst(llvm_usize, 0)).toLlvm(&o.builder),5769 return self.wip.buildAggregate(slice_llvm_ty, &.{ ptr, len }, "");
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, "");
5852 }5770 }
58535771
5854 fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5772 fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
5855 const o = self.dg.object;5773 const o = self.dg.object;
5856 const mod = o.module;5774 const mod = o.module;
5857 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5775 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -5865,23 +5783,21 @@ pub const FuncGen = struct {...@@ -5865,23 +5783,21 @@ pub const FuncGen = struct {
5865 const dest_llvm_ty = try o.lowerType(dest_ty);5783 const dest_llvm_ty = try o.lowerType(dest_ty);
5866 const target = mod.getTarget();5784 const target = mod.getTarget();
58675785
5868 if (intrinsicsAllowed(dest_scalar_ty, target)) {5786 if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv(
5869 if (operand_scalar_ty.isSignedInt(mod)) {5787 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5870 return self.builder.buildSIToFP(operand, dest_llvm_ty.toLlvm(&o.builder), "");5788 operand,
5871 } else {5789 dest_llvm_ty,
5872 return self.builder.buildUIToFP(operand, dest_llvm_ty.toLlvm(&o.builder), "");5790 "",
5873 }5791 );
5874 }
58755792
5876 const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(mod)));5793 const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(mod)));
5877 const rt_int_ty = try o.builder.intType(rt_int_bits);5794 const rt_int_ty = try o.builder.intType(rt_int_bits);
5878 var extended = e: {5795 var extended = try self.wip.conv(
5879 if (operand_scalar_ty.isSignedInt(mod)) {5796 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5880 break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty.toLlvm(&o.builder), "");5797 operand,
5881 } else {5798 rt_int_ty,
5882 break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty.toLlvm(&o.builder), "");5799 "",
5883 }5800 );
5884 };
5885 const dest_bits = dest_scalar_ty.floatBits(target);5801 const dest_bits = dest_scalar_ty.floatBits(target);
5886 const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);5802 const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);
5887 const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);5803 const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);
...@@ -5897,16 +5813,23 @@ pub const FuncGen = struct {...@@ -5897,16 +5813,23 @@ pub const FuncGen = struct {
5897 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard5813 // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
5898 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.5814 // i128 calling convention to adhere to the ABI that LLVM expects compiler-rt to have.
5899 param_type = try o.builder.vectorType(.normal, 2, .i64);5815 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, "");
5901 }5817 }
59025818
5903 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);5819 const libc_fn = try self.getLibcFunction(fn_name, &.{param_type}, dest_llvm_ty);
5904 const params = [1]*llvm.Value{extended};5820 const params = [1]*llvm.Value{extended.toLlvm(&self.wip)};
59055821 return (try self.wip.unimplemented(dest_llvm_ty, "")).finish(self.builder.buildCall(
5906 return self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");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);
5907 }5830 }
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 {
5910 self.builder.setFastMath(want_fast_math);5833 self.builder.setFastMath(want_fast_math);
59115834
5912 const o = self.dg.object;5835 const o = self.dg.object;
...@@ -5924,11 +5847,12 @@ pub const FuncGen = struct {...@@ -5924,11 +5847,12 @@ pub const FuncGen = struct {
59245847
5925 if (intrinsicsAllowed(operand_scalar_ty, target)) {5848 if (intrinsicsAllowed(operand_scalar_ty, target)) {
5926 // TODO set fast math flag5849 // TODO set fast math flag
5927 if (dest_scalar_ty.isSignedInt(mod)) {5850 return self.wip.conv(
5928 return self.builder.buildFPToSI(operand, dest_llvm_ty.toLlvm(&o.builder), "");5851 if (dest_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
5929 } else {5852 operand,
5930 return self.builder.buildFPToUI(operand, dest_llvm_ty.toLlvm(&o.builder), "");5853 dest_llvm_ty,
5931 }5854 "",
5855 );
5932 }5856 }
59335857
5934 const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(mod)));5858 const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(mod)));
...@@ -5953,66 +5877,69 @@ pub const FuncGen = struct {...@@ -5953,66 +5877,69 @@ pub const FuncGen = struct {
59535877
5954 const operand_llvm_ty = try o.lowerType(operand_ty);5878 const operand_llvm_ty = try o.lowerType(operand_ty);
5955 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);5879 const libc_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, libc_ret_ty);
5956 const params = [1]*llvm.Value{operand};5880 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
59575881 var result = (try self.wip.unimplemented(libc_ret_ty, "")).finish(self.builder.buildCall(
5958 var result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");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), "");5891 if (libc_ret_ty != ret_ty) result = try self.wip.cast(.bitcast, result, ret_ty, "");
5961 if (ret_ty != dest_llvm_ty) result = self.builder.buildTrunc(result, dest_llvm_ty.toLlvm(&o.builder), "");5892 if (ret_ty != dest_llvm_ty) result = try self.wip.cast(.trunc, result, dest_llvm_ty, "");
5962 return result;5893 return result;
5963 }5894 }
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 {
5966 const o = fg.dg.object;5897 const o = fg.dg.object;
5967 const mod = o.module;5898 const mod = o.module;
5968 if (ty.isSlice(mod)) {5899 return if (ty.isSlice(mod)) fg.wip.extractValue(ptr, &.{0}, "") else ptr;
5969 return fg.builder.buildExtractValue(ptr, 0, "");
5970 } else {
5971 return ptr;
5972 }
5973 }5900 }
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 {
5976 const o = fg.dg.object;5903 const o = fg.dg.object;
5977 const mod = o.module;5904 const mod = o.module;
5978 const llvm_usize = try o.lowerType(Type.usize);5905 const llvm_usize = try o.lowerType(Type.usize);
5979 switch (ty.ptrSize(mod)) {5906 switch (ty.ptrSize(mod)) {
5980 .Slice => {5907 .Slice => {
5981 const len = fg.builder.buildExtractValue(ptr, 1, "");5908 const len = try fg.wip.extractValue(ptr, &.{1}, "");
5982 const elem_ty = ty.childType(mod);5909 const elem_ty = ty.childType(mod);
5983 const abi_size = elem_ty.abiSize(mod);5910 const abi_size = elem_ty.abiSize(mod);
5984 if (abi_size == 1) return len;5911 if (abi_size == 1) return len;
5985 const abi_size_llvm_val = try o.builder.intConst(llvm_usize, abi_size);5912 const abi_size_llvm_val = try o.builder.intValue(llvm_usize, abi_size);
5986 return fg.builder.buildMul(len, abi_size_llvm_val.toLlvm(&o.builder), "");5913 return fg.wip.bin(.@"mul nuw", len, abi_size_llvm_val, "");
5987 },5914 },
5988 .One => {5915 .One => {
5989 const array_ty = ty.childType(mod);5916 const array_ty = ty.childType(mod);
5990 const elem_ty = array_ty.childType(mod);5917 const elem_ty = array_ty.childType(mod);
5991 const abi_size = elem_ty.abiSize(mod);5918 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);
5993 },5920 },
5994 .Many, .C => unreachable,5921 .Many, .C => unreachable,
5995 }5922 }
5996 }5923 }
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 {
5999 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5926 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6000 const operand = try self.resolveInst(ty_op.operand);5927 const operand = try self.resolveInst(ty_op.operand);
6001 return self.builder.buildExtractValue(operand, index, "");5928 return self.wip.extractValue(operand, &.{index}, "");
6002 }5929 }
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 {
6005 const o = self.dg.object;5932 const o = self.dg.object;
6006 const mod = o.module;5933 const mod = o.module;
6007 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5934 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6008 const slice_ptr = try self.resolveInst(ty_op.operand);5935 const slice_ptr = try self.resolveInst(ty_op.operand);
6009 const slice_ptr_ty = self.typeOf(ty_op.operand);5936 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, "");
6013 }5940 }
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 {
6016 const o = self.dg.object;5943 const o = self.dg.object;
6017 const mod = o.module;5944 const mod = o.module;
6018 const inst = body_tail[0];5945 const inst = body_tail[0];
...@@ -6021,21 +5948,21 @@ pub const FuncGen = struct {...@@ -6021,21 +5948,21 @@ pub const FuncGen = struct {
6021 const slice = try self.resolveInst(bin_op.lhs);5948 const slice = try self.resolveInst(bin_op.lhs);
6022 const index = try self.resolveInst(bin_op.rhs);5949 const index = try self.resolveInst(bin_op.rhs);
6023 const elem_ty = slice_ty.childType(mod);5950 const elem_ty = slice_ty.childType(mod);
6024 const llvm_elem_ty = (try o.lowerPtrElemTy(elem_ty)).toLlvm(&o.builder);5951 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);
6025 const base_ptr = self.builder.buildExtractValue(slice, 0, "");5952 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
6026 const indices: [1]*llvm.Value = .{index};5953 const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
6027 const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
6028 if (isByRef(elem_ty, mod)) {5954 if (isByRef(elem_ty, mod)) {
6029 if (self.canElideLoad(body_tail))5955 if (self.canElideLoad(body_tail))
6030 return ptr;5956 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);
6033 }5960 }
60345961
6035 return self.load(ptr, slice_ty);5962 return self.load(ptr, slice_ty);
6036 }5963 }
60375964
6038 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5965 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6039 const o = self.dg.object;5966 const o = self.dg.object;
6040 const mod = o.module;5967 const mod = o.module;
6041 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5968 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -6044,13 +5971,12 @@ pub const FuncGen = struct {...@@ -6044,13 +5971,12 @@ pub const FuncGen = struct {
60445971
6045 const slice = try self.resolveInst(bin_op.lhs);5972 const slice = try self.resolveInst(bin_op.lhs);
6046 const index = try self.resolveInst(bin_op.rhs);5973 const index = try self.resolveInst(bin_op.rhs);
6047 const llvm_elem_ty = (try o.lowerPtrElemTy(slice_ty.childType(mod))).toLlvm(&o.builder);5974 const llvm_elem_ty = try o.lowerPtrElemTy(slice_ty.childType(mod));
6048 const base_ptr = self.builder.buildExtractValue(slice, 0, "");5975 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
6049 const indices: [1]*llvm.Value = .{index};5976 return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
6050 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
6051 }5977 }
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 {
6054 const o = self.dg.object;5980 const o = self.dg.object;
6055 const mod = o.module;5981 const mod = o.module;
6056 const inst = body_tail[0];5982 const inst = body_tail[0];
...@@ -6059,21 +5985,20 @@ pub const FuncGen = struct {...@@ -6059,21 +5985,20 @@ pub const FuncGen = struct {
6059 const array_ty = self.typeOf(bin_op.lhs);5985 const array_ty = self.typeOf(bin_op.lhs);
6060 const array_llvm_val = try self.resolveInst(bin_op.lhs);5986 const array_llvm_val = try self.resolveInst(bin_op.lhs);
6061 const rhs = try self.resolveInst(bin_op.rhs);5987 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);
6063 const elem_ty = array_ty.childType(mod);5989 const elem_ty = array_ty.childType(mod);
6064 if (isByRef(array_ty, mod)) {5990 if (isByRef(array_ty, mod)) {
6065 const indices: [2]*llvm.Value = .{5991 const indices: [2]Builder.Value = .{
6066 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),5992 try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs,
6067 rhs,
6068 };5993 };
6069 if (isByRef(elem_ty, mod)) {5994 if (isByRef(elem_ty, mod)) {
6070 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");5995 const elem_ptr =
6071 if (canElideLoad(self, body_tail))5996 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
6072 return elem_ptr;5997 if (canElideLoad(self, body_tail)) return elem_ptr;
60735998 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
6074 return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(mod), false);5999 return self.loadByRef(elem_ptr, elem_ty, elem_alignment, false);
6075 } else {6000 } else {
6076 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);6001 const elem_llvm_ty = try o.lowerType(elem_ty);
6077 if (Air.refToIndex(bin_op.lhs)) |lhs_index| {6002 if (Air.refToIndex(bin_op.lhs)) |lhs_index| {
6078 if (self.air.instructions.items(.tag)[lhs_index] == .load) {6003 if (self.air.instructions.items(.tag)[lhs_index] == .load) {
6079 const load_data = self.air.instructions.items(.data)[lhs_index];6004 const load_data = self.air.instructions.items(.data)[lhs_index];
...@@ -6081,66 +6006,70 @@ pub const FuncGen = struct {...@@ -6081,66 +6006,70 @@ pub const FuncGen = struct {
6081 if (Air.refToIndex(load_ptr)) |load_ptr_index| {6006 if (Air.refToIndex(load_ptr)) |load_ptr_index| {
6082 const load_ptr_tag = self.air.instructions.items(.tag)[load_ptr_index];6007 const load_ptr_tag = self.air.instructions.items(.tag)[load_ptr_index];
6083 switch (load_ptr_tag) {6008 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 => {
6085 const load_ptr_inst = try self.resolveInst(load_ptr);6015 const load_ptr_inst = try self.resolveInst(load_ptr);
6086 const gep = self.builder.buildInBoundsGEP(array_llvm_ty, load_ptr_inst, &indices, indices.len, "");6016 const gep = try self.wip.gep(
6087 return self.builder.buildLoad(elem_llvm_ty, 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, "");
6088 },6024 },
6089 else => {},6025 else => {},
6090 }6026 }
6091 }6027 }
6092 }6028 }
6093 }6029 }
6094 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");6030 const elem_ptr =
6095 return self.builder.buildLoad(elem_llvm_ty, 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, "");
6096 }6033 }
6097 }6034 }
60986035
6099 // This branch can be reached for vectors, which are always by-value.6036 // 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, "");
6101 }6038 }
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 {
6104 const o = self.dg.object;6041 const o = self.dg.object;
6105 const mod = o.module;6042 const mod = o.module;
6106 const inst = body_tail[0];6043 const inst = body_tail[0];
6107 const bin_op = self.air.instructions.items(.data)[inst].bin_op;6044 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
6108 const ptr_ty = self.typeOf(bin_op.lhs);6045 const ptr_ty = self.typeOf(bin_op.lhs);
6109 const elem_ty = ptr_ty.childType(mod);6046 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);
6111 const base_ptr = try self.resolveInst(bin_op.lhs);6048 const base_ptr = try self.resolveInst(bin_op.lhs);
6112 const rhs = try self.resolveInst(bin_op.rhs);6049 const rhs = try self.resolveInst(bin_op.rhs);
6113 // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch6050 // 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))
6115 // If this is a single-item pointer to an array, we need another index in the GEP.6052 // If this is a single-item pointer to an array, we need another index in the GEP.
6116 const indices: [2]*llvm.Value = .{6053 &.{ try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs }
6117 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),6054 else
6118 rhs,6055 &.{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 };
6125 if (isByRef(elem_ty, mod)) {6056 if (isByRef(elem_ty, mod)) {
6126 if (self.canElideLoad(body_tail))6057 if (self.canElideLoad(body_tail)) return ptr;
6127 return ptr;6058 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
61286059 return self.loadByRef(ptr, elem_ty, elem_alignment, false);
6129 return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false);
6130 }6060 }
61316061
6132 return self.load(ptr, ptr_ty);6062 return self.load(ptr, ptr_ty);
6133 }6063 }
61346064
6135 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6065 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6136 const o = self.dg.object;6066 const o = self.dg.object;
6137 const mod = o.module;6067 const mod = o.module;
6138 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;6068 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6139 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;6069 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
6140 const ptr_ty = self.typeOf(bin_op.lhs);6070 const ptr_ty = self.typeOf(bin_op.lhs);
6141 const elem_ty = ptr_ty.childType(mod);6071 const elem_ty = ptr_ty.childType(mod);
6142 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod))6072 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return (try o.lowerPtrToVoid(ptr_ty)).toValue();
6143 return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder);
61446073
6145 const base_ptr = try self.resolveInst(bin_op.lhs);6074 const base_ptr = try self.resolveInst(bin_op.lhs);
6146 const rhs = try self.resolveInst(bin_op.rhs);6075 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -6148,21 +6077,15 @@ pub const FuncGen = struct {...@@ -6148,21 +6077,15 @@ pub const FuncGen = struct {
6148 const elem_ptr = self.air.getRefType(ty_pl.ty);6077 const elem_ptr = self.air.getRefType(ty_pl.ty);
6149 if (elem_ptr.ptrInfo(mod).flags.vector_index != .none) return base_ptr;6078 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);6080 const llvm_elem_ty = try o.lowerPtrElemTy(elem_ty);
6152 if (ptr_ty.isSinglePointer(mod)) {6081 return try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, if (ptr_ty.isSinglePointer(mod))
6153 // If this is a single-item pointer to an array, we need another index in the GEP.6082 // If this is a single-item pointer to an array, we need another index in the GEP.
6154 const indices: [2]*llvm.Value = .{6083 &.{ try o.builder.intValue(try o.lowerType(Type.usize), 0), rhs }
6155 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),6084 else
6156 rhs,6085 &.{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 }
6163 }6086 }
61646087
6165 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6088 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6166 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;6089 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6167 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;6090 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
6168 const struct_ptr = try self.resolveInst(struct_field.struct_operand);6091 const struct_ptr = try self.resolveInst(struct_field.struct_operand);
...@@ -6174,14 +6097,14 @@ pub const FuncGen = struct {...@@ -6174,14 +6097,14 @@ pub const FuncGen = struct {
6174 self: *FuncGen,6097 self: *FuncGen,
6175 inst: Air.Inst.Index,6098 inst: Air.Inst.Index,
6176 field_index: u32,6099 field_index: u32,
6177 ) !?*llvm.Value {6100 ) !Builder.Value {
6178 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6101 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6179 const struct_ptr = try self.resolveInst(ty_op.operand);6102 const struct_ptr = try self.resolveInst(ty_op.operand);
6180 const struct_ptr_ty = self.typeOf(ty_op.operand);6103 const struct_ptr_ty = self.typeOf(ty_op.operand);
6181 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);6104 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);
6182 }6105 }
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 {
6185 const o = self.dg.object;6108 const o = self.dg.object;
6186 const mod = o.module;6109 const mod = o.module;
6187 const inst = body_tail[0];6110 const inst = body_tail[0];
...@@ -6191,9 +6114,7 @@ pub const FuncGen = struct {...@@ -6191,9 +6114,7 @@ pub const FuncGen = struct {
6191 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);6114 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
6192 const field_index = struct_field.field_index;6115 const field_index = struct_field.field_index;
6193 const field_ty = struct_ty.structFieldType(field_index, mod);6116 const field_ty = struct_ty.structFieldType(field_index, mod);
6194 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {6117 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
6195 return null;
6196 }
61976118
6198 if (!isByRef(struct_ty, mod)) {6119 if (!isByRef(struct_ty, mod)) {
6199 assert(!isByRef(field_ty, mod));6120 assert(!isByRef(field_ty, mod));
...@@ -6203,39 +6124,44 @@ pub const FuncGen = struct {...@@ -6203,39 +6124,44 @@ pub const FuncGen = struct {
6203 const struct_obj = mod.typeToStruct(struct_ty).?;6124 const struct_obj = mod.typeToStruct(struct_ty).?;
6204 const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index);6125 const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index);
6205 const containing_int = struct_llvm_val;6126 const containing_int = struct_llvm_val;
6206 const shift_amt = containing_int.typeOf().constInt(bit_offset, .False);6127 const shift_amt =
6207 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");6128 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
6208 const elem_llvm_ty = (try o.lowerType(field_ty)).toLlvm(&o.builder);6129 const shifted_value = try self.wip.bin(.lshr, containing_int, shift_amt, "");
6130 const elem_llvm_ty = try o.lowerType(field_ty);
6209 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {6131 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);6132 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6211 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");6133 const truncated_int =
6212 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");6134 try self.wip.cast(.trunc, shifted_value, same_size_int, "");
6135 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
6213 } else if (field_ty.isPtrAtRuntime(mod)) {6136 } else if (field_ty.isPtrAtRuntime(mod)) {
6214 const same_size_int = (try o.builder.intType(@intCast(field_ty.bitSize(mod)))).toLlvm(&o.builder);6137 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6215 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");6138 const truncated_int =
6216 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");6139 try self.wip.cast(.trunc, shifted_value, same_size_int, "");
6140 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
6217 }6141 }
6218 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");6142 return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
6219 },6143 },
6220 else => {6144 else => {
6221 const llvm_field_index = llvmField(struct_ty, field_index, mod).?.index;6145 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}, "");
6223 },6147 },
6224 },6148 },
6225 .Union => {6149 .Union => {
6226 assert(struct_ty.containerLayout(mod) == .Packed);6150 assert(struct_ty.containerLayout(mod) == .Packed);
6227 const containing_int = struct_llvm_val;6151 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);
6229 if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) {6153 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);6154 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6231 const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, "");6155 const truncated_int =
6232 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");6156 try self.wip.cast(.trunc, containing_int, same_size_int, "");
6157 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
6233 } else if (field_ty.isPtrAtRuntime(mod)) {6158 } else if (field_ty.isPtrAtRuntime(mod)) {
6234 const same_size_int = (try o.builder.intType(@intCast(field_ty.bitSize(mod)))).toLlvm(&o.builder);6159 const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(mod)));
6235 const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, "");6160 const truncated_int =
6236 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");6161 try self.wip.cast(.trunc, containing_int, same_size_int, "");
6162 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
6237 }6163 }
6238 return self.builder.buildTrunc(containing_int, elem_llvm_ty, "");6164 return self.wip.cast(.trunc, containing_int, elem_llvm_ty, "");
6239 },6165 },
6240 else => unreachable,6166 else => unreachable,
6241 }6167 }
...@@ -6245,8 +6171,9 @@ pub const FuncGen = struct {...@@ -6245,8 +6171,9 @@ pub const FuncGen = struct {
6245 .Struct => {6171 .Struct => {
6246 assert(struct_ty.containerLayout(mod) != .Packed);6172 assert(struct_ty.containerLayout(mod) != .Packed);
6247 const llvm_field = llvmField(struct_ty, field_index, mod).?;6173 const llvm_field = llvmField(struct_ty, field_index, mod).?;
6248 const struct_llvm_ty = (try o.lowerType(struct_ty)).toLlvm(&o.builder);6174 const struct_llvm_ty = try o.lowerType(struct_ty);
6249 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field.index, "");6175 const field_ptr =
6176 try self.wip.gepStruct(struct_llvm_ty, struct_llvm_val, llvm_field.index, "");
6250 const field_ptr_ty = try mod.ptrType(.{6177 const field_ptr_ty = try mod.ptrType(.{
6251 .child = llvm_field.ty.toIntern(),6178 .child = llvm_field.ty.toIntern(),
6252 .flags = .{6179 .flags = .{
...@@ -6258,31 +6185,32 @@ pub const FuncGen = struct {...@@ -6258,31 +6185,32 @@ pub const FuncGen = struct {
6258 return field_ptr;6185 return field_ptr;
62596186
6260 assert(llvm_field.alignment != 0);6187 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);
6262 } else {6190 } else {
6263 return self.load(field_ptr, field_ptr_ty);6191 return self.load(field_ptr, field_ptr_ty);
6264 }6192 }
6265 },6193 },
6266 .Union => {6194 .Union => {
6267 const union_llvm_ty = (try o.lowerType(struct_ty)).toLlvm(&o.builder);6195 const union_llvm_ty = try o.lowerType(struct_ty);
6268 const layout = struct_ty.unionGetLayout(mod);6196 const layout = struct_ty.unionGetLayout(mod);
6269 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);6197 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, "");6198 const field_ptr =
6271 const llvm_field_ty = (try o.lowerType(field_ty)).toLlvm(&o.builder);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);
6272 if (isByRef(field_ty, mod)) {6202 if (isByRef(field_ty, mod)) {
6273 if (canElideLoad(self, body_tail))6203 if (canElideLoad(self, body_tail)) return field_ptr;
6274 return field_ptr;6204 return self.loadByRef(field_ptr, field_ty, payload_alignment, false);
6275
6276 return self.loadByRef(field_ptr, field_ty, layout.payload_align, false);
6277 } else {6205 } else {
6278 return self.builder.buildLoad(llvm_field_ty, field_ptr, "");6206 return self.wip.load(.normal, llvm_field_ty, field_ptr, payload_alignment, "");
6279 }6207 }
6280 },6208 },
6281 else => unreachable,6209 else => unreachable,
6282 }6210 }
6283 }6211 }
62846212
6285 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6213 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6286 const o = self.dg.object;6214 const o = self.dg.object;
6287 const mod = o.module;6215 const mod = o.module;
6288 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;6216 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -6292,33 +6220,36 @@ pub const FuncGen = struct {...@@ -6292,33 +6220,36 @@ pub const FuncGen = struct {
62926220
6293 const parent_ty = self.air.getRefType(ty_pl.ty).childType(mod);6221 const parent_ty = self.air.getRefType(ty_pl.ty).childType(mod);
6294 const field_offset = parent_ty.structFieldOffset(extra.field_index, mod);6222 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);6225 const res_ty = try o.lowerType(self.air.getRefType(ty_pl.ty));
6297 if (field_offset == 0) {
6298 return field_ptr;
6299 }
6300 const llvm_usize = try o.lowerType(Type.usize);6226 const llvm_usize = try o.lowerType(Type.usize);
63016227
6302 const field_ptr_int = self.builder.buildPtrToInt(field_ptr, llvm_usize.toLlvm(&o.builder), "");6228 const field_ptr_int = try self.wip.cast(.ptrtoint, field_ptr, llvm_usize, "");
6303 const base_ptr_int = self.builder.buildNUWSub(field_ptr_int, (try o.builder.intConst(llvm_usize, field_offset)).toLlvm(&o.builder), "");6229 const base_ptr_int = try self.wip.bin(
6304 return self.builder.buildIntToPtr(base_ptr_int, res_ty, "");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, "");
6305 }6236 }
63066237
6307 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6238 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6308 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6239 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6309 const operand = try self.resolveInst(ty_op.operand);6240 const operand = try self.resolveInst(ty_op.operand);
63106241
6311 return self.builder.buildNot(operand, "");6242 return self.wip.not(operand, "");
6312 }6243 }
63136244
6314 fn airUnreach(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {6245 fn airUnreach(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6315 _ = inst;6246 _ = inst;
6316 _ = self.builder.buildUnreachable();6247 _ = try self.wip.@"unreachable"();
6317 return null;6248 return .none;
6318 }6249 }
63196250
6320 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*llvm.Value {6251 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6321 const di_scope = self.di_scope orelse return null;6252 const di_scope = self.di_scope orelse return .none;
6322 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;6253 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
6323 self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1);6254 self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1);
6324 self.prev_dbg_column = @intCast(dbg_stmt.column + 1);6255 self.prev_dbg_column = @intCast(dbg_stmt.column + 1);
...@@ -6327,12 +6258,12 @@ pub const FuncGen = struct {...@@ -6327,12 +6258,12 @@ pub const FuncGen = struct {
6327 else6258 else
6328 null;6259 null;
6329 self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);6260 self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);
6330 return null;6261 return .none;
6331 }6262 }
63326263
6333 fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6264 fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6334 const o = self.dg.object;6265 const o = self.dg.object;
6335 const dib = o.di_builder orelse return null;6266 const dib = o.di_builder orelse return .none;
6336 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;6267 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
63376268
6338 const mod = o.module;6269 const mod = o.module;
...@@ -6385,12 +6316,12 @@ pub const FuncGen = struct {...@@ -6385,12 +6316,12 @@ pub const FuncGen = struct {
6385 const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);6316 const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);
6386 self.di_scope = lexical_block.toScope();6317 self.di_scope = lexical_block.toScope();
6387 self.base_line = decl.src_line;6318 self.base_line = decl.src_line;
6388 return null;6319 return .none;
6389 }6320 }
63906321
6391 fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6322 fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6392 const o = self.dg.object;6323 const o = self.dg.object;
6393 if (o.di_builder == null) return null;6324 if (o.di_builder == null) return .none;
6394 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;6325 const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
63956326
6396 const mod = o.module;6327 const mod = o.module;
...@@ -6400,30 +6331,30 @@ pub const FuncGen = struct {...@@ -6400,30 +6331,30 @@ pub const FuncGen = struct {
6400 const old = self.dbg_inlined.pop();6331 const old = self.dbg_inlined.pop();
6401 self.di_scope = old.scope;6332 self.di_scope = old.scope;
6402 self.base_line = old.base_line;6333 self.base_line = old.base_line;
6403 return null;6334 return .none;
6404 }6335 }
64056336
6406 fn airDbgBlockBegin(self: *FuncGen) !?*llvm.Value {6337 fn airDbgBlockBegin(self: *FuncGen) !Builder.Value {
6407 const o = self.dg.object;6338 const o = self.dg.object;
6408 const dib = o.di_builder orelse return null;6339 const dib = o.di_builder orelse return .none;
6409 const old_scope = self.di_scope.?;6340 const old_scope = self.di_scope.?;
6410 try self.dbg_block_stack.append(self.gpa, old_scope);6341 try self.dbg_block_stack.append(self.gpa, old_scope);
6411 const lexical_block = dib.createLexicalBlock(old_scope, self.di_file.?, self.prev_dbg_line, self.prev_dbg_column);6342 const lexical_block = dib.createLexicalBlock(old_scope, self.di_file.?, self.prev_dbg_line, self.prev_dbg_column);
6412 self.di_scope = lexical_block.toScope();6343 self.di_scope = lexical_block.toScope();
6413 return null;6344 return .none;
6414 }6345 }
64156346
6416 fn airDbgBlockEnd(self: *FuncGen) !?*llvm.Value {6347 fn airDbgBlockEnd(self: *FuncGen) !Builder.Value {
6417 const o = self.dg.object;6348 const o = self.dg.object;
6418 if (o.di_builder == null) return null;6349 if (o.di_builder == null) return .none;
6419 self.di_scope = self.dbg_block_stack.pop();6350 self.di_scope = self.dbg_block_stack.pop();
6420 return null;6351 return .none;
6421 }6352 }
64226353
6423 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6354 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6424 const o = self.dg.object;6355 const o = self.dg.object;
6425 const mod = o.module;6356 const mod = o.module;
6426 const dib = o.di_builder orelse return null;6357 const dib = o.di_builder orelse return .none;
6427 const pl_op = self.air.instructions.items(.data)[inst].pl_op;6358 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
6428 const operand = try self.resolveInst(pl_op.operand);6359 const operand = try self.resolveInst(pl_op.operand);
6429 const name = self.air.nullTerminatedString(pl_op.payload);6360 const name = self.air.nullTerminatedString(pl_op.payload);
...@@ -6443,22 +6374,20 @@ pub const FuncGen = struct {...@@ -6443,22 +6374,20 @@ pub const FuncGen = struct {
6443 else6374 else
6444 null;6375 null;
6445 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);6376 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();6377 const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
6447 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);6378 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
6448 return null;6379 return .none;
6449 }6380 }
64506381
6451 fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6382 fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6452 const o = self.dg.object;6383 const o = self.dg.object;
6453 const dib = o.di_builder orelse return null;6384 const dib = o.di_builder orelse return .none;
6454 const pl_op = self.air.instructions.items(.data)[inst].pl_op;6385 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
6455 const operand = try self.resolveInst(pl_op.operand);6386 const operand = try self.resolveInst(pl_op.operand);
6456 const operand_ty = self.typeOf(pl_op.operand);6387 const operand_ty = self.typeOf(pl_op.operand);
6457 const name = self.air.nullTerminatedString(pl_op.payload);6388 const name = self.air.nullTerminatedString(pl_op.payload);
64586389
6459 if (needDbgVarWorkaround(o)) {6390 if (needDbgVarWorkaround(o)) return .none;
6460 return null;
6461 }
64626391
6463 const di_local_var = dib.createAutoVariable(6392 const di_local_var = dib.createAutoVariable(
6464 self.di_scope.?,6393 self.di_scope.?,
...@@ -6474,23 +6403,22 @@ pub const FuncGen = struct {...@@ -6474,23 +6403,22 @@ pub const FuncGen = struct {
6474 else6403 else
6475 null;6404 null;
6476 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);6405 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);
6478 const mod = o.module;6407 const mod = o.module;
6479 if (isByRef(operand_ty, mod)) {6408 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);
6481 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {6410 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
6482 const alignment = operand_ty.abiAlignment(mod);6411 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
6483 const alloca = try self.buildAlloca(operand.typeOf(), alignment);6412 const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
6484 const store_inst = self.builder.buildStore(operand, alloca);6413 _ = try self.wip.store(.normal, operand, alloca, alignment);
6485 store_inst.setAlignment(alignment);6414 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
6486 _ = dib.insertDeclareAtEnd(alloca, di_local_var, debug_loc, insert_block);
6487 } else {6415 } 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);
6489 }6417 }
6490 return null;6418 return .none;
6491 }6419 }
64926420
6493 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6421 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6494 // Eventually, the Zig compiler needs to be reworked to have inline6422 // Eventually, the Zig compiler needs to be reworked to have inline
6495 // assembly go through the same parsing code regardless of backend, and6423 // assembly go through the same parsing code regardless of backend, and
6496 // have LLVM-flavored inline assembly be *output* from that assembler.6424 // have LLVM-flavored inline assembly be *output* from that assembler.
...@@ -6523,11 +6451,11 @@ pub const FuncGen = struct {...@@ -6523,11 +6451,11 @@ pub const FuncGen = struct {
6523 const llvm_ret_indirect = try arena.alloc(bool, max_return_count);6451 const llvm_ret_indirect = try arena.alloc(bool, max_return_count);
65246452
6525 const max_param_count = inputs.len + outputs.len;6453 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);
6527 const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);6455 const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);
6528 // This stores whether we need to add an elementtype attribute and6456 // This stores whether we need to add an elementtype attribute and
6529 // if so, the element type itself.6457 // 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);
6531 const mod = o.module;6459 const mod = o.module;
6532 const target = mod.getTarget();6460 const target = mod.getTarget();
65336461
...@@ -6564,9 +6492,9 @@ pub const FuncGen = struct {...@@ -6564,9 +6492,9 @@ pub const FuncGen = struct {
6564 // Pass the result by reference as an indirect output (e.g. "=*m")6492 // Pass the result by reference as an indirect output (e.g. "=*m")
6565 llvm_constraints.appendAssumeCapacity('*');6493 llvm_constraints.appendAssumeCapacity('*');
65666494
6567 llvm_param_values[llvm_param_i] = output_inst;6495 llvm_param_values[llvm_param_i] = output_inst.toLlvm(&self.wip);
6568 llvm_param_types[llvm_param_i] = output_inst.typeOf();6496 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
6569 llvm_param_attrs[llvm_param_i] = elem_llvm_ty.toLlvm(&o.builder);6497 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
6570 llvm_param_i += 1;6498 llvm_param_i += 1;
6571 } else {6499 } else {
6572 // Pass the result directly (e.g. "=r")6500 // Pass the result directly (e.g. "=r")
...@@ -6614,27 +6542,26 @@ pub const FuncGen = struct {...@@ -6614,27 +6542,26 @@ pub const FuncGen = struct {
6614 if (isByRef(arg_ty, mod)) {6542 if (isByRef(arg_ty, mod)) {
6615 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);6543 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
6616 if (constraintAllowsMemory(constraint)) {6544 if (constraintAllowsMemory(constraint)) {
6617 llvm_param_values[llvm_param_i] = arg_llvm_value;6545 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6618 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();6546 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6619 } else {6547 } else {
6620 const alignment = arg_ty.abiAlignment(mod);6548 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6621 const arg_llvm_ty = (try o.lowerType(arg_ty)).toLlvm(&o.builder);6549 const arg_llvm_ty = try o.lowerType(arg_ty);
6622 const load_inst = self.builder.buildLoad(arg_llvm_ty, arg_llvm_value, "");6550 const load_inst =
6623 load_inst.setAlignment(alignment);6551 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
6624 llvm_param_values[llvm_param_i] = load_inst;6552 llvm_param_values[llvm_param_i] = load_inst.toLlvm(&self.wip);
6625 llvm_param_types[llvm_param_i] = arg_llvm_ty;6553 llvm_param_types[llvm_param_i] = arg_llvm_ty;
6626 }6554 }
6627 } else {6555 } else {
6628 if (constraintAllowsRegister(constraint)) {6556 if (constraintAllowsRegister(constraint)) {
6629 llvm_param_values[llvm_param_i] = arg_llvm_value;6557 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
6630 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();6558 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6631 } else {6559 } else {
6632 const alignment = arg_ty.abiAlignment(mod);6560 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6633 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOf(), alignment);6561 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
6634 const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);6562 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
6635 store_inst.setAlignment(alignment);6563 llvm_param_values[llvm_param_i] = arg_ptr.toLlvm(&self.wip);
6636 llvm_param_values[llvm_param_i] = arg_ptr;6564 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
6637 llvm_param_types[llvm_param_i] = arg_ptr.typeOf();
6638 }6565 }
6639 }6566 }
66406567
...@@ -6658,12 +6585,12 @@ pub const FuncGen = struct {...@@ -6658,12 +6585,12 @@ pub const FuncGen = struct {
6658 // In the case of indirect inputs, LLVM requires the callsite to have6585 // In the case of indirect inputs, LLVM requires the callsite to have
6659 // an elementtype(<ty>) attribute.6586 // an elementtype(<ty>) attribute.
6660 if (constraint[0] == '*') {6587 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)
6662 llvm_elem_ty6589 llvm_elem_ty
6663 else6590 else
6664 try o.lowerPtrElemTy(arg_ty.childType(mod))).toLlvm(&o.builder);6591 try o.lowerPtrElemTy(arg_ty.childType(mod));
6665 } else {6592 } else {
6666 llvm_param_attrs[llvm_param_i] = null;6593 llvm_param_attrs[llvm_param_i] = .none;
6667 }6594 }
66686595
6669 llvm_param_i += 1;6596 llvm_param_i += 1;
...@@ -6786,14 +6713,9 @@ pub const FuncGen = struct {...@@ -6786,14 +6713,9 @@ pub const FuncGen = struct {
6786 else => try o.builder.structType(.normal, llvm_ret_types),6713 else => try o.builder.structType(.normal, llvm_ret_types),
6787 };6714 };
67886715
6789 const llvm_fn_ty = llvm.functionType(6716 const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);
6790 ret_llvm_ty.toLlvm(&o.builder),
6791 llvm_param_types.ptr,
6792 @intCast(param_count),
6793 .False,
6794 );
6795 const asm_fn = llvm.getInlineAsm(6717 const asm_fn = llvm.getInlineAsm(
6796 llvm_fn_ty,6718 llvm_fn_ty.toLlvm(&o.builder),
6797 rendered_template.items.ptr,6719 rendered_template.items.ptr,
6798 rendered_template.items.len,6720 rendered_template.items.len,
6799 llvm_constraints.items.ptr,6721 llvm_constraints.items.ptr,
...@@ -6803,18 +6725,18 @@ pub const FuncGen = struct {...@@ -6803,18 +6725,18 @@ pub const FuncGen = struct {
6803 .ATT,6725 .ATT,
6804 .False,6726 .False,
6805 );6727 );
6806 const call = self.builder.buildCall(6728 const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCall(
6807 llvm_fn_ty,6729 llvm_fn_ty.toLlvm(&o.builder),
6808 asm_fn,6730 asm_fn,
6809 llvm_param_values.ptr,6731 llvm_param_values.ptr,
6810 @intCast(param_count),6732 @intCast(param_count),
6811 .C,6733 .C,
6812 .Auto,6734 .Auto,
6813 "",6735 "",
6814 );6736 ), &self.wip);
6815 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {6737 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
6816 if (llvm_elem_ty) |llvm_ty| {6738 if (llvm_elem_ty != .none) {
6817 llvm.setCallElemTypeAttr(call, i, llvm_ty);6739 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
6818 }6740 }
6819 }6741 }
68206742
...@@ -6823,16 +6745,17 @@ pub const FuncGen = struct {...@@ -6823,16 +6745,17 @@ pub const FuncGen = struct {
6823 for (outputs, 0..) |output, i| {6745 for (outputs, 0..) |output, i| {
6824 if (llvm_ret_indirect[i]) continue;6746 if (llvm_ret_indirect[i]) continue;
68256747
6826 const output_value = if (return_count > 1) b: {6748 const output_value = if (return_count > 1)
6827 break :b self.builder.buildExtractValue(call, @intCast(llvm_ret_i), "");6749 try self.wip.extractValue(call, &[_]u32{@intCast(llvm_ret_i)}, "")
6828 } else call;6750 else
6751 call;
68296752
6830 if (output != .none) {6753 if (output != .none) {
6831 const output_ptr = try self.resolveInst(output);6754 const output_ptr = try self.resolveInst(output);
6832 const output_ptr_ty = self.typeOf(output);6755 const output_ptr_ty = self.typeOf(output);
68336756
6834 const store_inst = self.builder.buildStore(output_value, output_ptr);6757 const alignment = Builder.Alignment.fromByteUnits(output_ptr_ty.ptrAlignment(mod));
6835 store_inst.setAlignment(output_ptr_ty.ptrAlignment(mod));6758 _ = try self.wip.store(.normal, output_value, output_ptr, alignment);
6836 } else {6759 } else {
6837 ret_val = output_value;6760 ret_val = output_value;
6838 }6761 }
...@@ -6846,8 +6769,8 @@ pub const FuncGen = struct {...@@ -6846,8 +6769,8 @@ pub const FuncGen = struct {
6846 self: *FuncGen,6769 self: *FuncGen,
6847 inst: Air.Inst.Index,6770 inst: Air.Inst.Index,
6848 operand_is_ptr: bool,6771 operand_is_ptr: bool,
6849 pred: llvm.IntPredicate,6772 cond: Builder.IntegerCondition,
6850 ) !?*llvm.Value {6773 ) !Builder.Value {
6851 const o = self.dg.object;6774 const o = self.dg.object;
6852 const mod = o.module;6775 const mod = o.module;
6853 const un_op = self.air.instructions.items(.data)[inst].un_op;6776 const un_op = self.air.instructions.items(.data)[inst].un_op;
...@@ -6858,45 +6781,40 @@ pub const FuncGen = struct {...@@ -6858,45 +6781,40 @@ pub const FuncGen = struct {
6858 const payload_ty = optional_ty.optionalChild(mod);6781 const payload_ty = optional_ty.optionalChild(mod);
6859 if (optional_ty.optionalReprIsPayload(mod)) {6782 if (optional_ty.optionalReprIsPayload(mod)) {
6860 const loaded = if (operand_is_ptr)6783 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, "")
6862 else6785 else
6863 operand;6786 operand;
6864 if (payload_ty.isSlice(mod)) {6787 if (payload_ty.isSlice(mod)) {
6865 const slice_ptr = self.builder.buildExtractValue(loaded, 0, "");6788 const slice_ptr = try self.wip.extractValue(loaded, &.{0}, "");
6866 const ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(6789 const ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(
6867 payload_ty.ptrAddressSpace(mod),6790 payload_ty.ptrAddressSpace(mod),
6868 mod.getTarget(),6791 mod.getTarget(),
6869 ));6792 ));
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), "");
6871 }6794 }
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), "");
6873 }6796 }
68746797
6875 comptime assert(optional_layout_version == 3);6798 comptime assert(optional_layout_version == 3);
68766799
6877 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {6800 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6878 const loaded = if (operand_is_ptr)6801 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, "")
6880 else6803 else
6881 operand;6804 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), "");
6883 }6806 }
68846807
6885 const is_by_ref = operand_is_ptr or isByRef(optional_ty, mod);6808 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);6809 return self.optCmpNull(cond, optional_llvm_ty, operand, is_by_ref);
6887 if (pred == .EQ) {
6888 return self.builder.buildNot(non_null_bit, "");
6889 } else {
6890 return non_null_bit;
6891 }
6892 }6810 }
68936811
6894 fn airIsErr(6812 fn airIsErr(
6895 self: *FuncGen,6813 self: *FuncGen,
6896 inst: Air.Inst.Index,6814 inst: Air.Inst.Index,
6897 op: llvm.IntPredicate,6815 cond: Builder.IntegerCondition,
6898 operand_is_ptr: bool,6816 operand_is_ptr: bool,
6899 ) !?*llvm.Value {6817 ) !Builder.Value {
6900 const o = self.dg.object;6818 const o = self.dg.object;
6901 const mod = o.module;6819 const mod = o.module;
6902 const un_op = self.air.instructions.items(.data)[inst].un_op;6820 const un_op = self.air.instructions.items(.data)[inst].un_op;
...@@ -6904,39 +6822,37 @@ pub const FuncGen = struct {...@@ -6904,39 +6822,37 @@ pub const FuncGen = struct {
6904 const operand_ty = self.typeOf(un_op);6822 const operand_ty = self.typeOf(un_op);
6905 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;6823 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;
6906 const payload_ty = err_union_ty.errorUnionPayload(mod);6824 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
6909 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {6827 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
6910 const val: Builder.Constant = switch (op) {6828 const val: Builder.Constant = switch (cond) {
6911 .EQ => .true, // 0 == 06829 .eq => .true, // 0 == 0
6912 .NE => .false, // 0 != 06830 .ne => .false, // 0 != 0
6913 else => unreachable,6831 else => unreachable,
6914 };6832 };
6915 return val.toLlvm(&o.builder);6833 return val.toValue();
6916 }6834 }
69176835
6918 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {6836 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6919 const loaded = if (operand_is_ptr)6837 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, "")
6921 else6839 else
6922 operand;6840 operand;
6923 return self.builder.buildICmp(op, loaded, zero, "");6841 return self.wip.icmp(cond, loaded, zero, "");
6924 }6842 }
69256843
6926 const err_field_index = errUnionErrorOffset(payload_ty, mod);6844 const err_field_index = errUnionErrorOffset(payload_ty, mod);
69276845
6928 if (operand_is_ptr or isByRef(err_union_ty, mod)) {6846 const loaded = if (operand_is_ptr or isByRef(err_union_ty, mod)) loaded: {
6929 const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder);6847 const err_union_llvm_ty = try o.lowerType(err_union_ty);
6930 const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, "");6848 const err_field_ptr =
6931 const loaded = self.builder.buildLoad(Builder.Type.err_int.toLlvm(&o.builder), err_field_ptr, "");6849 try self.wip.gepStruct(err_union_llvm_ty, operand, err_field_index, "");
6932 return self.builder.buildICmp(op, loaded, zero, "");6850 break :loaded try self.wip.load(.normal, Builder.Type.err_int, err_field_ptr, .default, "");
6933 }6851 } else try self.wip.extractValue(operand, &.{err_field_index}, "");
69346852 return self.wip.icmp(cond, loaded, zero, "");
6935 const loaded = self.builder.buildExtractValue(operand, err_field_index, "");
6936 return self.builder.buildICmp(op, loaded, zero, "");
6937 }6853 }
69386854
6939 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6855 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6940 const o = self.dg.object;6856 const o = self.dg.object;
6941 const mod = o.module;6857 const mod = o.module;
6942 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6858 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -6952,11 +6868,10 @@ pub const FuncGen = struct {...@@ -6952,11 +6868,10 @@ pub const FuncGen = struct {
6952 // The payload and the optional are the same value.6868 // The payload and the optional are the same value.
6953 return operand;6869 return operand;
6954 }6870 }
6955 const optional_llvm_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);6871 return self.wip.gepStruct(try o.lowerType(optional_ty), operand, 0, "");
6956 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
6957 }6872 }
69586873
6959 fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6874 fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
6960 comptime assert(optional_layout_version == 3);6875 comptime assert(optional_layout_version == 3);
69616876
6962 const o = self.dg.object;6877 const o = self.dg.object;
...@@ -6965,10 +6880,10 @@ pub const FuncGen = struct {...@@ -6965,10 +6880,10 @@ pub const FuncGen = struct {
6965 const operand = try self.resolveInst(ty_op.operand);6880 const operand = try self.resolveInst(ty_op.operand);
6966 const optional_ty = self.typeOf(ty_op.operand).childType(mod);6881 const optional_ty = self.typeOf(ty_op.operand).childType(mod);
6967 const payload_ty = optional_ty.optionalChild(mod);6882 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);
6969 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {6884 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6970 // We have a pointer to a i8. We need to set it to 1 and then return the same pointer.6885 // 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);
6972 return operand;6887 return operand;
6973 }6888 }
6974 if (optional_ty.optionalReprIsPayload(mod)) {6889 if (optional_ty.optionalReprIsPayload(mod)) {
...@@ -6978,19 +6893,18 @@ pub const FuncGen = struct {...@@ -6978,19 +6893,18 @@ pub const FuncGen = struct {
6978 }6893 }
69796894
6980 // First set the non-null bit.6895 // First set the non-null bit.
6981 const optional_llvm_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);6896 const optional_llvm_ty = try o.lowerType(optional_ty);
6982 const non_null_ptr = self.builder.buildStructGEP(optional_llvm_ty, operand, 1, "");6897 const non_null_ptr = try self.wip.gepStruct(optional_llvm_ty, operand, 1, "");
6983 // TODO set alignment on this store6898 // 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
6986 // Then return the payload pointer (only if it's used).6901 // Then return the payload pointer (only if it's used).
6987 if (self.liveness.isUnused(inst))6902 if (self.liveness.isUnused(inst)) return .none;
6988 return null;
69896903
6990 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");6904 return self.wip.gepStruct(optional_llvm_ty, operand, 0, "");
6991 }6905 }
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 {
6994 const o = self.dg.object;6908 const o = self.dg.object;
6995 const mod = o.module;6909 const mod = o.module;
6996 const inst = body_tail[0];6910 const inst = body_tail[0];
...@@ -6998,14 +6912,14 @@ pub const FuncGen = struct {...@@ -6998,14 +6912,14 @@ pub const FuncGen = struct {
6998 const operand = try self.resolveInst(ty_op.operand);6912 const operand = try self.resolveInst(ty_op.operand);
6999 const optional_ty = self.typeOf(ty_op.operand);6913 const optional_ty = self.typeOf(ty_op.operand);
7000 const payload_ty = self.typeOfIndex(inst);6914 const payload_ty = self.typeOfIndex(inst);
7001 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return null;6915 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
70026916
7003 if (optional_ty.optionalReprIsPayload(mod)) {6917 if (optional_ty.optionalReprIsPayload(mod)) {
7004 // Payload value is the same as the optional value.6918 // Payload value is the same as the optional value.
7005 return operand;6919 return operand;
7006 }6920 }
70076921
7008 const opt_llvm_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);6922 const opt_llvm_ty = try o.lowerType(optional_ty);
7009 const can_elide_load = if (isByRef(payload_ty, mod)) self.canElideLoad(body_tail) else false;6923 const can_elide_load = if (isByRef(payload_ty, mod)) self.canElideLoad(body_tail) else false;
7010 return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, can_elide_load);6924 return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, can_elide_load);
7011 }6925 }
...@@ -7014,7 +6928,7 @@ pub const FuncGen = struct {...@@ -7014,7 +6928,7 @@ pub const FuncGen = struct {
7014 self: *FuncGen,6928 self: *FuncGen,
7015 body_tail: []const Air.Inst.Index,6929 body_tail: []const Air.Inst.Index,
7016 operand_is_ptr: bool,6930 operand_is_ptr: bool,
7017 ) !?*llvm.Value {6931 ) !Builder.Value {
7018 const o = self.dg.object;6932 const o = self.dg.object;
7019 const mod = o.module;6933 const mod = o.module;
7020 const inst = body_tail[0];6934 const inst = body_tail[0];
...@@ -7026,32 +6940,30 @@ pub const FuncGen = struct {...@@ -7026,32 +6940,30 @@ pub const FuncGen = struct {
7026 const payload_ty = if (operand_is_ptr) result_ty.childType(mod) else result_ty;6940 const payload_ty = if (operand_is_ptr) result_ty.childType(mod) else result_ty;
70276941
7028 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {6942 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
7029 return if (operand_is_ptr) operand else null;6943 return if (operand_is_ptr) operand else .none;
7030 }6944 }
7031 const offset = errUnionPayloadOffset(payload_ty, mod);6945 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);
7033 if (operand_is_ptr) {6947 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, "");
7035 } else if (isByRef(err_union_ty, mod)) {6949 } 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, "");
7037 if (isByRef(payload_ty, mod)) {6952 if (isByRef(payload_ty, mod)) {
7038 if (self.canElideLoad(body_tail))6953 if (self.canElideLoad(body_tail)) return payload_ptr;
7039 return payload_ptr;6954 return self.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
7040
7041 return self.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(mod), false);
7042 }6955 }
7043 const load_inst = self.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, "");6956 const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
7044 load_inst.setAlignment(payload_ty.abiAlignment(mod));6957 return self.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
7045 return load_inst;
7046 }6958 }
7047 return self.builder.buildExtractValue(operand, offset, "");6959 return self.wip.extractValue(operand, &.{offset}, "");
7048 }6960 }
70496961
7050 fn airErrUnionErr(6962 fn airErrUnionErr(
7051 self: *FuncGen,6963 self: *FuncGen,
7052 inst: Air.Inst.Index,6964 inst: Air.Inst.Index,
7053 operand_is_ptr: bool,6965 operand_is_ptr: bool,
7054 ) !?*llvm.Value {6966 ) !Builder.Value {
7055 const o = self.dg.object;6967 const o = self.dg.object;
7056 const mod = o.module;6968 const mod = o.module;
7057 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6969 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -7062,30 +6974,28 @@ pub const FuncGen = struct {...@@ -7062,30 +6974,28 @@ pub const FuncGen = struct {
7062 if (operand_is_ptr) {6974 if (operand_is_ptr) {
7063 return operand;6975 return operand;
7064 } else {6976 } 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);
7066 }6978 }
7067 }6979 }
70686980
7069 const err_set_llvm_ty = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder);
7070
7071 const payload_ty = err_union_ty.errorUnionPayload(mod);6981 const payload_ty = err_union_ty.errorUnionPayload(mod);
7072 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {6982 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
7073 if (!operand_is_ptr) return operand;6983 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, "");
7075 }6985 }
70766986
7077 const offset = errUnionErrorOffset(payload_ty, mod);6987 const offset = errUnionErrorOffset(payload_ty, mod);
70786988
7079 if (operand_is_ptr or isByRef(err_union_ty, mod)) {6989 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);6990 const err_union_llvm_ty = try o.lowerType(err_union_ty);
7081 const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");6991 const err_field_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
7082 return self.builder.buildLoad(err_set_llvm_ty, err_field_ptr, "");6992 return self.wip.load(.normal, Builder.Type.err_int, err_field_ptr, .default, "");
7083 }6993 }
70846994
7085 return self.builder.buildExtractValue(operand, offset, "");6995 return self.wip.extractValue(operand, &.{offset}, "");
7086 }6996 }
70876997
7088 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {6998 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7089 const o = self.dg.object;6999 const o = self.dg.object;
7090 const mod = o.module;7000 const mod = o.module;
7091 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7001 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -7093,49 +7003,49 @@ pub const FuncGen = struct {...@@ -7093,49 +7003,49 @@ pub const FuncGen = struct {
7093 const err_union_ty = self.typeOf(ty_op.operand).childType(mod);7003 const err_union_ty = self.typeOf(ty_op.operand).childType(mod);
70947004
7095 const payload_ty = err_union_ty.errorUnionPayload(mod);7005 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);
7097 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {7007 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);
7099 return operand;7009 return operand;
7100 }7010 }
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);
7102 {7012 {
7013 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
7103 const error_offset = errUnionErrorOffset(payload_ty, mod);7014 const error_offset = errUnionErrorOffset(payload_ty, mod);
7104 // First set the non-error value.7015 // First set the non-error value.
7105 const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, "");7016 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");
7106 const store_inst = self.builder.buildStore(non_error_val.toLlvm(&o.builder), non_null_ptr);7017 _ = try self.wip.store(.normal, non_error_val, non_null_ptr, error_alignment);
7107 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));
7108 }7018 }
7109 // Then return the payload pointer (only if it is used).7019 // Then return the payload pointer (only if it is used).
7110 if (self.liveness.isUnused(inst))7020 if (self.liveness.isUnused(inst)) return .none;
7111 return null;
71127021
7113 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7022 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, "");
7115 }7024 }
71167025
7117 fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !?*llvm.Value {7026 fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !Builder.Value {
7118 return self.err_ret_trace.?;7027 assert(self.err_ret_trace != .none);
7028 return self.err_ret_trace;
7119 }7029 }
71207030
7121 fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7031 fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7122 const un_op = self.air.instructions.items(.data)[inst].un_op;7032 const un_op = self.air.instructions.items(.data)[inst].un_op;
7123 const operand = try self.resolveInst(un_op);7033 self.err_ret_trace = try self.resolveInst(un_op);
7124 self.err_ret_trace = operand;7034 return .none;
7125 return null;
7126 }7035 }
71277036
7128 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7037 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7129 const o = self.dg.object;7038 const o = self.dg.object;
7130 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7039 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
7131 //const struct_ty = try self.resolveInst(ty_pl.ty);
7132 const struct_ty = self.air.getRefType(ty_pl.ty);7040 const struct_ty = self.air.getRefType(ty_pl.ty);
7133 const field_index = ty_pl.payload;7041 const field_index = ty_pl.payload;
71347042
7135 const mod = o.module;7043 const mod = o.module;
7136 const llvm_field = llvmField(struct_ty, field_index, mod).?;7044 const llvm_field = llvmField(struct_ty, field_index, mod).?;
7137 const struct_llvm_ty = (try o.lowerType(struct_ty)).toLlvm(&o.builder);7045 const struct_llvm_ty = try o.lowerType(struct_ty);
7138 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field.index, "");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, "");
7139 const field_ptr_ty = try mod.ptrType(.{7049 const field_ptr_ty = try mod.ptrType(.{
7140 .child = llvm_field.ty.toIntern(),7050 .child = llvm_field.ty.toIntern(),
7141 .flags = .{7051 .flags = .{
...@@ -7145,34 +7055,32 @@ pub const FuncGen = struct {...@@ -7145,34 +7055,32 @@ pub const FuncGen = struct {
7145 return self.load(field_ptr, field_ptr_ty);7055 return self.load(field_ptr, field_ptr_ty);
7146 }7056 }
71477057
7148 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7058 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7149 const o = self.dg.object;7059 const o = self.dg.object;
7150 const mod = o.module;7060 const mod = o.module;
7151 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7061 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7152 const payload_ty = self.typeOf(ty_op.operand);7062 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);
7154 comptime assert(optional_layout_version == 3);7064 comptime assert(optional_layout_version == 3);
7155 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return non_null_bit;7065 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return non_null_bit;
7156 const operand = try self.resolveInst(ty_op.operand);7066 const operand = try self.resolveInst(ty_op.operand);
7157 const optional_ty = self.typeOfIndex(inst);7067 const optional_ty = self.typeOfIndex(inst);
7158 if (optional_ty.optionalReprIsPayload(mod)) {7068 if (optional_ty.optionalReprIsPayload(mod)) return operand;
7159 return operand;7069 const llvm_optional_ty = try o.lowerType(optional_ty);
7160 }
7161 const llvm_optional_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);
7162 if (isByRef(optional_ty, mod)) {7070 if (isByRef(optional_ty, mod)) {
7163 const optional_ptr = try self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(mod));7071 const alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
7164 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");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, "");
7165 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7074 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
7166 try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);7075 try self.store(payload_ptr, payload_ptr_ty, operand, .none);
7167 const non_null_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 1, "");7076 const non_null_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 1, "");
7168 _ = self.builder.buildStore(non_null_bit, non_null_ptr);7077 _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default);
7169 return optional_ptr;7078 return optional_ptr;
7170 }7079 }
7171 const partial = self.builder.buildInsertValue(llvm_optional_ty.getUndef(), operand, 0, "");7080 return self.wip.buildAggregate(llvm_optional_ty, &.{ operand, non_null_bit }, "");
7172 return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
7173 }7081 }
71747082
7175 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7083 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7176 const o = self.dg.object;7084 const o = self.dg.object;
7177 const mod = o.module;7085 const mod = o.module;
7178 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7086 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -7182,46 +7090,47 @@ pub const FuncGen = struct {...@@ -7182,46 +7090,47 @@ pub const FuncGen = struct {
7182 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {7090 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
7183 return operand;7091 return operand;
7184 }7092 }
7185 const ok_err_code = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder);7093 const ok_err_code = try o.builder.intValue(Builder.Type.err_int, 0);
7186 const err_un_llvm_ty = (try o.lowerType(err_un_ty)).toLlvm(&o.builder);7094 const err_un_llvm_ty = try o.lowerType(err_un_ty);
71877095
7188 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7096 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
7189 const error_offset = errUnionErrorOffset(payload_ty, mod);7097 const error_offset = errUnionErrorOffset(payload_ty, mod);
7190 if (isByRef(err_un_ty, mod)) {7098 if (isByRef(err_un_ty, mod)) {
7191 const result_ptr = try self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod));7099 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
7192 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");7100 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7193 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);7101 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
7194 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));7102 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
7195 const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");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, "");
7196 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7105 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);
7198 return result_ptr;7107 return result_ptr;
7199 }7108 }
72007109 var fields: [2]Builder.Value = undefined;
7201 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, error_offset, "");7110 fields[payload_offset] = operand;
7202 return self.builder.buildInsertValue(partial, operand, payload_offset, "");7111 fields[error_offset] = ok_err_code;
7112 return self.wip.buildAggregate(err_un_llvm_ty, &fields, "");
7203 }7113 }
72047114
7205 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7115 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7206 const o = self.dg.object;7116 const o = self.dg.object;
7207 const mod = o.module;7117 const mod = o.module;
7208 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7118 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7209 const err_un_ty = self.typeOfIndex(inst);7119 const err_un_ty = self.typeOfIndex(inst);
7210 const payload_ty = err_un_ty.errorUnionPayload(mod);7120 const payload_ty = err_un_ty.errorUnionPayload(mod);
7211 const operand = try self.resolveInst(ty_op.operand);7121 const operand = try self.resolveInst(ty_op.operand);
7212 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {7122 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return operand;
7213 return operand;7123 const err_un_llvm_ty = try o.lowerType(err_un_ty);
7214 }
7215 const err_un_llvm_ty = (try o.lowerType(err_un_ty)).toLlvm(&o.builder);
72167124
7217 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7125 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
7218 const error_offset = errUnionErrorOffset(payload_ty, mod);7126 const error_offset = errUnionErrorOffset(payload_ty, mod);
7219 if (isByRef(err_un_ty, mod)) {7127 if (isByRef(err_un_ty, mod)) {
7220 const result_ptr = try self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod));7128 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
7221 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");7129 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7222 const store_inst = self.builder.buildStore(operand, err_ptr);7130 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");
7223 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));7131 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
7224 const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, "");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, "");
7225 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7134 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
7226 // TODO store undef to payload_ptr7135 // TODO store undef to payload_ptr
7227 _ = payload_ptr;7136 _ = payload_ptr;
...@@ -7229,12 +7138,12 @@ pub const FuncGen = struct {...@@ -7229,12 +7138,12 @@ pub const FuncGen = struct {
7229 return result_ptr;7138 return result_ptr;
7230 }7139 }
72317140
7232 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), operand, error_offset, "");
7233 // TODO set payload bytes to undef7141 // 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}, "");
7235 }7144 }
72367145
7237 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7146 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7238 const o = self.dg.object;7147 const o = self.dg.object;
7239 const pl_op = self.air.instructions.items(.data)[inst].pl_op;7148 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
7240 const index = pl_op.payload;7149 const index = pl_op.payload;
...@@ -7242,10 +7151,18 @@ pub const FuncGen = struct {...@@ -7242,10 +7151,18 @@ pub const FuncGen = struct {
7242 const args: [1]*llvm.Value = .{7151 const args: [1]*llvm.Value = .{
7243 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),7152 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
7244 };7153 };
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);
7246 }7163 }
72477164
7248 fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7165 fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7249 const o = self.dg.object;7166 const o = self.dg.object;
7250 const pl_op = self.air.instructions.items(.data)[inst].pl_op;7167 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
7251 const index = pl_op.payload;7168 const index = pl_op.payload;
...@@ -7253,12 +7170,20 @@ pub const FuncGen = struct {...@@ -7253,12 +7170,20 @@ pub const FuncGen = struct {
7253 const llvm_fn = try self.getIntrinsic("llvm.wasm.memory.grow", &.{.i32});7170 const llvm_fn = try self.getIntrinsic("llvm.wasm.memory.grow", &.{.i32});
7254 const args: [2]*llvm.Value = .{7171 const args: [2]*llvm.Value = .{
7255 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),7172 (try o.builder.intConst(.i32, index)).toLlvm(&o.builder),
7256 operand,7173 operand.toLlvm(&self.wip),
7257 };7174 };
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);
7259 }7184 }
72607185
7261 fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7186 fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7262 const o = self.dg.object;7187 const o = self.dg.object;
7263 const mod = o.module;7188 const mod = o.module;
7264 const data = self.air.instructions.items(.data)[inst].vector_store_elem;7189 const data = self.air.instructions.items(.data)[inst].vector_store_elem;
...@@ -7269,19 +7194,20 @@ pub const FuncGen = struct {...@@ -7269,19 +7194,20 @@ pub const FuncGen = struct {
7269 const index = try self.resolveInst(extra.lhs);7194 const index = try self.resolveInst(extra.lhs);
7270 const operand = try self.resolveInst(extra.rhs);7195 const operand = try self.resolveInst(extra.rhs);
72717196
7272 const loaded_vector = blk: {7197 const kind: Builder.MemoryAccessKind = switch (vector_ptr_ty.isVolatilePtr(mod)) {
7273 const elem_llvm_ty = (try o.lowerType(vector_ptr_ty.childType(mod))).toLlvm(&o.builder);7198 false => .normal,
7274 const load_inst = self.builder.buildLoad(elem_llvm_ty, vector_ptr, "");7199 true => .@"volatile",
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;
7278 };7200 };
7279 const modified_vector = self.builder.buildInsertElement(loaded_vector, operand, index, "");7201 const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod));
7280 try self.store(vector_ptr, vector_ptr_ty, modified_vector, .NotAtomic);7202 const alignment = Builder.Alignment.fromByteUnits(vector_ptr_ty.ptrAlignment(mod));
7281 return null;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;
7282 }7208 }
72837209
7284 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7210 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7285 const o = self.dg.object;7211 const o = self.dg.object;
7286 const mod = o.module;7212 const mod = o.module;
7287 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7213 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7290,11 +7216,13 @@ pub const FuncGen = struct {...@@ -7290,11 +7216,13 @@ pub const FuncGen = struct {
7290 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);7216 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);
72917217
7292 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmin, scalar_ty, 2, .{ lhs, rhs });7218 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, "");7219 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7294 return self.builder.buildUMin(lhs, rhs, "");7220 .@"llvm.smin."
7221 else
7222 .@"llvm.umin.", lhs, rhs, "");
7295 }7223 }
72967224
7297 fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7225 fn airMax(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7298 const o = self.dg.object;7226 const o = self.dg.object;
7299 const mod = o.module;7227 const mod = o.module;
7300 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7228 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7303,26 +7231,23 @@ pub const FuncGen = struct {...@@ -7303,26 +7231,23 @@ pub const FuncGen = struct {
7303 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);7231 const scalar_ty = self.typeOfIndex(inst).scalarType(mod);
73047232
7305 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmax, scalar_ty, 2, .{ lhs, rhs });7233 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, "");7234 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7307 return self.builder.buildUMax(lhs, rhs, "");7235 .@"llvm.smax."
7236 else
7237 .@"llvm.umax.", lhs, rhs, "");
7308 }7238 }
73097239
7310 fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7240 fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7311 const o = self.dg.object;7241 const o = self.dg.object;
7312 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7242 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
7313 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;7243 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
7314 const ptr = try self.resolveInst(bin_op.lhs);7244 const ptr = try self.resolveInst(bin_op.lhs);
7315 const len = try self.resolveInst(bin_op.rhs);7245 const len = try self.resolveInst(bin_op.rhs);
7316 const inst_ty = self.typeOfIndex(inst);7246 const inst_ty = self.typeOfIndex(inst);
7317 const llvm_slice_ty = (try o.lowerType(inst_ty)).toLlvm(&o.builder);7247 return self.wip.buildAggregate(try o.lowerType(inst_ty), &.{ ptr, len }, "");
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, "");
7323 }7248 }
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 {
7326 self.builder.setFastMath(want_fast_math);7251 self.builder.setFastMath(want_fast_math);
73277252
7328 const o = self.dg.object;7253 const o = self.dg.object;
...@@ -7334,8 +7259,7 @@ pub const FuncGen = struct {...@@ -7334,8 +7259,7 @@ pub const FuncGen = struct {
7334 const scalar_ty = inst_ty.scalarType(mod);7259 const scalar_ty = inst_ty.scalarType(mod);
73357260
7336 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.add, inst_ty, 2, .{ lhs, rhs });7261 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, "");7262 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"add nsw" else .@"add nuw", lhs, rhs, "");
7338 return self.builder.buildNUWAdd(lhs, rhs, "");
7339 }7263 }
73407264
7341 fn airSafeArithmetic(7265 fn airSafeArithmetic(
...@@ -7343,7 +7267,7 @@ pub const FuncGen = struct {...@@ -7343,7 +7267,7 @@ pub const FuncGen = struct {
7343 inst: Air.Inst.Index,7267 inst: Air.Inst.Index,
7344 signed_intrinsic: []const u8,7268 signed_intrinsic: []const u8,
7345 unsigned_intrinsic: []const u8,7269 unsigned_intrinsic: []const u8,
7346 ) !?*llvm.Value {7270 ) !Builder.Value {
7347 const o = fg.dg.object;7271 const o = fg.dg.object;
7348 const mod = o.module;7272 const mod = o.module;
73497273
...@@ -7358,44 +7282,51 @@ pub const FuncGen = struct {...@@ -7358,44 +7282,51 @@ pub const FuncGen = struct {
7358 true => signed_intrinsic,7282 true => signed_intrinsic,
7359 false => unsigned_intrinsic,7283 false => unsigned_intrinsic,
7360 };7284 };
7361 const llvm_fn = try fg.getIntrinsic(intrinsic_name, &.{try o.lowerType(inst_ty)});7285 const llvm_inst_ty = try o.lowerType(inst_ty);
7362 const result_struct = fg.builder.buildCall(7286 const llvm_ret_ty = try o.builder.structType(.normal, &.{
7363 llvm_fn.globalGetValueType(),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),
7364 llvm_fn,7294 llvm_fn,
7365 &[_]*llvm.Value{ lhs, rhs },7295 &[_]*llvm.Value{ lhs.toLlvm(&fg.wip), rhs.toLlvm(&fg.wip) },
7366 2,7296 2,
7367 .Fast,7297 .Fast,
7368 .Auto,7298 .Auto,
7369 "",7299 "",
7370 );7300 ), &fg.wip);
7371 const overflow_bit = fg.builder.buildExtractValue(result_struct, 1, "");7301 const overflow_bit = try fg.wip.extractValue(result_struct, &.{1}, "");
7372 const scalar_overflow_bit = switch (is_scalar) {7302 const scalar_overflow_bit = switch (is_scalar) {
7373 true => overflow_bit,7303 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 ),
7375 };7308 };
73767309
7377 const fail_block = try fg.wip.block("OverflowFail");7310 const fail_block = try fg.wip.block(1, "OverflowFail");
7378 const ok_block = try fg.wip.block("OverflowOk");7311 const ok_block = try fg.wip.block(1, "OverflowOk");
7379 _ = fg.builder.buildCondBr(scalar_overflow_bit, fail_block.toLlvm(&fg.wip), ok_block.toLlvm(&fg.wip));7312 _ = try fg.wip.brCond(scalar_overflow_bit, fail_block, ok_block);
73807313
7381 fg.wip.cursor = .{ .block = fail_block };7314 fg.wip.cursor = .{ .block = fail_block };
7382 fg.builder.positionBuilderAtEnd(fail_block.toLlvm(&fg.wip));
7383 try fg.buildSimplePanic(.integer_overflow);7315 try fg.buildSimplePanic(.integer_overflow);
73847316
7385 fg.wip.cursor = .{ .block = ok_block };7317 fg.wip.cursor = .{ .block = ok_block };
7386 fg.builder.positionBuilderAtEnd(ok_block.toLlvm(&fg.wip));7318 return fg.wip.extractValue(result_struct, &.{0}, "");
7387 return fg.builder.buildExtractValue(result_struct, 0, "");
7388 }7319 }
73897320
7390 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7321 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7391 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7322 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7392 const lhs = try self.resolveInst(bin_op.lhs);7323 const lhs = try self.resolveInst(bin_op.lhs);
7393 const rhs = try self.resolveInst(bin_op.rhs);7324 const rhs = try self.resolveInst(bin_op.rhs);
73947325
7395 return self.builder.buildAdd(lhs, rhs, "");7326 return self.wip.bin(.add, lhs, rhs, "");
7396 }7327 }
73977328
7398 fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7329 fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7399 const o = self.dg.object;7330 const o = self.dg.object;
7400 const mod = o.module;7331 const mod = o.module;
7401 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7332 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7405,12 +7336,13 @@ pub const FuncGen = struct {...@@ -7405,12 +7336,13 @@ pub const FuncGen = struct {
7405 const scalar_ty = inst_ty.scalarType(mod);7336 const scalar_ty = inst_ty.scalarType(mod);
74067337
7407 if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});7338 if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});
7408 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSAddSat(lhs, rhs, "");7339 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
74097340 .@"llvm.sadd.sat."
7410 return self.builder.buildUAddSat(lhs, rhs, "");7341 else
7342 .@"llvm.uadd.sat.", lhs, rhs, "");
7411 }7343 }
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 {
7414 self.builder.setFastMath(want_fast_math);7346 self.builder.setFastMath(want_fast_math);
74157347
7416 const o = self.dg.object;7348 const o = self.dg.object;
...@@ -7422,19 +7354,18 @@ pub const FuncGen = struct {...@@ -7422,19 +7354,18 @@ pub const FuncGen = struct {
7422 const scalar_ty = inst_ty.scalarType(mod);7354 const scalar_ty = inst_ty.scalarType(mod);
74237355
7424 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.sub, inst_ty, 2, .{ lhs, rhs });7356 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, "");7357 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"sub nsw" else .@"sub nuw", lhs, rhs, "");
7426 return self.builder.buildNUWSub(lhs, rhs, "");
7427 }7358 }
74287359
7429 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7360 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7430 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7361 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7431 const lhs = try self.resolveInst(bin_op.lhs);7362 const lhs = try self.resolveInst(bin_op.lhs);
7432 const rhs = try self.resolveInst(bin_op.rhs);7363 const rhs = try self.resolveInst(bin_op.rhs);
74337364
7434 return self.builder.buildSub(lhs, rhs, "");7365 return self.wip.bin(.sub, lhs, rhs, "");
7435 }7366 }
74367367
7437 fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7368 fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7438 const o = self.dg.object;7369 const o = self.dg.object;
7439 const mod = o.module;7370 const mod = o.module;
7440 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7371 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7444,11 +7375,13 @@ pub const FuncGen = struct {...@@ -7444,11 +7375,13 @@ pub const FuncGen = struct {
7444 const scalar_ty = inst_ty.scalarType(mod);7375 const scalar_ty = inst_ty.scalarType(mod);
74457376
7446 if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});7377 if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
7447 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSSubSat(lhs, rhs, "");7378 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7448 return self.builder.buildUSubSat(lhs, rhs, "");7379 .@"llvm.ssub.sat."
7380 else
7381 .@"llvm.usub.sat.", lhs, rhs, "");
7449 }7382 }
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 {
7452 self.builder.setFastMath(want_fast_math);7385 self.builder.setFastMath(want_fast_math);
74537386
7454 const o = self.dg.object;7387 const o = self.dg.object;
...@@ -7460,19 +7393,18 @@ pub const FuncGen = struct {...@@ -7460,19 +7393,18 @@ pub const FuncGen = struct {
7460 const scalar_ty = inst_ty.scalarType(mod);7393 const scalar_ty = inst_ty.scalarType(mod);
74617394
7462 if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.mul, inst_ty, 2, .{ lhs, rhs });7395 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, "");7396 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .@"mul nsw" else .@"mul nuw", lhs, rhs, "");
7464 return self.builder.buildNUWMul(lhs, rhs, "");
7465 }7397 }
74667398
7467 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7399 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7468 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7400 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
7469 const lhs = try self.resolveInst(bin_op.lhs);7401 const lhs = try self.resolveInst(bin_op.lhs);
7470 const rhs = try self.resolveInst(bin_op.rhs);7402 const rhs = try self.resolveInst(bin_op.rhs);
74717403
7472 return self.builder.buildMul(lhs, rhs, "");7404 return self.wip.bin(.mul, lhs, rhs, "");
7473 }7405 }
74747406
7475 fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7407 fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7476 const o = self.dg.object;7408 const o = self.dg.object;
7477 const mod = o.module;7409 const mod = o.module;
7478 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7410 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7482,11 +7414,13 @@ pub const FuncGen = struct {...@@ -7482,11 +7414,13 @@ pub const FuncGen = struct {
7482 const scalar_ty = inst_ty.scalarType(mod);7414 const scalar_ty = inst_ty.scalarType(mod);
74837415
7484 if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});7416 if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
7485 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMulFixSat(lhs, rhs, "");7417 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7486 return self.builder.buildUMulFixSat(lhs, rhs, "");7418 .@"llvm.smul.fix.sat."
7419 else
7420 .@"llvm.umul.fix.sat.", lhs, rhs, "");
7487 }7421 }
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 {
7490 self.builder.setFastMath(want_fast_math);7424 self.builder.setFastMath(want_fast_math);
74917425
7492 const bin_op = self.air.instructions.items(.data)[inst].bin_op;7426 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -7497,7 +7431,7 @@ pub const FuncGen = struct {...@@ -7497,7 +7431,7 @@ pub const FuncGen = struct {
7497 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });7431 return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
7498 }7432 }
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 {
7501 self.builder.setFastMath(want_fast_math);7435 self.builder.setFastMath(want_fast_math);
75027436
7503 const o = self.dg.object;7437 const o = self.dg.object;
...@@ -7512,11 +7446,10 @@ pub const FuncGen = struct {...@@ -7512,11 +7446,10 @@ pub const FuncGen = struct {
7512 const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });7446 const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
7513 return self.buildFloatOp(.trunc, inst_ty, 1, .{result});7447 return self.buildFloatOp(.trunc, inst_ty, 1, .{result});
7514 }7448 }
7515 if (scalar_ty.isSignedInt(mod)) return self.builder.buildSDiv(lhs, rhs, "");7449 return self.wip.bin(if (scalar_ty.isSignedInt(mod)) .sdiv else .udiv, lhs, rhs, "");
7516 return self.builder.buildUDiv(lhs, rhs, "");
7517 }7450 }
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 {
7520 self.builder.setFastMath(want_fast_math);7453 self.builder.setFastMath(want_fast_math);
75217454
7522 const o = self.dg.object;7455 const o = self.dg.object;
...@@ -7533,24 +7466,24 @@ pub const FuncGen = struct {...@@ -7533,24 +7466,24 @@ pub const FuncGen = struct {
7533 }7466 }
7534 if (scalar_ty.isSignedInt(mod)) {7467 if (scalar_ty.isSignedInt(mod)) {
7535 const inst_llvm_ty = try o.lowerType(inst_ty);7468 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(
7537 inst_llvm_ty.scalarType(&o.builder),7470 inst_llvm_ty.scalarType(&o.builder),
7538 inst_llvm_ty.scalarBits(&o.builder) - 1,7471 inst_llvm_ty.scalarBits(&o.builder) - 1,
7539 ));7472 ));
75407473
7541 const div = self.builder.buildSDiv(lhs, rhs, "");7474 const div = try self.wip.bin(.sdiv, lhs, rhs, "");
7542 const rem = self.builder.buildSRem(lhs, rhs, "");7475 const rem = try self.wip.bin(.srem, lhs, rhs, "");
7543 const div_sign = self.builder.buildXor(lhs, rhs, "");7476 const div_sign = try self.wip.bin(.xor, lhs, rhs, "");
7544 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one.toLlvm(&o.builder), "");7477 const div_sign_mask = try self.wip.bin(.ashr, div_sign, bit_size_minus_one, "");
7545 const zero = try o.builder.zeroInitConst(inst_llvm_ty);7478 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7546 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero.toLlvm(&o.builder), "");7479 const rem_nonzero = try self.wip.icmp(.ne, rem, zero, "");
7547 const correction = self.builder.buildSelect(rem_nonzero, div_sign_mask, zero.toLlvm(&o.builder), "");7480 const correction = try self.wip.select(rem_nonzero, div_sign_mask, zero, "");
7548 return self.builder.buildNSWAdd(div, correction, "");7481 return self.wip.bin(.@"add nsw", div, correction, "");
7549 }7482 }
7550 return self.builder.buildUDiv(lhs, rhs, "");7483 return self.wip.bin(.udiv, lhs, rhs, "");
7551 }7484 }
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 {
7554 self.builder.setFastMath(want_fast_math);7487 self.builder.setFastMath(want_fast_math);
75557488
7556 const o = self.dg.object;7489 const o = self.dg.object;
...@@ -7562,11 +7495,13 @@ pub const FuncGen = struct {...@@ -7562,11 +7495,13 @@ pub const FuncGen = struct {
7562 const scalar_ty = inst_ty.scalarType(mod);7495 const scalar_ty = inst_ty.scalarType(mod);
75637496
7564 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });7497 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, "");7498 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7566 return self.builder.buildExactUDiv(lhs, rhs, "");7499 .@"sdiv exact"
7500 else
7501 .@"udiv exact", lhs, rhs, "");
7567 }7502 }
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 {
7570 self.builder.setFastMath(want_fast_math);7505 self.builder.setFastMath(want_fast_math);
75717506
7572 const o = self.dg.object;7507 const o = self.dg.object;
...@@ -7578,11 +7513,13 @@ pub const FuncGen = struct {...@@ -7578,11 +7513,13 @@ pub const FuncGen = struct {
7578 const scalar_ty = inst_ty.scalarType(mod);7513 const scalar_ty = inst_ty.scalarType(mod);
75797514
7580 if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });7515 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, "");7516 return self.wip.bin(if (scalar_ty.isSignedInt(mod))
7582 return self.builder.buildURem(lhs, rhs, "");7517 .srem
7518 else
7519 .urem, lhs, rhs, "");
7583 }7520 }
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 {
7586 self.builder.setFastMath(want_fast_math);7523 self.builder.setFastMath(want_fast_math);
75877524
7588 const o = self.dg.object;7525 const o = self.dg.object;
...@@ -7598,29 +7535,29 @@ pub const FuncGen = struct {...@@ -7598,29 +7535,29 @@ pub const FuncGen = struct {
7598 const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });7535 const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
7599 const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });7536 const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });
7600 const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs });7537 const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs });
7601 const zero = try o.builder.zeroInitConst(inst_llvm_ty);7538 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7602 const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero.toLlvm(&o.builder) });7539 const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero });
7603 return self.builder.buildSelect(ltz, c, a, "");7540 return self.wip.select(ltz, c, a, "");
7604 }7541 }
7605 if (scalar_ty.isSignedInt(mod)) {7542 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(
7607 inst_llvm_ty.scalarType(&o.builder),7544 inst_llvm_ty.scalarType(&o.builder),
7608 inst_llvm_ty.scalarBits(&o.builder) - 1,7545 inst_llvm_ty.scalarBits(&o.builder) - 1,
7609 ));7546 ));
76107547
7611 const rem = self.builder.buildSRem(lhs, rhs, "");7548 const rem = try self.wip.bin(.srem, lhs, rhs, "");
7612 const div_sign = self.builder.buildXor(lhs, rhs, "");7549 const div_sign = try self.wip.bin(.xor, lhs, rhs, "");
7613 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one.toLlvm(&o.builder), "");7550 const div_sign_mask = try self.wip.bin(.ashr, div_sign, bit_size_minus_one, "");
7614 const rhs_masked = self.builder.buildAnd(rhs, div_sign_mask, "");7551 const rhs_masked = try self.wip.bin(.@"and", rhs, div_sign_mask, "");
7615 const zero = try o.builder.zeroInitConst(inst_llvm_ty);7552 const zero = try o.builder.zeroInitValue(inst_llvm_ty);
7616 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero.toLlvm(&o.builder), "");7553 const rem_nonzero = try self.wip.icmp(.ne, rem, zero, "");
7617 const correction = self.builder.buildSelect(rem_nonzero, rhs_masked, zero.toLlvm(&o.builder), "");7554 const correction = try self.wip.select(rem_nonzero, rhs_masked, zero, "");
7618 return self.builder.buildNSWAdd(rem, correction, "");7555 return self.wip.bin(.@"add nsw", rem, correction, "");
7619 }7556 }
7620 return self.builder.buildURem(lhs, rhs, "");7557 return self.wip.bin(.urem, lhs, rhs, "");
7621 }7558 }
76227559
7623 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7560 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7624 const o = self.dg.object;7561 const o = self.dg.object;
7625 const mod = o.module;7562 const mod = o.module;
7626 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7563 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -7628,55 +7565,39 @@ pub const FuncGen = struct {...@@ -7628,55 +7565,39 @@ pub const FuncGen = struct {
7628 const ptr = try self.resolveInst(bin_op.lhs);7565 const ptr = try self.resolveInst(bin_op.lhs);
7629 const offset = try self.resolveInst(bin_op.rhs);7566 const offset = try self.resolveInst(bin_op.rhs);
7630 const ptr_ty = self.typeOf(bin_op.lhs);7567 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));
7632 switch (ptr_ty.ptrSize(mod)) {7569 switch (ptr_ty.ptrSize(mod)) {
7633 .One => {7570 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7634 // 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, &.{
7635 const indices: [2]*llvm.Value = .{7572 try o.builder.intValue(try o.lowerType(Type.usize), 0), offset,
7636 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),7573 }, ""),
7637 offset,7574 .C, .Many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{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 },
7645 .Slice => {7575 .Slice => {
7646 const base = self.builder.buildExtractValue(ptr, 0, "");7576 const base = try self.wip.extractValue(ptr, &.{0}, "");
7647 const indices: [1]*llvm.Value = .{offset};7577 return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{offset}, "");
7648 return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
7649 },7578 },
7650 }7579 }
7651 }7580 }
76527581
7653 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7582 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7654 const o = self.dg.object;7583 const o = self.dg.object;
7655 const mod = o.module;7584 const mod = o.module;
7656 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7585 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
7657 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;7586 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
7658 const ptr = try self.resolveInst(bin_op.lhs);7587 const ptr = try self.resolveInst(bin_op.lhs);
7659 const offset = try self.resolveInst(bin_op.rhs);7588 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, "");
7661 const ptr_ty = self.typeOf(bin_op.lhs);7590 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));
7663 switch (ptr_ty.ptrSize(mod)) {7592 switch (ptr_ty.ptrSize(mod)) {
7664 .One => {7593 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7665 // 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, &.{
7666 const indices: [2]*llvm.Value = .{7595 try o.builder.intValue(try o.lowerType(Type.usize), 0), negative_offset,
7667 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),7596 }, ""),
7668 negative_offset,7597 .C, .Many => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{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 },
7676 .Slice => {7598 .Slice => {
7677 const base = self.builder.buildExtractValue(ptr, 0, "");7599 const base = try self.wip.extractValue(ptr, &.{0}, "");
7678 const indices: [1]*llvm.Value = .{negative_offset};7600 return self.wip.gep(.inbounds, llvm_elem_ty, base, &.{negative_offset}, "");
7679 return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, "");
7680 },7601 },
7681 }7602 }
7682 }7603 }
...@@ -7686,7 +7607,7 @@ pub const FuncGen = struct {...@@ -7686,7 +7607,7 @@ pub const FuncGen = struct {
7686 inst: Air.Inst.Index,7607 inst: Air.Inst.Index,
7687 signed_intrinsic: []const u8,7608 signed_intrinsic: []const u8,
7688 unsigned_intrinsic: []const u8,7609 unsigned_intrinsic: []const u8,
7689 ) !?*llvm.Value {7610 ) !Builder.Value {
7690 const o = self.dg.object;7611 const o = self.dg.object;
7691 const mod = o.module;7612 const mod = o.module;
7692 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7613 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -7701,59 +7622,91 @@ pub const FuncGen = struct {...@@ -7701,59 +7622,91 @@ pub const FuncGen = struct {
77017622
7702 const intrinsic_name = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic;7623 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)});7628 const llvm_fn = try self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty});
7707 const result_struct = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &[_]*llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, "");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, "");7647 const result = try self.wip.extractValue(result_struct, &.{0}, "");
7710 const overflow_bit = self.builder.buildExtractValue(result_struct, 1, "");7648 const overflow_bit = try self.wip.extractValue(result_struct, &.{1}, "");
77117649
7712 const result_index = llvmField(dest_ty, 0, mod).?.index;7650 const result_index = llvmField(dest_ty, 0, mod).?.index;
7713 const overflow_index = llvmField(dest_ty, 1, mod).?.index;7651 const overflow_index = llvmField(dest_ty, 1, mod).?.index;
77147652
7715 if (isByRef(dest_ty, mod)) {7653 if (isByRef(dest_ty, mod)) {
7716 const result_alignment = dest_ty.abiAlignment(mod);7654 const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
7717 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);7655 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
7718 {7656 {
7719 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");7657 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
7720 const store_inst = self.builder.buildStore(result, field_ptr);7658 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);
7721 store_inst.setAlignment(result_alignment);
7722 }7659 }
7723 {7660 {
7724 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");7661 const overflow_alignment = comptime Builder.Alignment.fromByteUnits(1);
7725 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);7662 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");
7726 store_inst.setAlignment(1);7663 _ = try self.wip.store(.normal, overflow_bit, field_ptr, overflow_alignment);
7727 }7664 }
77287665
7729 return alloca_inst;7666 return alloca_inst;
7730 }7667 }
77317668
7732 const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");7669 var fields: [2]Builder.Value = undefined;
7733 return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");7670 fields[result_index] = result;
7671 fields[overflow_index] = overflow_bit;
7672 return self.wip.buildAggregate(llvm_dest_ty, &fields, "");
7734 }7673 }
77357674
7736 fn buildElementwiseCall(7675 fn buildElementwiseCall(
7737 self: *FuncGen,7676 self: *FuncGen,
7738 llvm_fn: *llvm.Value,7677 llvm_fn: Builder.Function.Index,
7739 args_vectors: []const *llvm.Value,7678 args_vectors: []const Builder.Value,
7740 result_vector: *llvm.Value,7679 result_vector: Builder.Value,
7741 vector_len: usize,7680 vector_len: usize,
7742 ) !*llvm.Value {7681 ) !Builder.Value {
7743 const o = self.dg.object;7682 const o = self.dg.object;
7744 assert(args_vectors.len <= 3);7683 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
7746 var i: usize = 0;7688 var i: usize = 0;
7747 var result = result_vector;7689 var result = result_vector;
7748 while (i < vector_len) : (i += 1) {7690 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
7751 var args: [3]*llvm.Value = undefined;7693 var args: [3]*llvm.Value = undefined;
7752 for (args_vectors, 0..) |arg_vector, k| {7694 for (args[0..args_vectors.len], args_vectors) |*arg_elem, arg_vector| {
7753 args[k] = self.builder.buildExtractElement(arg_vector, index_i32, "");7695 arg_elem.* = (try self.wip.extractElement(arg_vector, index_i32, "")).toLlvm(&self.wip);
7754 }7696 }
7755 const result_elem = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, @intCast(args_vectors.len), .C, .Auto, "");7697 const result_elem = (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
7756 result = self.builder.buildInsertElement(result, result_elem, index_i32, "");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, "");
7757 }7710 }
7758 return result;7711 return result;
7759 }7712 }
...@@ -7763,29 +7716,29 @@ pub const FuncGen = struct {...@@ -7763,29 +7716,29 @@ pub const FuncGen = struct {
7763 fn_name: Builder.String,7716 fn_name: Builder.String,
7764 param_types: []const Builder.Type,7717 param_types: []const Builder.Type,
7765 return_type: Builder.Type,7718 return_type: Builder.Type,
7766 ) Allocator.Error!*llvm.Value {7719 ) Allocator.Error!Builder.Function.Index {
7767 const o = self.dg.object;7720 const o = self.dg.object;
7768 const slice = fn_name.toSlice(&o.builder).?;7721 if (o.builder.getGlobal(fn_name)) |global| return switch (global.ptrConst(&o.builder).kind) {
7769 return o.llvm_module.getNamedFunction(slice) orelse b: {7722 .alias => |alias| alias.getAliasee(&o.builder).ptrConst(&o.builder).kind.function,
7770 const alias = o.llvm_module.getNamedGlobalAlias(slice.ptr, slice.len);7723 .function => |function| function,
7771 break :b if (alias) |a| a.getAliasee() else null;7724 else => unreachable,
7772 } orelse b: {7725 };
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 };
77837726
7784 try o.builder.llvm.globals.append(self.gpa, f);7727 const fn_type = try o.builder.fnType(return_type, param_types, .normal);
7785 _ = try o.builder.addGlobal(fn_name, global);7728 const f = o.llvm_module.addFunction(fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
7786 try o.builder.functions.append(self.gpa, function);7729
7787 break :b f;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()),
7788 };7736 };
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;
7789 }7742 }
77907743
7791 /// Creates a floating point comparison by lowering to the appropriate7744 /// Creates a floating point comparison by lowering to the appropriate
...@@ -7794,8 +7747,8 @@ pub const FuncGen = struct {...@@ -7794,8 +7747,8 @@ pub const FuncGen = struct {
7794 self: *FuncGen,7747 self: *FuncGen,
7795 pred: math.CompareOperator,7748 pred: math.CompareOperator,
7796 ty: Type,7749 ty: Type,
7797 params: [2]*llvm.Value,7750 params: [2]Builder.Value,
7798 ) !*llvm.Value {7751 ) !Builder.Value {
7799 const o = self.dg.object;7752 const o = self.dg.object;
7800 const mod = o.module;7753 const mod = o.module;
7801 const target = o.module.getTarget();7754 const target = o.module.getTarget();
...@@ -7803,15 +7756,15 @@ pub const FuncGen = struct {...@@ -7803,15 +7756,15 @@ pub const FuncGen = struct {
7803 const scalar_llvm_ty = try o.lowerType(scalar_ty);7756 const scalar_llvm_ty = try o.lowerType(scalar_ty);
78047757
7805 if (intrinsicsAllowed(scalar_ty, target)) {7758 if (intrinsicsAllowed(scalar_ty, target)) {
7806 const llvm_predicate: llvm.RealPredicate = switch (pred) {7759 const cond: Builder.FloatCondition = switch (pred) {
7807 .eq => .OEQ,7760 .eq => .oeq,
7808 .neq => .UNE,7761 .neq => .une,
7809 .lt => .OLT,7762 .lt => .olt,
7810 .lte => .OLE,7763 .lte => .ole,
7811 .gt => .OGT,7764 .gt => .ogt,
7812 .gte => .OGE,7765 .gte => .oge,
7813 };7766 };
7814 return self.builder.buildFCmp(llvm_predicate, params[0], params[1], "");7767 return self.wip.fcmp(cond, params[0], params[1], "");
7815 }7768 }
78167769
7817 const float_bits = scalar_ty.floatBits(target);7770 const float_bits = scalar_ty.floatBits(target);
...@@ -7832,29 +7785,42 @@ pub const FuncGen = struct {...@@ -7832,29 +7785,42 @@ pub const FuncGen = struct {
7832 .i32,7785 .i32,
7833 );7786 );
78347787
7835 const zero = (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder);7788 const zero = try o.builder.intConst(.i32, 0);
7836 const int_pred: llvm.IntPredicate = switch (pred) {7789 const int_cond: Builder.IntegerCondition = switch (pred) {
7837 .eq => .EQ,7790 .eq => .eq,
7838 .neq => .NE,7791 .neq => .ne,
7839 .lt => .SLT,7792 .lt => .slt,
7840 .lte => .SLE,7793 .lte => .sle,
7841 .gt => .SGT,7794 .gt => .sgt,
7842 .gte => .SGE,7795 .gte => .sge,
7843 };7796 };
78447797
7845 if (ty.zigTypeTag(mod) == .Vector) {7798 if (ty.zigTypeTag(mod) == .Vector) {
7846 const vec_len = ty.vectorLen(mod);7799 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();7802 const init = try o.builder.poisonValue(vector_result_ty);
7850 result = try self.buildElementwiseCall(libc_fn, &params, result, vec_len);7803 const result = try self.buildElementwiseCall(libc_fn, &params, init, vec_len);
78517804
7852 const zero_vector = self.builder.buildVectorSplat(vec_len, zero, "");7805 const zero_vector = try o.builder.splatValue(vector_result_ty, zero);
7853 return self.builder.buildICmp(int_pred, result, zero_vector, "");7806 return self.wip.icmp(int_cond, result, zero_vector, "");
7854 }7807 }
78557808
7856 const result = self.builder.buildCall(libc_fn.globalGetValueType(), libc_fn, &params, params.len, .C, .Auto, "");7809 const llvm_fn_ty = libc_fn.typeOf(&o.builder);
7857 return self.builder.buildICmp(int_pred, result, zero, "");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(), "");
7858 }7824 }
78597825
7860 const FloatOp = enum {7826 const FloatOp = enum {
...@@ -7896,26 +7862,25 @@ pub const FuncGen = struct {...@@ -7896,26 +7862,25 @@ pub const FuncGen = struct {
7896 comptime op: FloatOp,7862 comptime op: FloatOp,
7897 ty: Type,7863 ty: Type,
7898 comptime params_len: usize,7864 comptime params_len: usize,
7899 params: [params_len]*llvm.Value,7865 params: [params_len]Builder.Value,
7900 ) !*llvm.Value {7866 ) !Builder.Value {
7901 const o = self.dg.object;7867 const o = self.dg.object;
7902 const mod = o.module;7868 const mod = o.module;
7903 const target = mod.getTarget();7869 const target = mod.getTarget();
7904 const scalar_ty = ty.scalarType(mod);7870 const scalar_ty = ty.scalarType(mod);
7905 const llvm_ty = try o.lowerType(ty);7871 const llvm_ty = try o.lowerType(ty);
7906 const scalar_llvm_ty = try o.lowerType(scalar_ty);
79077872
7908 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);7873 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);
7909 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {7874 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
7910 // Some operations are dedicated LLVM instructions, not available as intrinsics7875 // Some operations are dedicated LLVM instructions, not available as intrinsics
7911 .neg => return self.builder.buildFNeg(params[0], ""),7876 .neg => return self.wip.un(.fneg, params[0], ""),
7912 .add => return self.builder.buildFAdd(params[0], params[1], ""),7877 .add => return self.wip.bin(.fadd, params[0], params[1], ""),
7913 .sub => return self.builder.buildFSub(params[0], params[1], ""),7878 .sub => return self.wip.bin(.fsub, params[0], params[1], ""),
7914 .mul => return self.builder.buildFMul(params[0], params[1], ""),7879 .mul => return self.wip.bin(.fmul, params[0], params[1], ""),
7915 .div => return self.builder.buildFDiv(params[0], params[1], ""),7880 .div => return self.wip.bin(.fdiv, params[0], params[1], ""),
7916 .fmod => return self.builder.buildFRem(params[0], params[1], ""),7881 .fmod => return self.wip.bin(.frem, params[0], params[1], ""),
7917 .fmax => return self.builder.buildMaxNum(params[0], params[1], ""),7882 .fmax => return self.wip.bin(.@"llvm.maxnum.", params[0], params[1], ""),
7918 .fmin => return self.builder.buildMinNum(params[0], params[1], ""),7883 .fmin => return self.wip.bin(.@"llvm.minnum.", params[0], params[1], ""),
7919 else => .{ .intrinsic = "llvm." ++ @tagName(op) },7884 else => .{ .intrinsic = "llvm." ++ @tagName(op) },
7920 } else b: {7885 } else b: {
7921 const float_bits = scalar_ty.floatBits(target);7886 const float_bits = scalar_ty.floatBits(target);
...@@ -7924,19 +7889,14 @@ pub const FuncGen = struct {...@@ -7924,19 +7889,14 @@ pub const FuncGen = struct {
7924 // In this case we can generate a softfloat negation by XORing the7889 // In this case we can generate a softfloat negation by XORing the
7925 // bits with a constant.7890 // bits with a constant.
7926 const int_ty = try o.builder.intType(@intCast(float_bits));7891 const int_ty = try o.builder.intType(@intCast(float_bits));
7927 const one = try o.builder.intConst(int_ty, 1);7892 const cast_ty = try llvm_ty.changeScalar(int_ty, &o.builder);
7928 const shift_amt = try o.builder.intConst(int_ty, float_bits - 1);7893 const sign_mask = try o.builder.splatValue(
7929 const sign_mask = try o.builder.binConst(.shl, one, shift_amt);7894 cast_ty,
7930 const result = if (ty.zigTypeTag(mod) == .Vector) blk: {7895 try o.builder.intConst(int_ty, @as(u128, 1) << @intCast(float_bits - 1)),
7931 const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(mod), sign_mask.toLlvm(&o.builder), "");7896 );
7932 const cast_ty = try o.builder.vectorType(.normal, ty.vectorLen(mod), int_ty);7897 const bitcasted_operand = try self.wip.cast(.bitcast, params[0], cast_ty, "");
7933 const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty.toLlvm(&o.builder), "");7898 const result = try self.wip.bin(.xor, bitcasted_operand, sign_mask, "");
7934 break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, "");7899 return self.wip.cast(.bitcast, result, llvm_ty, "");
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), "");
7940 },7900 },
7941 .add, .sub, .div, .mul => .{ .libc = try o.builder.fmt("__{s}{s}f3", .{7901 .add, .sub, .div, .mul => .{ .libc = try o.builder.fmt("__{s}{s}f3", .{
7942 @tagName(op), compilerRtFloatAbbrev(float_bits),7902 @tagName(op), compilerRtFloatAbbrev(float_bits),
...@@ -7965,26 +7925,42 @@ pub const FuncGen = struct {...@@ -7965,26 +7925,42 @@ pub const FuncGen = struct {
7965 };7925 };
7966 };7926 };
79677927
7968 const llvm_fn: *llvm.Value = switch (strat) {7928 const llvm_fn = switch (strat) {
7969 .intrinsic => |fn_name| try self.getIntrinsic(fn_name, &.{llvm_ty}),7929 .intrinsic => |fn_name| try self.getIntrinsic(fn_name, &.{llvm_ty}),
7970 .libc => |fn_name| b: {7930 .libc => |fn_name| b: {
7931 const scalar_llvm_ty = llvm_ty.scalarType(&o.builder);
7971 const libc_fn = try self.getLibcFunction(7932 const libc_fn = try self.getLibcFunction(
7972 fn_name,7933 fn_name,
7973 ([1]Builder.Type{scalar_llvm_ty} ** 3)[0..params.len],7934 ([1]Builder.Type{scalar_llvm_ty} ** 3)[0..params.len],
7974 scalar_llvm_ty,7935 scalar_llvm_ty,
7975 );7936 );
7976 if (ty.zigTypeTag(mod) == .Vector) {7937 if (ty.zigTypeTag(mod) == .Vector) {
7977 const result = llvm_ty.toLlvm(&o.builder).getUndef();7938 const result = try o.builder.poisonValue(llvm_ty);
7978 return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod));7939 return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod));
7979 }7940 }
79807941
7981 break :b libc_fn;7942 break :b libc_fn.toLlvm(&o.builder);
7982 },7943 },
7983 };7944 };
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);
7985 }7961 }
79867962
7987 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7963 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
7988 const pl_op = self.air.instructions.items(.data)[inst].pl_op;7964 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
7989 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;7965 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
79907966
...@@ -7996,7 +7972,7 @@ pub const FuncGen = struct {...@@ -7996,7 +7972,7 @@ pub const FuncGen = struct {
7996 return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend });7972 return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend });
7997 }7973 }
79987974
7999 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7975 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8000 const o = self.dg.object;7976 const o = self.dg.object;
8001 const mod = o.module;7977 const mod = o.module;
8002 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7978 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -8006,72 +7982,67 @@ pub const FuncGen = struct {...@@ -8006,72 +7982,67 @@ pub const FuncGen = struct {
8006 const rhs = try self.resolveInst(extra.rhs);7982 const rhs = try self.resolveInst(extra.rhs);
80077983
8008 const lhs_ty = self.typeOf(extra.lhs);7984 const lhs_ty = self.typeOf(extra.lhs);
8009 const rhs_ty = self.typeOf(extra.rhs);
8010 const lhs_scalar_ty = lhs_ty.scalarType(mod);7985 const lhs_scalar_ty = lhs_ty.scalarType(mod);
8011 const rhs_scalar_ty = rhs_ty.scalarType(mod);
80127986
8013 const dest_ty = self.typeOfIndex(inst);7987 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))7990 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
8017 self.builder.buildZExt(rhs, (try o.lowerType(lhs_ty)).toLlvm(&o.builder), "")
8018 else
8019 rhs;
80207991
8021 const result = self.builder.buildShl(lhs, casted_rhs, "");7992 const result = try self.wip.bin(.shl, lhs, casted_rhs, "");
8022 const reconstructed = if (lhs_scalar_ty.isSignedInt(mod))7993 const reconstructed = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
8023 self.builder.buildAShr(result, casted_rhs, "")7994 .ashr
8024 else7995 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
8029 const result_index = llvmField(dest_ty, 0, mod).?.index;8000 const result_index = llvmField(dest_ty, 0, mod).?.index;
8030 const overflow_index = llvmField(dest_ty, 1, mod).?.index;8001 const overflow_index = llvmField(dest_ty, 1, mod).?.index;
80318002
8032 if (isByRef(dest_ty, mod)) {8003 if (isByRef(dest_ty, mod)) {
8033 const result_alignment = dest_ty.abiAlignment(mod);8004 const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
8034 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);8005 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
8035 {8006 {
8036 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");8007 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
8037 const store_inst = self.builder.buildStore(result, field_ptr);8008 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);
8038 store_inst.setAlignment(result_alignment);
8039 }8009 }
8040 {8010 {
8041 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, overflow_index, "");8011 const field_alignment = comptime Builder.Alignment.fromByteUnits(1);
8042 const store_inst = self.builder.buildStore(overflow_bit, field_ptr);8012 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");
8043 store_inst.setAlignment(1);8013 _ = try self.wip.store(.normal, overflow_bit, field_ptr, field_alignment);
8044 }8014 }
8045
8046 return alloca_inst;8015 return alloca_inst;
8047 }8016 }
80488017
8049 const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, "");8018 var fields: [2]Builder.Value = undefined;
8050 return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, "");8019 fields[result_index] = result;
8020 fields[overflow_index] = overflow_bit;
8021 return self.wip.buildAggregate(llvm_dest_ty, &fields, "");
8051 }8022 }
80528023
8053 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8024 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8054 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8025 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8055 const lhs = try self.resolveInst(bin_op.lhs);8026 const lhs = try self.resolveInst(bin_op.lhs);
8056 const rhs = try self.resolveInst(bin_op.rhs);8027 const rhs = try self.resolveInst(bin_op.rhs);
8057 return self.builder.buildAnd(lhs, rhs, "");8028 return self.wip.bin(.@"and", lhs, rhs, "");
8058 }8029 }
80598030
8060 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8031 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8061 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8032 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8062 const lhs = try self.resolveInst(bin_op.lhs);8033 const lhs = try self.resolveInst(bin_op.lhs);
8063 const rhs = try self.resolveInst(bin_op.rhs);8034 const rhs = try self.resolveInst(bin_op.rhs);
8064 return self.builder.buildOr(lhs, rhs, "");8035 return self.wip.bin(.@"or", lhs, rhs, "");
8065 }8036 }
80668037
8067 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8038 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8068 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8039 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8069 const lhs = try self.resolveInst(bin_op.lhs);8040 const lhs = try self.resolveInst(bin_op.lhs);
8070 const rhs = try self.resolveInst(bin_op.rhs);8041 const rhs = try self.resolveInst(bin_op.rhs);
8071 return self.builder.buildXor(lhs, rhs, "");8042 return self.wip.bin(.xor, lhs, rhs, "");
8072 }8043 }
80738044
8074 fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8045 fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8075 const o = self.dg.object;8046 const o = self.dg.object;
8076 const mod = o.module;8047 const mod = o.module;
8077 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8048 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -8080,39 +8051,29 @@ pub const FuncGen = struct {...@@ -8080,39 +8051,29 @@ pub const FuncGen = struct {
8080 const rhs = try self.resolveInst(bin_op.rhs);8051 const rhs = try self.resolveInst(bin_op.rhs);
80818052
8082 const lhs_ty = self.typeOf(bin_op.lhs);8053 const lhs_ty = self.typeOf(bin_op.lhs);
8083 const rhs_ty = self.typeOf(bin_op.rhs);
8084 const lhs_scalar_ty = lhs_ty.scalarType(mod);8054 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))8056 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
8088 self.builder.buildZExt(rhs, (try o.lowerType(lhs_ty)).toLlvm(&o.builder), "")8057 return self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
8058 .@"shl nsw"
8089 else8059 else
8090 rhs;8060 .@"shl nuw", lhs, casted_rhs, "");
8091 if (lhs_scalar_ty.isSignedInt(mod)) return self.builder.buildNSWShl(lhs, casted_rhs, "");
8092 return self.builder.buildNUWShl(lhs, casted_rhs, "");
8093 }8061 }
80948062
8095 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8063 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8096 const o = self.dg.object;8064 const o = self.dg.object;
8097 const mod = o.module;
8098 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8065 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
80998066
8100 const lhs = try self.resolveInst(bin_op.lhs);8067 const lhs = try self.resolveInst(bin_op.lhs);
8101 const rhs = try self.resolveInst(bin_op.rhs);8068 const rhs = try self.resolveInst(bin_op.rhs);
81028069
8103 const lhs_type = self.typeOf(bin_op.lhs);8070 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))8072 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_type), "");
8109 self.builder.buildZExt(rhs, (try o.lowerType(lhs_type)).toLlvm(&o.builder), "")8073 return self.wip.bin(.shl, lhs, casted_rhs, "");
8110 else
8111 rhs;
8112 return self.builder.buildShl(lhs, casted_rhs, "");
8113 }8074 }
81148075
8115 fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8076 fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8116 const o = self.dg.object;8077 const o = self.dg.object;
8117 const mod = o.module;8078 const mod = o.module;
8118 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8079 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -8121,42 +8082,36 @@ pub const FuncGen = struct {...@@ -8121,42 +8082,36 @@ pub const FuncGen = struct {
8121 const rhs = try self.resolveInst(bin_op.rhs);8082 const rhs = try self.resolveInst(bin_op.rhs);
81228083
8123 const lhs_ty = self.typeOf(bin_op.lhs);8084 const lhs_ty = self.typeOf(bin_op.lhs);
8124 const rhs_ty = self.typeOf(bin_op.rhs);
8125 const lhs_scalar_ty = lhs_ty.scalarType(mod);8085 const lhs_scalar_ty = lhs_ty.scalarType(mod);
8126 const rhs_scalar_ty = rhs_ty.scalarType(mod);
8127 const lhs_bits = lhs_scalar_ty.bitSize(mod);8086 const lhs_bits = lhs_scalar_ty.bitSize(mod);
81288087
8129 const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_bits)8088 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
8130 self.builder.buildZExt(rhs, lhs.typeOf(), "")
8131 else
8132 rhs;
81338089
8134 const result = if (lhs_scalar_ty.isSignedInt(mod))8090 const result = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(mod))
8135 self.builder.buildSShlSat(lhs, casted_rhs, "")8091 .@"llvm.sshl.sat."
8136 else8092 else
8137 self.builder.buildUShlSat(lhs, casted_rhs, "");8093 .@"llvm.ushl.sat.", lhs, casted_rhs, "");
81388094
8139 // LLVM langref says "If b is (statically or dynamically) equal to or8095 // LLVM langref says "If b is (statically or dynamically) equal to or
8140 // larger than the integer bit width of the arguments, the result is a8096 // larger than the integer bit width of the arguments, the result is a
8141 // poison value."8097 // poison value."
8142 // However Zig semantics says that saturating shift left can never produce8098 // However Zig semantics says that saturating shift left can never produce
8143 // undefined; instead it saturates.8099 // undefined; instead it saturates.
8144 const lhs_scalar_llvm_ty = try o.lowerType(lhs_scalar_ty);8100 const lhs_llvm_ty = try o.lowerType(lhs_ty);
8145 const bits = (try o.builder.intConst(lhs_scalar_llvm_ty, lhs_bits)).toLlvm(&o.builder);8101 const lhs_scalar_llvm_ty = lhs_llvm_ty.scalarType(&o.builder);
8146 const lhs_max = (try o.builder.intConst(lhs_scalar_llvm_ty, -1)).toLlvm(&o.builder);8102 const bits = try o.builder.splatValue(
8147 if (rhs_ty.zigTypeTag(mod) == .Vector) {8103 lhs_llvm_ty,
8148 const vec_len = rhs_ty.vectorLen(mod);8104 try o.builder.intConst(lhs_scalar_llvm_ty, lhs_bits),
8149 const bits_vec = self.builder.buildVectorSplat(vec_len, bits, "");8105 );
8150 const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, "");8106 const lhs_max = try o.builder.splatValue(
8151 const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, "");8107 lhs_llvm_ty,
8152 return self.builder.buildSelect(in_range, result, lhs_max_vec, "");8108 try o.builder.intConst(lhs_scalar_llvm_ty, -1),
8153 } else {8109 );
8154 const in_range = self.builder.buildICmp(.ULT, rhs, bits, "");8110 const in_range = try self.wip.icmp(.ult, rhs, bits, "");
8155 return self.builder.buildSelect(in_range, result, lhs_max, "");8111 return self.wip.select(in_range, result, lhs_max, "");
8156 }
8157 }8112 }
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 {
8160 const o = self.dg.object;8115 const o = self.dg.object;
8161 const mod = o.module;8116 const mod = o.module;
8162 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8117 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -8165,63 +8120,41 @@ pub const FuncGen = struct {...@@ -8165,63 +8120,41 @@ pub const FuncGen = struct {
8165 const rhs = try self.resolveInst(bin_op.rhs);8120 const rhs = try self.resolveInst(bin_op.rhs);
81668121
8167 const lhs_ty = self.typeOf(bin_op.lhs);8122 const lhs_ty = self.typeOf(bin_op.lhs);
8168 const rhs_ty = self.typeOf(bin_op.rhs);
8169 const lhs_scalar_ty = lhs_ty.scalarType(mod);8123 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))8125 const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), "");
8173 self.builder.buildZExt(rhs, (try o.lowerType(lhs_ty)).toLlvm(&o.builder), "")
8174 else
8175 rhs;
8176 const is_signed_int = lhs_scalar_ty.isSignedInt(mod);8126 const is_signed_int = lhs_scalar_ty.isSignedInt(mod);
81778127
8178 if (is_exact) {8128 return self.wip.bin(if (is_exact)
8179 if (is_signed_int) {8129 if (is_signed_int) .@"ashr exact" else .@"lshr exact"
8180 return self.builder.buildAShrExact(lhs, casted_rhs, "");8130 else if (is_signed_int) .ashr else .lshr, 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 }
8191 }8131 }
81928132
8193 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8133 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8194 const o = self.dg.object;8134 const o = self.dg.object;
8195 const mod = o.module;8135 const mod = o.module;
8196 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8136 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8197 const dest_ty = self.typeOfIndex(inst);8137 const dest_ty = self.typeOfIndex(inst);
8198 const dest_info = dest_ty.intInfo(mod);8138 const dest_llvm_ty = try o.lowerType(dest_ty);
8199 const dest_llvm_ty = (try o.lowerType(dest_ty)).toLlvm(&o.builder);
8200 const operand = try self.resolveInst(ty_op.operand);8139 const operand = try self.resolveInst(ty_op.operand);
8201 const operand_ty = self.typeOf(ty_op.operand);8140 const operand_ty = self.typeOf(ty_op.operand);
8202 const operand_info = operand_ty.intInfo(mod);8141 const operand_info = operand_ty.intInfo(mod);
82038142
8204 if (operand_info.bits < dest_info.bits) {8143 return self.wip.conv(switch (operand_info.signedness) {
8205 switch (operand_info.signedness) {8144 .signed => .signed,
8206 .signed => return self.builder.buildSExt(operand, dest_llvm_ty, ""),8145 .unsigned => .unsigned,
8207 .unsigned => return self.builder.buildZExt(operand, dest_llvm_ty, ""),8146 }, 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 }
8214 }8147 }
82158148
8216 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8149 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8217 const o = self.dg.object;8150 const o = self.dg.object;
8218 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8151 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8219 const operand = try self.resolveInst(ty_op.operand);8152 const operand = try self.resolveInst(ty_op.operand);
8220 const dest_llvm_ty = (try o.lowerType(self.typeOfIndex(inst))).toLlvm(&o.builder);8153 const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
8221 return self.builder.buildTrunc(operand, dest_llvm_ty, "");8154 return self.wip.cast(.trunc, operand, dest_llvm_ty, "");
8222 }8155 }
82238156
8224 fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8157 fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8225 const o = self.dg.object;8158 const o = self.dg.object;
8226 const mod = o.module;8159 const mod = o.module;
8227 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8160 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -8233,8 +8166,7 @@ pub const FuncGen = struct {...@@ -8233,8 +8166,7 @@ pub const FuncGen = struct {
8233 const src_bits = operand_ty.floatBits(target);8166 const src_bits = operand_ty.floatBits(target);
82348167
8235 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {8168 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
8236 const dest_llvm_ty = (try o.lowerType(dest_ty)).toLlvm(&o.builder);8169 return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty), "");
8237 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
8238 } else {8170 } else {
8239 const operand_llvm_ty = try o.lowerType(operand_ty);8171 const operand_llvm_ty = try o.lowerType(operand_ty);
8240 const dest_llvm_ty = try o.lowerType(dest_ty);8172 const dest_llvm_ty = try o.lowerType(dest_ty);
...@@ -8243,14 +8175,21 @@ pub const FuncGen = struct {...@@ -8243,14 +8175,21 @@ pub const FuncGen = struct {
8243 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),8175 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
8244 });8176 });
82458177
8246 const params = [1]*llvm.Value{operand};
8247 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);8178 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
82488179 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
8249 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");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);
8250 }8189 }
8251 }8190 }
82528191
8253 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8192 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8254 const o = self.dg.object;8193 const o = self.dg.object;
8255 const mod = o.module;8194 const mod = o.module;
8256 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8195 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -8262,8 +8201,7 @@ pub const FuncGen = struct {...@@ -8262,8 +8201,7 @@ pub const FuncGen = struct {
8262 const src_bits = operand_ty.floatBits(target);8201 const src_bits = operand_ty.floatBits(target);
82638202
8264 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {8203 if (intrinsicsAllowed(dest_ty, target) and intrinsicsAllowed(operand_ty, target)) {
8265 const dest_llvm_ty = (try o.lowerType(dest_ty)).toLlvm(&o.builder);8204 return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty), "");
8266 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
8267 } else {8205 } else {
8268 const operand_llvm_ty = try o.lowerType(operand_ty);8206 const operand_llvm_ty = try o.lowerType(operand_ty);
8269 const dest_llvm_ty = try o.lowerType(dest_ty);8207 const dest_llvm_ty = try o.lowerType(dest_ty);
...@@ -8272,24 +8210,31 @@ pub const FuncGen = struct {...@@ -8272,24 +8210,31 @@ pub const FuncGen = struct {
8272 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),8210 compilerRtFloatAbbrev(src_bits), compilerRtFloatAbbrev(dest_bits),
8273 });8211 });
82748212
8275 const params = [1]*llvm.Value{operand};
8276 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);8213 const llvm_fn = try self.getLibcFunction(fn_name, &.{operand_llvm_ty}, dest_llvm_ty);
82778214 const params = [1]*llvm.Value{operand.toLlvm(&self.wip)};
8278 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");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);
8279 }8224 }
8280 }8225 }
82818226
8282 fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8227 fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8283 const o = self.dg.object;8228 const o = self.dg.object;
8284 const un_op = self.air.instructions.items(.data)[inst].un_op;8229 const un_op = self.air.instructions.items(.data)[inst].un_op;
8285 const operand = try self.resolveInst(un_op);8230 const operand = try self.resolveInst(un_op);
8286 const ptr_ty = self.typeOf(un_op);8231 const ptr_ty = self.typeOf(un_op);
8287 const operand_ptr = self.sliceOrArrayPtr(operand, ptr_ty);8232 const operand_ptr = try self.sliceOrArrayPtr(operand, ptr_ty);
8288 const dest_llvm_ty = (try o.lowerType(self.typeOfIndex(inst))).toLlvm(&o.builder);8233 const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
8289 return self.builder.buildPtrToInt(operand_ptr, dest_llvm_ty, "");8234 return self.wip.cast(.ptrtoint, operand_ptr, dest_llvm_ty, "");
8290 }8235 }
82918236
8292 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !*llvm.Value {8237 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8293 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8238 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8294 const operand_ty = self.typeOf(ty_op.operand);8239 const operand_ty = self.typeOf(ty_op.operand);
8295 const inst_ty = self.typeOfIndex(inst);8240 const inst_ty = self.typeOfIndex(inst);
...@@ -8297,26 +8242,26 @@ pub const FuncGen = struct {...@@ -8297,26 +8242,26 @@ pub const FuncGen = struct {
8297 return self.bitCast(operand, operand_ty, inst_ty);8242 return self.bitCast(operand, operand_ty, inst_ty);
8298 }8243 }
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 {
8301 const o = self.dg.object;8246 const o = self.dg.object;
8302 const mod = o.module;8247 const mod = o.module;
8303 const operand_is_ref = isByRef(operand_ty, mod);8248 const operand_is_ref = isByRef(operand_ty, mod);
8304 const result_is_ref = isByRef(inst_ty, mod);8249 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
8307 if (operand_is_ref and result_is_ref) {8252 if (operand_is_ref and result_is_ref) {
8308 // They are both pointers, so just return the same opaque pointer :)8253 // They are both pointers, so just return the same opaque pointer :)
8309 return operand;8254 return operand;
8310 }8255 }
83118256
8312 if (llvm_dest_ty.getTypeKind() == .Integer and8257 if (llvm_dest_ty.isInteger(&o.builder) and
8313 operand.typeOf().getTypeKind() == .Integer)8258 operand.typeOfWip(&self.wip).isInteger(&o.builder))
8314 {8259 {
8315 return self.builder.buildZExtOrBitCast(operand, llvm_dest_ty, "");8260 return self.wip.conv(.unsigned, operand, llvm_dest_ty, "");
8316 }8261 }
83178262
8318 if (operand_ty.zigTypeTag(mod) == .Int and inst_ty.isPtrAtRuntime(mod)) {8263 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, "");
8320 }8265 }
83218266
8322 if (operand_ty.zigTypeTag(mod) == .Vector and inst_ty.zigTypeTag(mod) == .Array) {8267 if (operand_ty.zigTypeTag(mod) == .Vector and inst_ty.zigTypeTag(mod) == .Array) {
...@@ -8324,108 +8269,97 @@ pub const FuncGen = struct {...@@ -8324,108 +8269,97 @@ pub const FuncGen = struct {
8324 if (!result_is_ref) {8269 if (!result_is_ref) {
8325 return self.dg.todo("implement bitcast vector to non-ref array", .{});8270 return self.dg.todo("implement bitcast vector to non-ref array", .{});
8326 }8271 }
8327 const array_ptr = try self.buildAlloca(llvm_dest_ty, null);8272 const array_ptr = try self.buildAlloca(llvm_dest_ty, .default);
8328 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;8273 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
8329 if (bitcast_ok) {8274 if (bitcast_ok) {
8330 const llvm_store = self.builder.buildStore(operand, array_ptr);8275 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8331 llvm_store.setAlignment(inst_ty.abiAlignment(mod));8276 _ = try self.wip.store(.normal, operand, array_ptr, alignment);
8332 } else {8277 } else {
8333 // If the ABI size of the element type is not evenly divisible by size in bits;8278 // If the ABI size of the element type is not evenly divisible by size in bits;
8334 // a simple bitcast will not work, and we fall back to extractelement.8279 // a simple bitcast will not work, and we fall back to extractelement.
8335 const llvm_usize = try o.lowerType(Type.usize);8280 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);
8337 const vector_len = operand_ty.arrayLen(mod);8282 const vector_len = operand_ty.arrayLen(mod);
8338 var i: u64 = 0;8283 var i: u64 = 0;
8339 while (i < vector_len) : (i += 1) {8284 while (i < vector_len) : (i += 1) {
8340 const index_usize = try o.builder.intConst(llvm_usize, i);8285 const elem_ptr = try self.wip.gep(.inbounds, llvm_dest_ty, array_ptr, &.{
8341 const index_u32 = try o.builder.intConst(.i32, i);8286 usize_zero, try o.builder.intValue(llvm_usize, i),
8342 const indexes: [2]*llvm.Value = .{8287 }, "");
8343 zero.toLlvm(&o.builder),8288 const elem =
8344 index_usize.toLlvm(&o.builder),8289 try self.wip.extractElement(operand, try o.builder.intValue(.i32, i), "");
8345 };8290 _ = try self.wip.store(.normal, elem, elem_ptr, .default);
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);
8349 }8291 }
8350 }8292 }
8351 return array_ptr;8293 return array_ptr;
8352 } else if (operand_ty.zigTypeTag(mod) == .Array and inst_ty.zigTypeTag(mod) == .Vector) {8294 } else if (operand_ty.zigTypeTag(mod) == .Array and inst_ty.zigTypeTag(mod) == .Vector) {
8353 const elem_ty = operand_ty.childType(mod);8295 const elem_ty = operand_ty.childType(mod);
8354 const llvm_vector_ty = (try o.lowerType(inst_ty)).toLlvm(&o.builder);8296 const llvm_vector_ty = try o.lowerType(inst_ty);
8355 if (!operand_is_ref) {8297 if (!operand_is_ref) return self.dg.todo("implement bitcast non-ref array to vector", .{});
8356 return self.dg.todo("implement bitcast non-ref array to vector", .{});
8357 }
83588298
8359 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;8299 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
8360 if (bitcast_ok) {8300 if (bitcast_ok) {
8361 const vector = self.builder.buildLoad(llvm_vector_ty, operand, "");
8362 // The array is aligned to the element's alignment, while the vector might have a completely8301 // The array is aligned to the element's alignment, while the vector might have a completely
8363 // different alignment. This means we need to enforce the alignment of this load.8302 // different alignment. This means we need to enforce the alignment of this load.
8364 vector.setAlignment(elem_ty.abiAlignment(mod));8303 const alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
8365 return vector;8304 return self.wip.load(.normal, llvm_vector_ty, operand, alignment, "");
8366 } else {8305 } else {
8367 // If the ABI size of the element type is not evenly divisible by size in bits;8306 // If the ABI size of the element type is not evenly divisible by size in bits;
8368 // a simple bitcast will not work, and we fall back to extractelement.8307 // 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);8308 const array_llvm_ty = try o.lowerType(operand_ty);
8370 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);8309 const elem_llvm_ty = try o.lowerType(elem_ty);
8371 const llvm_usize = try o.lowerType(Type.usize);8310 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);
8373 const vector_len = operand_ty.arrayLen(mod);8312 const vector_len = operand_ty.arrayLen(mod);
8374 var vector = llvm_vector_ty.getUndef();8313 var vector = try o.builder.poisonValue(llvm_vector_ty);
8375 var i: u64 = 0;8314 var i: u64 = 0;
8376 while (i < vector_len) : (i += 1) {8315 while (i < vector_len) : (i += 1) {
8377 const index_usize = try o.builder.intConst(llvm_usize, i);8316 const elem_ptr = try self.wip.gep(.inbounds, array_llvm_ty, operand, &.{
8378 const index_u32 = try o.builder.intConst(.i32, i);8317 usize_zero, try o.builder.intValue(llvm_usize, i),
8379 const indexes: [2]*llvm.Value = .{8318 }, "");
8380 zero.toLlvm(&o.builder),8319 const elem = try self.wip.load(.normal, elem_llvm_ty, elem_ptr, .default, "");
8381 index_usize.toLlvm(&o.builder),8320 vector =
8382 };8321 try self.wip.insertElement(vector, elem, try o.builder.intValue(.i32, i), "");
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), "");
8386 }8322 }
8387
8388 return vector;8323 return vector;
8389 }8324 }
8390 }8325 }
83918326
8392 if (operand_is_ref) {8327 if (operand_is_ref) {
8393 const load_inst = self.builder.buildLoad(llvm_dest_ty, operand, "");8328 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
8394 load_inst.setAlignment(operand_ty.abiAlignment(mod));8329 return self.wip.load(.normal, llvm_dest_ty, operand, alignment, "");
8395 return load_inst;
8396 }8330 }
83978331
8398 if (result_is_ref) {8332 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 );
8400 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);8336 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8401 const store_inst = self.builder.buildStore(operand, result_ptr);8337 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
8402 store_inst.setAlignment(alignment);
8403 return result_ptr;8338 return result_ptr;
8404 }8339 }
84058340
8406 if (llvm_dest_ty.getTypeKind() == .Struct) {8341 if (llvm_dest_ty.isStruct(&o.builder)) {
8407 // Both our operand and our result are values, not pointers,8342 // Both our operand and our result are values, not pointers,
8408 // but LLVM won't let us bitcast struct values.8343 // but LLVM won't let us bitcast struct values.
8409 // Therefore, we store operand to alloca, then load for result.8344 // 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 );
8411 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);8348 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8412 const store_inst = self.builder.buildStore(operand, result_ptr);8349 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
8413 store_inst.setAlignment(alignment);8350 return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, "");
8414 const load_inst = self.builder.buildLoad(llvm_dest_ty, result_ptr, "");
8415 load_inst.setAlignment(alignment);
8416 return load_inst;
8417 }8351 }
84188352
8419 return self.builder.buildBitCast(operand, llvm_dest_ty, "");8353 return self.wip.cast(.bitcast, operand, llvm_dest_ty, "");
8420 }8354 }
84218355
8422 fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8356 fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8423 const un_op = self.air.instructions.items(.data)[inst].un_op;8357 const un_op = self.air.instructions.items(.data)[inst].un_op;
8424 const operand = try self.resolveInst(un_op);8358 const operand = try self.resolveInst(un_op);
8425 return operand;8359 return operand;
8426 }8360 }
84278361
8428 fn airArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8362 fn airArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8429 const o = self.dg.object;8363 const o = self.dg.object;
8430 const mod = o.module;8364 const mod = o.module;
8431 const arg_val = self.args[self.arg_index];8365 const arg_val = self.args[self.arg_index];
...@@ -8433,9 +8367,7 @@ pub const FuncGen = struct {...@@ -8433,9 +8367,7 @@ pub const FuncGen = struct {
84338367
8434 const inst_ty = self.typeOfIndex(inst);8368 const inst_ty = self.typeOfIndex(inst);
8435 if (o.di_builder) |dib| {8369 if (o.di_builder) |dib| {
8436 if (needDbgVarWorkaround(o)) {8370 if (needDbgVarWorkaround(o)) return arg_val;
8437 return arg_val;
8438 }
84398371
8440 const src_index = self.air.instructions.items(.data)[inst].arg.src_index;8372 const src_index = self.air.instructions.items(.data)[inst].arg.src_index;
8441 const func_index = self.dg.decl.getOwnedFunctionIndex();8373 const func_index = self.dg.decl.getOwnedFunctionIndex();
...@@ -8450,62 +8382,64 @@ pub const FuncGen = struct {...@@ -8450,62 +8382,64 @@ pub const FuncGen = struct {
8450 try o.lowerDebugType(inst_ty, .full),8382 try o.lowerDebugType(inst_ty, .full),
8451 true, // always preserve8383 true, // always preserve
8452 0, // flags8384 0, // flags
8453 self.arg_index, // includes +1 because 0 is return type8385 @intCast(self.arg_index), // includes +1 because 0 is return type
8454 );8386 );
84558387
8456 const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);8388 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);
8458 if (isByRef(inst_ty, mod)) {8390 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);
8460 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {8392 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
8461 const alignment = inst_ty.abiAlignment(mod);8393 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8462 const alloca = try self.buildAlloca(arg_val.typeOf(), alignment);8394 const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
8463 const store_inst = self.builder.buildStore(arg_val, alloca);8395 _ = try self.wip.store(.normal, arg_val, alloca, alignment);
8464 store_inst.setAlignment(alignment);8396 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
8465 _ = dib.insertDeclareAtEnd(alloca, di_local_var, debug_loc, insert_block);
8466 } else {8397 } 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);
8468 }8399 }
8469 }8400 }
84708401
8471 return arg_val;8402 return arg_val;
8472 }8403 }
84738404
8474 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8405 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8475 const o = self.dg.object;8406 const o = self.dg.object;
8476 const mod = o.module;8407 const mod = o.module;
8477 const ptr_ty = self.typeOfIndex(inst);8408 const ptr_ty = self.typeOfIndex(inst);
8478 const pointee_type = ptr_ty.childType(mod);8409 const pointee_type = ptr_ty.childType(mod);
8479 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod))8410 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);8413 const pointee_llvm_ty = try o.lowerType(pointee_type);
8483 const alignment = ptr_ty.ptrAlignment(mod);8414 const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8484 return self.buildAlloca(pointee_llvm_ty, alignment);8415 return self.buildAlloca(pointee_llvm_ty, alignment);
8485 }8416 }
84868417
8487 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8418 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8488 const o = self.dg.object;8419 const o = self.dg.object;
8489 const mod = o.module;8420 const mod = o.module;
8490 const ptr_ty = self.typeOfIndex(inst);8421 const ptr_ty = self.typeOfIndex(inst);
8491 const ret_ty = ptr_ty.childType(mod);8422 const ret_ty = ptr_ty.childType(mod);
8492 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod))8423 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod))
8493 return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder);8424 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
8494 if (self.ret_ptr) |ret_ptr| return ret_ptr;8425 if (self.ret_ptr != .none) return self.ret_ptr;
8495 const ret_llvm_ty = (try o.lowerType(ret_ty)).toLlvm(&o.builder);8426 const ret_llvm_ty = try o.lowerType(ret_ty);
8496 return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(mod));8427 const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8428 return self.buildAlloca(ret_llvm_ty, alignment);
8497 }8429 }
84988430
8499 /// Use this instead of builder.buildAlloca, because this function makes sure to8431 /// Use this instead of builder.buildAlloca, because this function makes sure to
8500 /// put the alloca instruction at the top of the function!8432 /// 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 {8433 fn buildAlloca(
8502 const o = self.dg.object;8434 self: *FuncGen,
8503 const mod = o.module;8435 llvm_ty: Builder.Type,
8504 const target = mod.getTarget();8436 alignment: Builder.Alignment,
8505 return o.buildAllocaInner(&self.wip, self.builder, self.llvm_func, self.di_scope != null, llvm_ty, alignment, target);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);
8506 }8440 }
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 {
8509 const o = self.dg.object;8443 const o = self.dg.object;
8510 const mod = o.module;8444 const mod = o.module;
8511 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8445 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -8519,23 +8453,29 @@ pub const FuncGen = struct {...@@ -8519,23 +8453,29 @@ pub const FuncGen = struct {
8519 // extra information to LLVM. However, safety makes the difference between using8453 // extra information to LLVM. However, safety makes the difference between using
8520 // 0xaa or actual undefined for the fill byte.8454 // 0xaa or actual undefined for the fill byte.
8521 const fill_byte = if (safety)8455 const fill_byte = if (safety)
8522 (try o.builder.intConst(.i8, 0xaa)).toLlvm(&o.builder)8456 try o.builder.intConst(.i8, 0xaa)
8523 else8457 else
8524 Builder.Type.i8.toLlvm(&o.builder).getUndef();8458 try o.builder.undefConst(.i8);
8525 const operand_size = operand_ty.abiSize(mod);8459 const operand_size = operand_ty.abiSize(mod);
8526 const usize_ty = try o.lowerType(Type.usize);8460 const usize_ty = try o.lowerType(Type.usize);
8527 const len = (try o.builder.intConst(usize_ty, operand_size)).toLlvm(&o.builder);8461 const len = try o.builder.intValue(usize_ty, operand_size);
8528 const dest_ptr_align = ptr_ty.ptrAlignment(mod);8462 const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8529 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr(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);
8530 if (safety and mod.comp.bin_file.options.valgrind) {8470 if (safety and mod.comp.bin_file.options.valgrind) {
8531 try self.valgrindMarkUndef(dest_ptr, len);8471 try self.valgrindMarkUndef(dest_ptr, len);
8532 }8472 }
8533 return null;8473 return .none;
8534 }8474 }
85358475
8536 const src_operand = try self.resolveInst(bin_op.rhs);8476 const src_operand = try self.resolveInst(bin_op.rhs);
8537 try self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic);8477 try self.store(dest_ptr, ptr_ty, src_operand, .none);
8538 return null;8478 return .none;
8539 }8479 }
85408480
8541 /// As an optimization, we want to avoid unnecessary copies of isByRef=true8481 /// As an optimization, we want to avoid unnecessary copies of isByRef=true
...@@ -8560,7 +8500,7 @@ pub const FuncGen = struct {...@@ -8560,7 +8500,7 @@ pub const FuncGen = struct {
8560 return false;8500 return false;
8561 }8501 }
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 {
8564 const o = fg.dg.object;8504 const o = fg.dg.object;
8565 const mod = o.module;8505 const mod = o.module;
8566 const inst = body_tail[0];8506 const inst = body_tail[0];
...@@ -8577,22 +8517,40 @@ pub const FuncGen = struct {...@@ -8577,22 +8517,40 @@ pub const FuncGen = struct {
8577 return fg.load(ptr, ptr_ty);8517 return fg.load(ptr, ptr_ty);
8578 }8518 }
85798519
8580 fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8520 fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8581 _ = inst;8521 _ = inst;
8522 const o = self.dg.object;
8582 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});8523 const llvm_fn = try self.getIntrinsic("llvm.trap", &.{});
8583 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .Cold, .Auto, "");8524 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8584 _ = self.builder.buildUnreachable();8525 (try o.builder.fnType(.void, &.{}, .normal)).toLlvm(&o.builder),
8585 return null;8526 llvm_fn,
8527 undefined,
8528 0,
8529 .Cold,
8530 .Auto,
8531 "",
8532 ), &self.wip);
8533 _ = try self.wip.@"unreachable"();
8534 return .none;
8586 }8535 }
85878536
8588 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8537 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8589 _ = inst;8538 _ = inst;
8539 const o = self.dg.object;
8590 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});8540 const llvm_fn = try self.getIntrinsic("llvm.debugtrap", &.{});
8591 _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, undefined, 0, .C, .Auto, "");8541 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
8592 return null;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;
8593 }8551 }
85948552
8595 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8553 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8596 _ = inst;8554 _ = inst;
8597 const o = self.dg.object;8555 const o = self.dg.object;
8598 const mod = o.module;8556 const mod = o.module;
...@@ -8600,18 +8558,26 @@ pub const FuncGen = struct {...@@ -8600,18 +8558,26 @@ pub const FuncGen = struct {
8600 const target = mod.getTarget();8558 const target = mod.getTarget();
8601 if (!target_util.supportsReturnAddress(target)) {8559 if (!target_util.supportsReturnAddress(target)) {
8602 // https://github.com/ziglang/zig/issues/119468560 // 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);
8604 }8562 }
86058563
8606 const llvm_fn = try self.getIntrinsic("llvm.returnaddress", &.{});8564 const llvm_fn = try self.getIntrinsic("llvm.returnaddress", &.{});
8607 const params = [_]*llvm.Value{8565 const params = [_]*llvm.Value{
8608 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),8566 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8609 };8567 };
8610 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");8568 const ptr_val = (try self.wip.unimplemented(.ptr, "")).finish(self.builder.buildCall(
8611 return self.builder.buildPtrToInt(ptr_val, llvm_usize.toLlvm(&o.builder), "");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, "");
8612 }8578 }
86138579
8614 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8580 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8615 _ = inst;8581 _ = inst;
8616 const o = self.dg.object;8582 const o = self.dg.object;
8617 const llvm_fn_name = "llvm.frameaddress.p0";8583 const llvm_fn_name = "llvm.frameaddress.p0";
...@@ -8619,24 +8585,34 @@ pub const FuncGen = struct {...@@ -8619,24 +8585,34 @@ pub const FuncGen = struct {
8619 const fn_type = try o.builder.fnType(.ptr, &.{.i32}, .normal);8585 const fn_type = try o.builder.fnType(.ptr, &.{.i32}, .normal);
8620 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));8586 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));
8621 };8587 };
8588 const llvm_fn_ty = try o.builder.fnType(.ptr, &.{.i32}, .normal);
86228589
8623 const params = [_]*llvm.Value{8590 const params = [_]*llvm.Value{
8624 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),8591 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8625 };8592 };
8626 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");8593 const ptr_val = (try self.wip.unimplemented(llvm_fn_ty.functionReturn(&o.builder), "")).finish(
8627 const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder);8594 self.builder.buildCall(
8628 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");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), "");
8629 }8606 }
86308607
8631 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8608 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8632 const atomic_order = self.air.instructions.items(.data)[inst].fence;8609 const atomic_order = self.air.instructions.items(.data)[inst].fence;
8633 const llvm_memory_order = toLlvmAtomicOrdering(atomic_order);8610 const ordering = toLlvmAtomicOrdering(atomic_order);
8634 const single_threaded = llvm.Bool.fromBool(self.single_threaded);8611 _ = try self.wip.fence(self.sync_scope, ordering);
8635 _ = self.builder.buildFence(llvm_memory_order, single_threaded, "");8612 return .none;
8636 return null;
8637 }8613 }
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 {
8640 const o = self.dg.object;8616 const o = self.dg.object;
8641 const mod = o.module;8617 const mod = o.module;
8642 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;8618 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -8645,47 +8621,51 @@ pub const FuncGen = struct {...@@ -8645,47 +8621,51 @@ pub const FuncGen = struct {
8645 var expected_value = try self.resolveInst(extra.expected_value);8621 var expected_value = try self.resolveInst(extra.expected_value);
8646 var new_value = try self.resolveInst(extra.new_value);8622 var new_value = try self.resolveInst(extra.new_value);
8647 const operand_ty = self.typeOf(extra.ptr).childType(mod);8623 const operand_ty = self.typeOf(extra.ptr).childType(mod);
8648 const abi_ty = try o.getAtomicAbiType(operand_ty, false);8624 const llvm_operand_ty = try o.lowerType(operand_ty);
8649 if (abi_ty != .none) {8625 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, false);
8650 const llvm_abi_ty = abi_ty.toLlvm(&o.builder);8626 if (llvm_abi_ty != .none) {
8651 // operand needs widening and truncating8627 // operand needs widening and truncating
8652 if (operand_ty.isSignedInt(mod)) {8628 const signedness: Builder.Function.Instruction.Cast.Signedness =
8653 expected_value = self.builder.buildSExt(expected_value, llvm_abi_ty, "");8629 if (operand_ty.isSignedInt(mod)) .signed else .unsigned;
8654 new_value = self.builder.buildSExt(new_value, llvm_abi_ty, "");8630 expected_value = try self.wip.conv(signedness, expected_value, llvm_abi_ty, "");
8655 } else {8631 new_value = try self.wip.conv(signedness, new_value, llvm_abi_ty, "");
8656 expected_value = self.builder.buildZExt(expected_value, llvm_abi_ty, "");
8657 new_value = self.builder.buildZExt(new_value, llvm_abi_ty, "");
8658 }
8659 }8632 }
8660 const result = self.builder.buildAtomicCmpXchg(8633
8661 ptr,8634 const llvm_result_ty = try o.builder.structType(.normal, &.{
8662 expected_value,8635 if (llvm_abi_ty != .none) llvm_abi_ty else llvm_operand_ty,
8663 new_value,8636 .i1,
8664 toLlvmAtomicOrdering(extra.successOrder()),8637 });
8665 toLlvmAtomicOrdering(extra.failureOrder()),8638 const result = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
8666 llvm.Bool.fromBool(self.single_threaded),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,
8667 );8648 );
8668 result.setWeak(llvm.Bool.fromBool(is_weak));8649 result.toLlvm(&self.wip).setWeak(llvm.Bool.fromBool(is_weak));
86698650
8670 const optional_ty = self.typeOfIndex(inst);8651 const optional_ty = self.typeOfIndex(inst);
86718652
8672 var payload = self.builder.buildExtractValue(result, 0, "");8653 var payload = try self.wip.extractValue(result, &.{0}, "");
8673 if (abi_ty != .none) {8654 if (llvm_abi_ty != .none) payload = try self.wip.cast(.trunc, payload, llvm_operand_ty, "");
8674 payload = self.builder.buildTrunc(payload, (try o.lowerType(operand_ty)).toLlvm(&o.builder), "");8655 const success_bit = try self.wip.extractValue(result, &.{1}, "");
8675 }
8676 const success_bit = self.builder.buildExtractValue(result, 1, "");
86778656
8678 if (optional_ty.optionalReprIsPayload(mod)) {8657 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, "");
8680 }8660 }
86818661
8682 comptime assert(optional_layout_version == 3);8662 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, "");
8685 return buildOptional(self, optional_ty, payload, non_null_bit);8665 return buildOptional(self, optional_ty, payload, non_null_bit);
8686 }8666 }
86878667
8688 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8668 fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8689 const o = self.dg.object;8669 const o = self.dg.object;
8690 const mod = o.module;8670 const mod = o.module;
8691 const pl_op = self.air.instructions.items(.data)[inst].pl_op;8671 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
...@@ -8698,121 +8678,146 @@ pub const FuncGen = struct {...@@ -8698,121 +8678,146 @@ pub const FuncGen = struct {
8698 const is_float = operand_ty.isRuntimeFloat();8678 const is_float = operand_ty.isRuntimeFloat();
8699 const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float);8679 const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float);
8700 const ordering = toLlvmAtomicOrdering(extra.ordering());8680 const ordering = toLlvmAtomicOrdering(extra.ordering());
8701 const single_threaded = llvm.Bool.fromBool(self.single_threaded);8681 const single_threaded = llvm.Bool.fromBool(self.sync_scope == .singlethread);
8702 const abi_ty = try o.getAtomicAbiType(operand_ty, op == .Xchg);8682 const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, op == .Xchg);
8703 if (abi_ty != .none) {8683 const llvm_operand_ty = try o.lowerType(operand_ty);
8704 const llvm_abi_ty = abi_ty.toLlvm(&o.builder);8684 if (llvm_abi_ty != .none) {
8705 // operand needs widening and truncating or bitcasting.8685 // operand needs widening and truncating or bitcasting.
8706 const casted_operand = if (is_float)8686 const casted_operand = try self.wip.cast(
8707 self.builder.buildBitCast(operand, llvm_abi_ty, "")8687 if (is_float) .bitcast else if (is_signed_int) .sext else .zext,
8708 else if (is_signed_int)8688 @enumFromInt(@intFromEnum(operand)),
8709 self.builder.buildSExt(operand, llvm_abi_ty, "")8689 llvm_abi_ty,
8710 else8690 "",
8711 self.builder.buildZExt(operand, llvm_abi_ty, "");8691 );
87128692
8713 const uncasted_result = self.builder.buildAtomicRmw(8693 const uncasted_result = (try self.wip.unimplemented(llvm_abi_ty, "")).finish(
8714 op,8694 self.builder.buildAtomicRmw(
8715 ptr,8695 op,
8716 casted_operand,8696 ptr.toLlvm(&self.wip),
8717 ordering,8697 casted_operand.toLlvm(&self.wip),
8718 single_threaded,8698 @enumFromInt(@intFromEnum(ordering)),
8699 single_threaded,
8700 ),
8701 &self.wip,
8719 );8702 );
8720 const operand_llvm_ty = (try o.lowerType(operand_ty)).toLlvm(&o.builder);8703
8721 if (is_float) {8704 if (is_float) {
8722 return self.builder.buildBitCast(uncasted_result, operand_llvm_ty, "");8705 return self.wip.cast(.bitcast, uncasted_result, llvm_operand_ty, "");
8723 } else {8706 } else {
8724 return self.builder.buildTrunc(uncasted_result, operand_llvm_ty, "");8707 return self.wip.cast(.trunc, uncasted_result, llvm_operand_ty, "");
8725 }8708 }
8726 }8709 }
87278710
8728 if (operand.typeOf().getTypeKind() != .Pointer) {8711 if (!llvm_operand_ty.isPointer(&o.builder)) {
8729 return self.builder.buildAtomicRmw(op, ptr, operand, ordering, single_threaded);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 );
8730 }8722 }
87318723
8732 // It's a pointer but we need to treat it as an int.8724 // 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);8725 const llvm_usize = try o.lowerType(Type.usize);
8734 const casted_operand = self.builder.buildPtrToInt(operand, usize_llvm_ty, "");8726 const casted_operand = try self.wip.cast(.ptrtoint, operand, llvm_usize, "");
8735 const uncasted_result = self.builder.buildAtomicRmw(8727 const uncasted_result = (try self.wip.unimplemented(llvm_usize, "")).finish(
8736 op,8728 self.builder.buildAtomicRmw(
8737 ptr,8729 op,
8738 casted_operand,8730 ptr.toLlvm(&self.wip),
8739 ordering,8731 casted_operand.toLlvm(&self.wip),
8740 single_threaded,8732 @enumFromInt(@intFromEnum(ordering)),
8733 single_threaded,
8734 ),
8735 &self.wip,
8741 );8736 );
8742 const operand_llvm_ty = (try o.lowerType(operand_ty)).toLlvm(&o.builder);8737 return self.wip.cast(.inttoptr, uncasted_result, llvm_operand_ty, "");
8743 return self.builder.buildIntToPtr(uncasted_result, operand_llvm_ty, "");
8744 }8738 }
87458739
8746 fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8740 fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8747 const o = self.dg.object;8741 const o = self.dg.object;
8748 const mod = o.module;8742 const mod = o.module;
8749 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;8743 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
8750 const ptr = try self.resolveInst(atomic_load.ptr);8744 const ptr = try self.resolveInst(atomic_load.ptr);
8751 const ptr_ty = self.typeOf(atomic_load.ptr);8745 const ptr_ty = self.typeOf(atomic_load.ptr);
8752 const ptr_info = ptr_ty.ptrInfo(mod);8746 const info = ptr_ty.ptrInfo(mod);
8753 const elem_ty = ptr_info.child.toType();8747 const elem_ty = info.child.toType();
8754 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod))8748 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
8755 return null;
8756 const ordering = toLlvmAtomicOrdering(atomic_load.order);8749 const ordering = toLlvmAtomicOrdering(atomic_load.order);
8757 const abi_ty = try o.getAtomicAbiType(elem_ty, false);8750 const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false);
8758 const ptr_alignment: u32 = @intCast(ptr_info.flags.alignment.toByteUnitsOptional() orelse8751 const ptr_alignment = Builder.Alignment.fromByteUnits(
8759 ptr_info.child.toType().abiAlignment(mod));8752 info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod),
8760 const ptr_volatile = llvm.Bool.fromBool(ptr_info.flags.is_volatile);8753 );
8761 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);8754 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
87628755 false => .normal,
8763 if (abi_ty != .none) {8756 true => .@"volatile",
8764 const llvm_abi_ty = abi_ty.toLlvm(&o.builder);8757 };
8758 const elem_llvm_ty = try o.lowerType(elem_ty);
8759
8760 if (llvm_abi_ty != .none) {
8765 // operand needs widening and truncating8761 // operand needs widening and truncating
8766 const load_inst = self.builder.buildLoad(llvm_abi_ty, ptr, "");8762 const loaded = try self.wip.loadAtomic(
8767 load_inst.setAlignment(ptr_alignment);8763 ptr_kind,
8768 load_inst.setVolatile(ptr_volatile);8764 llvm_abi_ty,
8769 load_inst.setOrdering(ordering);8765 ptr,
8770 return self.builder.buildTrunc(load_inst, elem_llvm_ty, "");8766 self.sync_scope,
8767 ordering,
8768 ptr_alignment,
8769 "",
8770 );
8771 return self.wip.cast(.trunc, loaded, elem_llvm_ty, "");
8771 }8772 }
8772 const load_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");8773 return self.wip.loadAtomic(
8773 load_inst.setAlignment(ptr_alignment);8774 ptr_kind,
8774 load_inst.setVolatile(ptr_volatile);8775 elem_llvm_ty,
8775 load_inst.setOrdering(ordering);8776 ptr,
8776 return load_inst;8777 self.sync_scope,
8778 ordering,
8779 ptr_alignment,
8780 "",
8781 );
8777 }8782 }
87788783
8779 fn airAtomicStore(8784 fn airAtomicStore(
8780 self: *FuncGen,8785 self: *FuncGen,
8781 inst: Air.Inst.Index,8786 inst: Air.Inst.Index,
8782 ordering: llvm.AtomicOrdering,8787 ordering: Builder.AtomicOrdering,
8783 ) !?*llvm.Value {8788 ) !Builder.Value {
8784 const o = self.dg.object;8789 const o = self.dg.object;
8785 const mod = o.module;8790 const mod = o.module;
8786 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8791 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8787 const ptr_ty = self.typeOf(bin_op.lhs);8792 const ptr_ty = self.typeOf(bin_op.lhs);
8788 const operand_ty = ptr_ty.childType(mod);8793 const operand_ty = ptr_ty.childType(mod);
8789 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return null;8794 if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return .none;
8790 const ptr = try self.resolveInst(bin_op.lhs);8795 const ptr = try self.resolveInst(bin_op.lhs);
8791 var element = try self.resolveInst(bin_op.rhs);8796 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) {8799 if (llvm_abi_ty != .none) {
8795 const llvm_abi_ty = abi_ty.toLlvm(&o.builder);
8796 // operand needs widening8800 // operand needs widening
8797 if (operand_ty.isSignedInt(mod)) {8801 element = try self.wip.conv(
8798 element = self.builder.buildSExt(element, llvm_abi_ty, "");8802 if (operand_ty.isSignedInt(mod)) .signed else .unsigned,
8799 } else {8803 element,
8800 element = self.builder.buildZExt(element, llvm_abi_ty, "");8804 llvm_abi_ty,
8801 }8805 "",
8806 );
8802 }8807 }
8803 try self.store(ptr, ptr_ty, element, ordering);8808 try self.store(ptr, ptr_ty, element, ordering);
8804 return null;8809 return .none;
8805 }8810 }
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 {
8808 const o = self.dg.object;8813 const o = self.dg.object;
8809 const mod = o.module;8814 const mod = o.module;
8810 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8815 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8811 const dest_slice = try self.resolveInst(bin_op.lhs);8816 const dest_slice = try self.resolveInst(bin_op.lhs);
8812 const ptr_ty = self.typeOf(bin_op.lhs);8817 const ptr_ty = self.typeOf(bin_op.lhs);
8813 const elem_ty = self.typeOf(bin_op.rhs);8818 const elem_ty = self.typeOf(bin_op.rhs);
8814 const dest_ptr_align = ptr_ty.ptrAlignment(mod);8819 const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8815 const dest_ptr = self.sliceOrArrayPtr(dest_slice, ptr_ty);8820 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty);
8816 const is_volatile = ptr_ty.isVolatilePtr(mod);8821 const is_volatile = ptr_ty.isVolatilePtr(mod);
88178822
8818 // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless8823 // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless
...@@ -8829,20 +8834,26 @@ pub const FuncGen = struct {...@@ -8829,20 +8834,26 @@ pub const FuncGen = struct {
8829 // extra information to LLVM. However, safety makes the difference between using8834 // extra information to LLVM. However, safety makes the difference between using
8830 // 0xaa or actual undefined for the fill byte.8835 // 0xaa or actual undefined for the fill byte.
8831 const fill_byte = if (safety)8836 const fill_byte = if (safety)
8832 (try o.builder.intConst(.i8, 0xaa)).toLlvm(&o.builder)8837 try o.builder.intValue(.i8, 0xaa)
8833 else8838 else
8834 Builder.Type.i8.toLlvm(&o.builder).getUndef();8839 try o.builder.undefValue(.i8);
8835 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);8840 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
8836 if (intrinsic_len0_traps) {8841 if (intrinsic_len0_traps) {
8837 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);8842 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
8838 } else {8843 } 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);
8840 }8851 }
88418852
8842 if (safety and mod.comp.bin_file.options.valgrind) {8853 if (safety and mod.comp.bin_file.options.valgrind) {
8843 try self.valgrindMarkUndef(dest_ptr, len);8854 try self.valgrindMarkUndef(dest_ptr, len);
8844 }8855 }
8845 return null;8856 return .none;
8846 }8857 }
88478858
8848 // Test if the element value is compile-time known to be a8859 // Test if the element value is compile-time known to be a
...@@ -8850,18 +8861,21 @@ pub const FuncGen = struct {...@@ -8850,18 +8861,21 @@ pub const FuncGen = struct {
8850 // repeating byte pattern of 0 bytes. In such case, the memset8861 // repeating byte pattern of 0 bytes. In such case, the memset
8851 // intrinsic can be used.8862 // intrinsic can be used.
8852 if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| {8863 if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| {
8853 const fill_byte = try self.resolveValue(.{8864 const fill_byte = try self.resolveValue(.{ .ty = Type.u8, .val = byte_val });
8854 .ty = Type.u8,
8855 .val = byte_val,
8856 });
8857 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);8865 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
88588866
8859 if (intrinsic_len0_traps) {8867 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);
8861 } else {8869 } 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);
8863 }8877 }
8864 return null;8878 return .none;
8865 }8879 }
8866 }8880 }
88678881
...@@ -8876,9 +8890,15 @@ pub const FuncGen = struct {...@@ -8876,9 +8890,15 @@ pub const FuncGen = struct {
8876 if (intrinsic_len0_traps) {8890 if (intrinsic_len0_traps) {
8877 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);8891 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
8878 } else {8892 } 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);
8880 }8900 }
8881 return null;8901 return .none;
8882 }8902 }
88838903
8884 // non-byte-sized element. lower with a loop. something like this:8904 // non-byte-sized element. lower with a loop. something like this:
...@@ -8886,96 +8906,92 @@ pub const FuncGen = struct {...@@ -8886,96 +8906,92 @@ pub const FuncGen = struct {
8886 // entry:8906 // entry:
8887 // ...8907 // ...
8888 // %end_ptr = getelementptr %ptr, %len8908 // %end_ptr = getelementptr %ptr, %len
8889 // br loop8909 // br %loop
8890 // loop:8910 // loop:
8891 // %it_ptr = phi body %next_ptr, entry %ptr8911 // %it_ptr = phi body %next_ptr, entry %ptr
8892 // %end = cmp eq %it_ptr, %end_ptr8912 // %end = cmp eq %it_ptr, %end_ptr
8893 // cond_br %end body, end8913 // br %end, %body, %end
8894 // body:8914 // body:
8895 // store %it_ptr, %value8915 // store %it_ptr, %value
8896 // %next_ptr = getelementptr %it_ptr, 18916 // %next_ptr = getelementptr %it_ptr, 1
8897 // br loop8917 // br %loop
8898 // end:8918 // end:
8899 // ...8919 // ...
8900 const entry_block = self.builder.getInsertBlock();8920 const entry_block = self.wip.cursor.block;
8901 const loop_block = try self.wip.block("InlineMemsetLoop");8921 const loop_block = try self.wip.block(2, "InlineMemsetLoop");
8902 const body_block = try self.wip.block("InlineMemsetBody");8922 const body_block = try self.wip.block(1, "InlineMemsetBody");
8903 const end_block = try self.wip.block("InlineMemsetEnd");8923 const end_block = try self.wip.block(1, "InlineMemsetEnd");
89048924
8905 const usize_ty = try o.lowerType(Type.usize);8925 const usize_ty = try o.lowerType(Type.usize);
8906 const len = switch (ptr_ty.ptrSize(mod)) {8926 const len = switch (ptr_ty.ptrSize(mod)) {
8907 .Slice => self.builder.buildExtractValue(dest_slice, 1, ""),8927 .Slice => try self.wip.extractValue(dest_slice, &.{1}, ""),
8908 .One => (try o.builder.intConst(usize_ty, ptr_ty.childType(mod).arrayLen(mod))).toLlvm(&o.builder),8928 .One => try o.builder.intValue(usize_ty, ptr_ty.childType(mod).arrayLen(mod)),
8909 .Many, .C => unreachable,8929 .Many, .C => unreachable,
8910 };8930 };
8911 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);8931 const elem_llvm_ty = try o.lowerType(elem_ty);
8912 const len_gep = [_]*llvm.Value{len};8932 const end_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, dest_ptr, &.{len}, "");
8913 const end_ptr = self.builder.buildInBoundsGEP(elem_llvm_ty, dest_ptr, &len_gep, len_gep.len, "");8933 _ = try self.wip.br(loop_block);
8914 _ = self.builder.buildBr(loop_block.toLlvm(&self.wip));
89158934
8916 self.wip.cursor = .{ .block = loop_block };8935 self.wip.cursor = .{ .block = loop_block };
8917 self.builder.positionBuilderAtEnd(loop_block.toLlvm(&self.wip));8936 const it_ptr = try self.wip.phi(.ptr, "");
8918 const it_ptr = self.builder.buildPhi(Builder.Type.ptr.toLlvm(&o.builder), "");8937 const end = try self.wip.icmp(.ne, it_ptr.toValue(), end_ptr, "");
8919 const end = self.builder.buildICmp(.NE, it_ptr, end_ptr, "");8938 _ = try self.wip.brCond(end, body_block, end_block);
8920 _ = self.builder.buildCondBr(end, body_block.toLlvm(&self.wip), end_block.toLlvm(&self.wip));
89218939
8922 self.wip.cursor = .{ .block = body_block };8940 self.wip.cursor = .{ .block = body_block };
8923 self.builder.positionBuilderAtEnd(body_block.toLlvm(&self.wip));
8924 const elem_abi_alignment = elem_ty.abiAlignment(mod);8941 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 );
8926 if (isByRef(elem_ty, mod)) {8945 if (isByRef(elem_ty, mod)) {
8927 _ = self.builder.buildMemCpy(8946 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
8928 it_ptr,8947 it_ptr.toValue().toLlvm(&self.wip),
8929 it_ptr_alignment,8948 @intCast(it_ptr_alignment.toByteUnits() orelse 0),
8930 value,8949 value.toLlvm(&self.wip),
8931 elem_abi_alignment,8950 elem_abi_alignment,
8932 (try o.builder.intConst(usize_ty, elem_abi_size)).toLlvm(&o.builder),8951 (try o.builder.intConst(usize_ty, elem_abi_size)).toLlvm(&o.builder),
8933 is_volatile,8952 is_volatile,
8934 );8953 ), &self.wip);
8935 } else {8954 } else _ = try self.wip.store(switch (is_volatile) {
8936 const store_inst = self.builder.buildStore(value, it_ptr);8955 false => .normal,
8937 store_inst.setAlignment(it_ptr_alignment);8956 true => .@"volatile",
8938 store_inst.setVolatile(llvm.Bool.fromBool(is_volatile));8957 }, value, it_ptr.toValue(), it_ptr_alignment);
8939 }8958 const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{
8940 const one_gep = [_]*llvm.Value{8959 try o.builder.intValue(usize_ty, 1),
8941 (try o.builder.intConst(usize_ty, 1)).toLlvm(&o.builder),8960 }, "");
8942 };8961 _ = try self.wip.br(loop_block);
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));
89458962
8946 self.wip.cursor = .{ .block = end_block };8963 self.wip.cursor = .{ .block = end_block };
8947 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));8964 try it_ptr.finish(&.{ next_ptr, dest_ptr }, &.{ body_block, entry_block }, &self.wip);
89488965 return .none;
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;
8954 }8966 }
89558967
8956 fn safeWasmMemset(8968 fn safeWasmMemset(
8957 self: *FuncGen,8969 self: *FuncGen,
8958 dest_ptr: *llvm.Value,8970 dest_ptr: Builder.Value,
8959 fill_byte: *llvm.Value,8971 fill_byte: Builder.Value,
8960 len: *llvm.Value,8972 len: Builder.Value,
8961 dest_ptr_align: u32,8973 dest_ptr_align: Builder.Alignment,
8962 is_volatile: bool,8974 is_volatile: bool,
8963 ) !void {8975 ) !void {
8964 const o = self.dg.object;8976 const o = self.dg.object;
8965 const llvm_usize_ty = try o.lowerType(Type.usize);8977 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);8978 const cond = try self.cmp(len, try o.builder.intValue(llvm_usize_ty, 0), Type.usize, .neq);
8967 const memset_block = try self.wip.block("MemsetTrapSkip");8979 const memset_block = try self.wip.block(1, "MemsetTrapSkip");
8968 const end_block = try self.wip.block("MemsetTrapEnd");8980 const end_block = try self.wip.block(2, "MemsetTrapEnd");
8969 _ = self.builder.buildCondBr(cond, memset_block.toLlvm(&self.wip), end_block.toLlvm(&self.wip));8981 _ = try self.wip.brCond(cond, memset_block, end_block);
8970 self.wip.cursor = .{ .block = memset_block };8982 self.wip.cursor = .{ .block = memset_block };
8971 self.builder.positionBuilderAtEnd(memset_block.toLlvm(&self.wip));8983 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
8972 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);8984 dest_ptr.toLlvm(&self.wip),
8973 _ = self.builder.buildBr(end_block.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);
8974 self.wip.cursor = .{ .block = end_block };8991 self.wip.cursor = .{ .block = end_block };
8975 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));
8976 }8992 }
89778993
8978 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8994 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8979 const o = self.dg.object;8995 const o = self.dg.object;
8980 const mod = o.module;8996 const mod = o.module;
8981 const bin_op = self.air.instructions.items(.data)[inst].bin_op;8997 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -8983,9 +8999,9 @@ pub const FuncGen = struct {...@@ -8983,9 +8999,9 @@ pub const FuncGen = struct {
8983 const dest_ptr_ty = self.typeOf(bin_op.lhs);8999 const dest_ptr_ty = self.typeOf(bin_op.lhs);
8984 const src_slice = try self.resolveInst(bin_op.rhs);9000 const src_slice = try self.resolveInst(bin_op.rhs);
8985 const src_ptr_ty = self.typeOf(bin_op.rhs);9001 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);
8987 const len = try self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty);9003 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);
8989 const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod);9005 const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod);
89909006
8991 // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction.9007 // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction.
...@@ -8997,86 +9013,81 @@ pub const FuncGen = struct {...@@ -8997,86 +9013,81 @@ pub const FuncGen = struct {
8997 std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and9013 std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and
8998 dest_ptr_ty.isSlice(mod))9014 dest_ptr_ty.isSlice(mod))
8999 {9015 {
9000 const llvm_usize_ty = try o.lowerType(Type.usize);9016 const zero_usize = try o.builder.intValue(try o.lowerType(Type.usize), 0);
9001 const cond = try self.cmp(len, (try o.builder.intConst(llvm_usize_ty, 0)).toLlvm(&o.builder), Type.usize, .neq);9017 const cond = try self.cmp(len, zero_usize, Type.usize, .neq);
9002 const memcpy_block = try self.wip.block("MemcpyTrapSkip");9018 const memcpy_block = try self.wip.block(1, "MemcpyTrapSkip");
9003 const end_block = try self.wip.block("MemcpyTrapEnd");9019 const end_block = try self.wip.block(2, "MemcpyTrapEnd");
9004 _ = self.builder.buildCondBr(cond, memcpy_block.toLlvm(&self.wip), end_block.toLlvm(&self.wip));9020 _ = try self.wip.brCond(cond, memcpy_block, end_block);
9005 self.wip.cursor = .{ .block = memcpy_block };9021 self.wip.cursor = .{ .block = memcpy_block };
9006 self.builder.positionBuilderAtEnd(memcpy_block.toLlvm(&self.wip));9022 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
9007 _ = self.builder.buildMemCpy(9023 dest_ptr.toLlvm(&self.wip),
9008 dest_ptr,
9009 dest_ptr_ty.ptrAlignment(mod),9024 dest_ptr_ty.ptrAlignment(mod),
9010 src_ptr,9025 src_ptr.toLlvm(&self.wip),
9011 src_ptr_ty.ptrAlignment(mod),9026 src_ptr_ty.ptrAlignment(mod),
9012 len,9027 len.toLlvm(&self.wip),
9013 is_volatile,9028 is_volatile,
9014 );9029 ), &self.wip);
9015 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));9030 _ = try self.wip.br(end_block);
9016 self.wip.cursor = .{ .block = end_block };9031 self.wip.cursor = .{ .block = end_block };
9017 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));9032 return .none;
9018 return null;
9019 }9033 }
90209034
9021 _ = self.builder.buildMemCpy(9035 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
9022 dest_ptr,9036 dest_ptr.toLlvm(&self.wip),
9023 dest_ptr_ty.ptrAlignment(mod),9037 dest_ptr_ty.ptrAlignment(mod),
9024 src_ptr,9038 src_ptr.toLlvm(&self.wip),
9025 src_ptr_ty.ptrAlignment(mod),9039 src_ptr_ty.ptrAlignment(mod),
9026 len,9040 len.toLlvm(&self.wip),
9027 is_volatile,9041 is_volatile,
9028 );9042 ), &self.wip);
9029 return null;9043 return .none;
9030 }9044 }
90319045
9032 fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9046 fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9033 const o = self.dg.object;9047 const o = self.dg.object;
9034 const mod = o.module;9048 const mod = o.module;
9035 const bin_op = self.air.instructions.items(.data)[inst].bin_op;9049 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
9036 const un_ty = self.typeOf(bin_op.lhs).childType(mod);9050 const un_ty = self.typeOf(bin_op.lhs).childType(mod);
9037 const layout = un_ty.unionGetLayout(mod);9051 const layout = un_ty.unionGetLayout(mod);
9038 if (layout.tag_size == 0) return null;9052 if (layout.tag_size == 0) return .none;
9039 const union_ptr = try self.resolveInst(bin_op.lhs);9053 const union_ptr = try self.resolveInst(bin_op.lhs);
9040 const new_tag = try self.resolveInst(bin_op.rhs);9054 const new_tag = try self.resolveInst(bin_op.rhs);
9041 if (layout.payload_size == 0) {9055 if (layout.payload_size == 0) {
9042 // TODO alignment on this store9056 // TODO alignment on this store
9043 _ = self.builder.buildStore(new_tag, union_ptr);9057 _ = try self.wip.store(.normal, new_tag, union_ptr, .default);
9044 return null;9058 return .none;
9045 }9059 }
9046 const un_llvm_ty = (try o.lowerType(un_ty)).toLlvm(&o.builder);
9047 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);9060 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, "");
9049 // TODO alignment on this store9062 // TODO alignment on this store
9050 _ = self.builder.buildStore(new_tag, tag_field_ptr);9063 _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default);
9051 return null;9064 return .none;
9052 }9065 }
90539066
9054 fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9067 fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9055 const o = self.dg.object;9068 const o = self.dg.object;
9056 const mod = o.module;9069 const mod = o.module;
9057 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9070 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
9058 const un_ty = self.typeOf(ty_op.operand);9071 const un_ty = self.typeOf(ty_op.operand);
9059 const layout = un_ty.unionGetLayout(mod);9072 const layout = un_ty.unionGetLayout(mod);
9060 if (layout.tag_size == 0) return null;9073 if (layout.tag_size == 0) return .none;
9061 const union_handle = try self.resolveInst(ty_op.operand);9074 const union_handle = try self.resolveInst(ty_op.operand);
9062 if (isByRef(un_ty, mod)) {9075 if (isByRef(un_ty, mod)) {
9063 const llvm_un_ty = (try o.lowerType(un_ty)).toLlvm(&o.builder);9076 const llvm_un_ty = try o.lowerType(un_ty);
9064 if (layout.payload_size == 0) {9077 if (layout.payload_size == 0)
9065 return self.builder.buildLoad(llvm_un_ty, union_handle, "");9078 return self.wip.load(.normal, llvm_un_ty, union_handle, .default, "");
9066 }
9067 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);9079 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, "");9080 const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, "");
9069 return self.builder.buildLoad(llvm_un_ty.structGetTypeAtIndex(tag_index), tag_field_ptr, "");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, "");
9070 } else {9083 } else {
9071 if (layout.payload_size == 0) {9084 if (layout.payload_size == 0) return union_handle;
9072 return union_handle;
9073 }
9074 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);9085 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}, "");
9076 }9087 }
9077 }9088 }
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 {
9080 const un_op = self.air.instructions.items(.data)[inst].un_op;9091 const un_op = self.air.instructions.items(.data)[inst].un_op;
9081 const operand = try self.resolveInst(un_op);9092 const operand = try self.resolveInst(un_op);
9082 const operand_ty = self.typeOf(un_op);9093 const operand_ty = self.typeOf(un_op);
...@@ -9084,7 +9095,7 @@ pub const FuncGen = struct {...@@ -9084,7 +9095,7 @@ pub const FuncGen = struct {
9084 return self.buildFloatOp(op, operand_ty, 1, .{operand});9095 return self.buildFloatOp(op, operand_ty, 1, .{operand});
9085 }9096 }
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 {
9088 self.builder.setFastMath(want_fast_math);9099 self.builder.setFastMath(want_fast_math);
90899100
9090 const un_op = self.air.instructions.items(.data)[inst].un_op;9101 const un_op = self.air.instructions.items(.data)[inst].un_op;
...@@ -9094,57 +9105,64 @@ pub const FuncGen = struct {...@@ -9094,57 +9105,64 @@ pub const FuncGen = struct {
9094 return self.buildFloatOp(.neg, operand_ty, 1, .{operand});9105 return self.buildFloatOp(.neg, operand_ty, 1, .{operand});
9095 }9106 }
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 {
9098 const o = self.dg.object;9109 const o = self.dg.object;
9099 const mod = o.module;
9100 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9110 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
9101 const operand_ty = self.typeOf(ty_op.operand);9111 const operand_ty = self.typeOf(ty_op.operand);
9102 const operand = try self.resolveInst(ty_op.operand);9112 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) };9118 const params = [_]*llvm.Value{
9107 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");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 );
9108 const result_ty = self.typeOfIndex(inst);9134 const result_ty = self.typeOfIndex(inst);
9109 const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder);9135 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
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 }
9120 }9136 }
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 {
9123 const o = self.dg.object;9139 const o = self.dg.object;
9124 const mod = o.module;
9125 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9140 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
9126 const operand_ty = self.typeOf(ty_op.operand);9141 const operand_ty = self.typeOf(ty_op.operand);
9127 const operand = try self.resolveInst(ty_op.operand);9142 const operand = try self.resolveInst(ty_op.operand);
91289143
9129 const params = [_]*llvm.Value{operand};9144 const llvm_operand_ty = try o.lowerType(operand_ty);
9130 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{try o.lowerType(operand_ty)});9145 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
91319146 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
9132 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");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 );
9133 const result_ty = self.typeOfIndex(inst);9161 const result_ty = self.typeOfIndex(inst);
9134 const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder);9162 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
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 }
9145 }9163 }
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 {
9148 const o = self.dg.object;9166 const o = self.dg.object;
9149 const mod = o.module;9167 const mod = o.module;
9150 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9168 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -9153,7 +9171,7 @@ pub const FuncGen = struct {...@@ -9153,7 +9171,7 @@ pub const FuncGen = struct {
9153 assert(bits % 8 == 0);9171 assert(bits % 8 == 0);
91549172
9155 var operand = try self.resolveInst(ty_op.operand);9173 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
9158 if (bits % 16 == 8) {9176 if (bits % 16 == 8) {
9159 // If not an even byte-multiple, we need zero-extend + shift-left 1 byte9177 // If not an even byte-multiple, we need zero-extend + shift-left 1 byte
...@@ -9161,35 +9179,39 @@ pub const FuncGen = struct {...@@ -9161,35 +9179,39 @@ pub const FuncGen = struct {
9161 const scalar_ty = try o.builder.intType(@intCast(bits + 8));9179 const scalar_ty = try o.builder.intType(@intCast(bits + 8));
9162 if (operand_ty.zigTypeTag(mod) == .Vector) {9180 if (operand_ty.zigTypeTag(mod) == .Vector) {
9163 const vec_len = operand_ty.vectorLen(mod);9181 const vec_len = operand_ty.vectorLen(mod);
9164 operand_llvm_ty = try o.builder.vectorType(.normal, vec_len, scalar_ty);9182 llvm_operand_ty = try o.builder.vectorType(.normal, vec_len, scalar_ty);
9165 } else operand_llvm_ty = scalar_ty;9183 } else llvm_operand_ty = scalar_ty;
91669184
9167 const shift_amt =9185 const shift_amt =
9168 try o.builder.splatConst(operand_llvm_ty, try o.builder.intConst(scalar_ty, 8));9186 try o.builder.splatValue(llvm_operand_ty, try o.builder.intConst(scalar_ty, 8));
9169 const extended = self.builder.buildZExt(operand, operand_llvm_ty.toLlvm(&o.builder), "");9187 const extended = try self.wip.cast(.zext, operand, llvm_operand_ty, "");
9170 operand = self.builder.buildShl(extended, shift_amt.toLlvm(&o.builder), "");9188 operand = try self.wip.bin(.shl, extended, shift_amt, "");
91719189
9172 bits = bits + 8;9190 bits = bits + 8;
9173 }9191 }
91749192
9175 const params = [_]*llvm.Value{operand};9193 const llvm_fn_ty = try o.builder.fnType(llvm_operand_ty, &.{llvm_operand_ty}, .normal);
9176 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});9194 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{llvm_operand_ty});
91779195
9178 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");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
9180 const result_ty = self.typeOfIndex(inst);9210 const result_ty = self.typeOfIndex(inst);
9181 const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder);9211 return self.wip.conv(.unsigned, wrong_size_result, try o.lowerType(result_ty), "");
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 }
9190 }9212 }
91919213
9192 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9214 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9193 const o = self.dg.object;9215 const o = self.dg.object;
9194 const mod = o.module;9216 const mod = o.module;
9195 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9217 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -9197,58 +9219,60 @@ pub const FuncGen = struct {...@@ -9197,58 +9219,60 @@ pub const FuncGen = struct {
9197 const error_set_ty = self.air.getRefType(ty_op.ty);9219 const error_set_ty = self.air.getRefType(ty_op.ty);
91989220
9199 const names = error_set_ty.errorSetNames(mod);9221 const names = error_set_ty.errorSetNames(mod);
9200 const valid_block = try self.wip.block("Valid");9222 const valid_block = try self.wip.block(@intCast(names.len), "Valid");
9201 const invalid_block = try self.wip.block("Invalid");9223 const invalid_block = try self.wip.block(1, "Invalid");
9202 const end_block = try self.wip.block("End");9224 const end_block = try self.wip.block(2, "End");
9203 const switch_instr = self.builder.buildSwitch(operand, invalid_block.toLlvm(&self.wip), @intCast(names.len));9225 var wip_switch = try self.wip.@"switch"(operand, invalid_block, @intCast(names.len));
9226 defer wip_switch.finish(&self.wip);
92049227
9205 for (names) |name| {9228 for (names) |name| {
9206 const err_int = mod.global_error_set.getIndex(name).?;9229 const err_int = mod.global_error_set.getIndex(name).?;
9207 const this_tag_int_value =9230 const this_tag_int_value = try o.builder.intConst(Builder.Type.err_int, err_int);
9208 try o.lowerValue((try mod.intValue(Type.err_int, err_int)).toIntern());9231 try wip_switch.addCase(this_tag_int_value, valid_block, &self.wip);
9209 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), valid_block.toLlvm(&self.wip));
9210 }9232 }
9211 self.wip.cursor = .{ .block = valid_block };9233 self.wip.cursor = .{ .block = valid_block };
9212 self.builder.positionBuilderAtEnd(valid_block.toLlvm(&self.wip));9234 _ = try self.wip.br(end_block);
9213 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
92149235
9215 self.wip.cursor = .{ .block = invalid_block };9236 self.wip.cursor = .{ .block = invalid_block };
9216 self.builder.positionBuilderAtEnd(invalid_block.toLlvm(&self.wip));9237 _ = try self.wip.br(end_block);
9217 _ = self.builder.buildBr(end_block.toLlvm(&self.wip));
92189238
9219 self.wip.cursor = .{ .block = end_block };9239 self.wip.cursor = .{ .block = end_block };
9220 self.builder.positionBuilderAtEnd(end_block.toLlvm(&self.wip));9240 const phi = try self.wip.phi(.i1, "");
92219241 try phi.finish(
9222 const incoming_values: [2]*llvm.Value = .{9242 &.{ Builder.Constant.true.toValue(), Builder.Constant.false.toValue() },
9223 Builder.Constant.true.toLlvm(&o.builder),9243 &.{ valid_block, invalid_block },
9224 Builder.Constant.false.toLlvm(&o.builder),9244 &self.wip,
9225 };9245 );
9226 const incoming_blocks: [2]*llvm.BasicBlock = .{9246 return phi.toValue();
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;
9232 }9247 }
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;
9235 const un_op = self.air.instructions.items(.data)[inst].un_op;9251 const un_op = self.air.instructions.items(.data)[inst].un_op;
9236 const operand = try self.resolveInst(un_op);9252 const operand = try self.resolveInst(un_op);
9237 const enum_ty = self.typeOf(un_op);9253 const enum_ty = self.typeOf(un_op);
92389254
9239 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);9255 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
9240 const params = [_]*llvm.Value{operand};9256 const params = [_]*llvm.Value{operand.toLlvm(&self.wip)};
9241 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");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);
9242 }9266 }
92439267
9244 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {9268 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
9245 const o = self.dg.object;9269 const o = self.dg.object;
9246 const mod = o.module;9270 const mod = o.module;
9247 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;9271 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
92489272
9249 // TODO: detect when the type changes and re-emit this function.9273 // TODO: detect when the type changes and re-emit this function.
9250 const gop = try o.named_enum_map.getOrPut(o.gpa, enum_type.decl);9274 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.*;
9252 errdefer assert(o.named_enum_map.remove(enum_type.decl));9276 errdefer assert(o.named_enum_map.remove(enum_type.decl));
92539277
9254 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);9278 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
...@@ -9256,9 +9280,9 @@ pub const FuncGen = struct {...@@ -9256,9 +9280,9 @@ pub const FuncGen = struct {
9256 fqn.fmt(&mod.intern_pool),9280 fqn.fmt(&mod.intern_pool),
9257 });9281 });
92589282
9259 const fn_type = try o.builder.fnType(.i1, &.{try o.lowerType(9283 const fn_type = try o.builder.fnType(.i1, &.{
9260 enum_type.tag_ty.toType(),9284 try o.lowerType(enum_type.tag_ty.toType()),
9261 )}, .normal);9285 }, .normal);
9262 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));9286 const fn_val = o.llvm_module.addFunction(llvm_fn_name.toSlice(&o.builder).?, fn_type.toLlvm(&o.builder));
9263 fn_val.setLinkage(.Internal);9287 fn_val.setLinkage(.Internal);
9264 fn_val.setFunctionCallConv(.Fast);9288 fn_val.setFunctionCallConv(.Fast);
...@@ -9277,63 +9301,63 @@ pub const FuncGen = struct {...@@ -9277,63 +9301,63 @@ pub const FuncGen = struct {
9277 try o.builder.functions.append(self.gpa, function);9301 try o.builder.functions.append(self.gpa, function);
9278 gop.value_ptr.* = global.kind.function;9302 gop.value_ptr.* = global.kind.function;
92799303
9280 const prev_block = self.builder.getInsertBlock();9304 var wip = try Builder.WipFunction.init(&o.builder, global.kind.function);
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);
9290 defer wip.deinit();9305 defer wip.deinit();
9306 wip.cursor = .{ .block = try wip.block(0, "Entry") };
92919307
9292 const entry_block = try wip.block("Entry");9308 const named_block = try wip.block(@intCast(enum_type.names.len), "Named");
9293 wip.cursor = .{ .block = entry_block };9309 const unnamed_block = try wip.block(1, "Unnamed");
9294 self.builder.positionBuilderAtEnd(entry_block.toLlvm(&wip));9310 const tag_int_value = wip.arg(0);
9295 self.builder.clearCurrentDebugLocation();9311 var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(enum_type.names.len));
92969312 defer wip_switch.finish(&wip);
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));
93019313
9302 for (0..enum_type.names.len) |field_index| {9314 for (0..enum_type.names.len) |field_index| {
9303 const this_tag_int_value =9315 const this_tag_int_value = try o.lowerValue(
9304 try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern());9316 (try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
9305 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), named_block.toLlvm(&wip));9317 );
9318 try wip_switch.addCase(this_tag_int_value, named_block, &wip);
9306 }9319 }
9307 wip.cursor = .{ .block = named_block };9320 wip.cursor = .{ .block = named_block };
9308 self.builder.positionBuilderAtEnd(named_block.toLlvm(&wip));9321 _ = try wip.ret(Builder.Constant.true.toValue());
9309 _ = self.builder.buildRet(Builder.Constant.true.toLlvm(&o.builder));
93109322
9311 wip.cursor = .{ .block = unnamed_block };9323 wip.cursor = .{ .block = unnamed_block };
9312 self.builder.positionBuilderAtEnd(unnamed_block.toLlvm(&wip));9324 _ = try wip.ret(Builder.Constant.false.toValue());
9313 _ = self.builder.buildRet(Builder.Constant.false.toLlvm(&o.builder));
93149325
9315 try wip.finish();9326 try wip.finish();
9316 return fn_val;9327 return global.kind.function;
9317 }9328 }
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;
9320 const un_op = self.air.instructions.items(.data)[inst].un_op;9332 const un_op = self.air.instructions.items(.data)[inst].un_op;
9321 const operand = try self.resolveInst(un_op);9333 const operand = try self.resolveInst(un_op);
9322 const enum_ty = self.typeOf(un_op);9334 const enum_ty = self.typeOf(un_op);
93239335
9324 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);9336 const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
9325 const params = [_]*llvm.Value{operand};9337 const llvm_fn_ty = llvm_fn.typeOf(&o.builder);
9326 return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");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 );
9327 }9351 }
93289352
9329 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value {9353 fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
9330 const o = self.dg.object;9354 const o = self.dg.object;
9331 const mod = o.module;9355 const mod = o.module;
9332 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;9356 const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
93339357
9334 // TODO: detect when the type changes and re-emit this function.9358 // TODO: detect when the type changes and re-emit this function.
9335 const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);9359 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;
9337 errdefer assert(o.decl_map.remove(enum_type.decl));9361 errdefer assert(o.decl_map.remove(enum_type.decl));
93389362
9339 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);9363 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
...@@ -9362,26 +9386,15 @@ pub const FuncGen = struct {...@@ -9362,26 +9386,15 @@ pub const FuncGen = struct {
9362 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);9386 gop.value_ptr.* = try o.builder.addGlobal(llvm_fn_name, global);
9363 try o.builder.functions.append(self.gpa, function);9387 try o.builder.functions.append(self.gpa, function);
93649388
9365 const prev_block = self.builder.getInsertBlock();9389 var wip = try Builder.WipFunction.init(&o.builder, global.kind.function);
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);
9375 defer wip.deinit();9390 defer wip.deinit();
9391 wip.cursor = .{ .block = try wip.block(0, "Entry") };
93769392
9377 const entry_block = try wip.block("Entry");9393 const bad_value_block = try wip.block(1, "BadValue");
9378 wip.cursor = .{ .block = entry_block };9394 const tag_int_value = wip.arg(0);
9379 self.builder.positionBuilderAtEnd(entry_block.toLlvm(&wip));9395 var wip_switch =
9380 self.builder.clearCurrentDebugLocation();9396 try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len));
93819397 defer wip_switch.finish(&wip);
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));
93859398
9386 for (enum_type.names, 0..) |name_ip, field_index| {9399 for (enum_type.names, 0..) |name_ip, field_index| {
9387 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_ip));9400 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_ip));
...@@ -9398,46 +9411,45 @@ pub const FuncGen = struct {...@@ -9398,46 +9411,45 @@ pub const FuncGen = struct {
9398 .linkage = .private,9411 .linkage = .private,
9399 .unnamed_addr = .unnamed_addr,9412 .unnamed_addr = .unnamed_addr,
9400 .type = str_ty,9413 .type = str_ty,
9401 .alignment = comptime Builder.Alignment.fromByteUnits(1),
9402 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },9414 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
9403 };9415 };
9404 var str_variable = Builder.Variable{9416 var str_variable = Builder.Variable{
9405 .global = @enumFromInt(o.builder.globals.count()),9417 .global = @enumFromInt(o.builder.globals.count()),
9406 .mutability = .constant,9418 .mutability = .constant,
9407 .init = str_init,9419 .init = str_init,
9420 .alignment = comptime Builder.Alignment.fromByteUnits(1),
9408 };9421 };
9409 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);9422 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);
9410 const global_index = try o.builder.addGlobal(.empty, str_global);9423 const global_index = try o.builder.addGlobal(.empty, str_global);
9411 try o.builder.variables.append(o.gpa, str_variable);9424 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, &.{
9414 global_index.toConst(),9427 global_index.toConst(),
9415 try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),9428 try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),
9416 });9429 });
94179430
9418 const return_block = try wip.block("Name");9431 const return_block = try wip.block(1, "Name");
9419 const this_tag_int_value =9432 const this_tag_int_value = try o.lowerValue(
9420 try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern());9433 (try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
9421 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), return_block.toLlvm(&wip));9434 );
9435 try wip_switch.addCase(this_tag_int_value, return_block, &wip);
94229436
9423 wip.cursor = .{ .block = return_block };9437 wip.cursor = .{ .block = return_block };
9424 self.builder.positionBuilderAtEnd(return_block.toLlvm(&wip));9438 _ = try wip.ret(slice_val);
9425 _ = self.builder.buildRet(slice_val.toLlvm(&o.builder));
9426 }9439 }
94279440
9428 wip.cursor = .{ .block = bad_value_block };9441 wip.cursor = .{ .block = bad_value_block };
9429 self.builder.positionBuilderAtEnd(bad_value_block.toLlvm(&wip));9442 _ = try wip.@"unreachable"();
9430 _ = self.builder.buildUnreachable();
94319443
9432 try wip.finish();9444 try wip.finish();
9433 return fn_val;9445 return global.kind.function;
9434 }9446 }
94359447
9436 fn getCmpLtErrorsLenFunction(self: *FuncGen) !*llvm.Value {9448 fn getCmpLtErrorsLenFunction(self: *FuncGen) !Builder.Function.Index {
9437 const o = self.dg.object;9449 const o = self.dg.object;
94389450
9439 const name = try o.builder.string(lt_errors_fn_name);9451 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
9442 // Function signature: fn (anyerror) bool9454 // Function signature: fn (anyerror) bool
94439455
...@@ -9458,47 +9470,45 @@ pub const FuncGen = struct {...@@ -9458,47 +9470,45 @@ pub const FuncGen = struct {
9458 };9470 };
94599471
9460 try o.builder.llvm.globals.append(self.gpa, llvm_fn);9472 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);
9462 try o.builder.functions.append(self.gpa, function);9474 try o.builder.functions.append(self.gpa, function);
9463 return global_index.toLlvm(&o.builder);9475 return global.kind.function;
9464 }9476 }
94659477
9466 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9478 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9467 const o = self.dg.object;9479 const o = self.dg.object;
9468 const un_op = self.air.instructions.items(.data)[inst].un_op;9480 const un_op = self.air.instructions.items(.data)[inst].un_op;
9469 const operand = try self.resolveInst(un_op);9481 const operand = try self.resolveInst(un_op);
9470 const slice_ty = self.typeOfIndex(inst);9482 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
9473 const error_name_table_ptr = try self.getErrorNameTable();9485 const error_name_table_ptr = try self.getErrorNameTable();
9474 const ptr_slice_llvm_ty = self.context.pointerType(0);9486 const error_name_table =
9475 const error_name_table = self.builder.buildLoad(ptr_slice_llvm_ty, error_name_table_ptr.toLlvm(&o.builder), "");9487 try self.wip.load(.normal, .ptr, error_name_table_ptr.toValue(&o.builder), .default, "");
9476 const indices = [_]*llvm.Value{operand};9488 const error_name_ptr =
9477 const error_name_ptr = self.builder.buildInBoundsGEP(slice_llvm_ty, error_name_table, &indices, indices.len, "");9489 try self.wip.gep(.inbounds, slice_llvm_ty, error_name_table, &.{operand}, "");
9478 return self.builder.buildLoad(slice_llvm_ty, error_name_ptr, "");9490 return self.wip.load(.normal, slice_llvm_ty, error_name_ptr, .default, "");
9479 }9491 }
94809492
9481 fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9493 fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9482 const o = self.dg.object;9494 const o = self.dg.object;
9483 const mod = o.module;
9484 const ty_op = self.air.instructions.items(.data)[inst].ty_op;9495 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
9485 const scalar = try self.resolveInst(ty_op.operand);9496 const scalar = try self.resolveInst(ty_op.operand);
9486 const vector_ty = self.typeOfIndex(inst);9497 const vector_ty = self.typeOfIndex(inst);
9487 const len = vector_ty.vectorLen(mod);9498 return self.wip.splatVector(try o.lowerType(vector_ty), scalar, "");
9488 return self.builder.buildVectorSplat(len, scalar, "");
9489 }9499 }
94909500
9491 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9501 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9492 const pl_op = self.air.instructions.items(.data)[inst].pl_op;9502 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
9493 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;9503 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
9494 const pred = try self.resolveInst(pl_op.operand);9504 const pred = try self.resolveInst(pl_op.operand);
9495 const a = try self.resolveInst(extra.lhs);9505 const a = try self.resolveInst(extra.lhs);
9496 const b = try self.resolveInst(extra.rhs);9506 const b = try self.resolveInst(extra.rhs);
94979507
9498 return self.builder.buildSelect(pred, a, b, "");9508 return self.wip.select(pred, a, b, "");
9499 }9509 }
95009510
9501 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9511 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9502 const o = self.dg.object;9512 const o = self.dg.object;
9503 const mod = o.module;9513 const mod = o.module;
9504 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;9514 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -9528,11 +9538,11 @@ pub const FuncGen = struct {...@@ -9528,11 +9538,11 @@ pub const FuncGen = struct {
9528 }9538 }
9529 }9539 }
95309540
9531 const llvm_mask_value = try o.builder.vectorConst(9541 const llvm_mask_value = try o.builder.vectorValue(
9532 try o.builder.vectorType(.normal, mask_len, .i32),9542 try o.builder.vectorType(.normal, mask_len, .i32),
9533 values,9543 values,
9534 );9544 );
9535 return self.builder.buildShuffleVector(a, b, llvm_mask_value.toLlvm(&o.builder), "");9545 return self.wip.shuffleVector(a, b, llvm_mask_value, "");
9536 }9546 }
95379547
9538 /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.9548 /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.
...@@ -9549,61 +9559,69 @@ pub const FuncGen = struct {...@@ -9549,61 +9559,69 @@ pub const FuncGen = struct {
9549 ///9559 ///
9550 fn buildReducedCall(9560 fn buildReducedCall(
9551 self: *FuncGen,9561 self: *FuncGen,
9552 llvm_fn: *llvm.Value,9562 llvm_fn: Builder.Function.Index,
9553 operand_vector: *llvm.Value,9563 operand_vector: Builder.Value,
9554 vector_len: usize,9564 vector_len: usize,
9555 accum_init: *llvm.Value,9565 accum_init: Builder.Value,
9556 ) !*llvm.Value {9566 ) !Builder.Value {
9557 const o = self.dg.object;9567 const o = self.dg.object;
9558 const usize_ty = try o.lowerType(Type.usize);9568 const usize_ty = try o.lowerType(Type.usize);
9559 const llvm_vector_len = try o.builder.intConst(usize_ty, vector_len);9569 const llvm_vector_len = try o.builder.intValue(usize_ty, vector_len);
9560 const llvm_result_ty = accum_init.typeOf();9570 const llvm_result_ty = accum_init.typeOfWip(&self.wip);
95619571
9562 // Allocate and initialize our mutable variables9572 // Allocate and initialize our mutable variables
9563 const i_ptr = try self.buildAlloca(usize_ty.toLlvm(&o.builder), null);9573 const i_ptr = try self.buildAlloca(usize_ty, .default);
9564 _ = self.builder.buildStore((try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder), i_ptr);9574 _ = try self.wip.store(.normal, try o.builder.intValue(usize_ty, 0), i_ptr, .default);
9565 const accum_ptr = try self.buildAlloca(llvm_result_ty, null);9575 const accum_ptr = try self.buildAlloca(llvm_result_ty, .default);
9566 _ = self.builder.buildStore(accum_init, accum_ptr);9576 _ = try self.wip.store(.normal, accum_init, accum_ptr, .default);
95679577
9568 // Setup the loop9578 // Setup the loop
9569 const loop = try self.wip.block("ReduceLoop");9579 const loop = try self.wip.block(2, "ReduceLoop");
9570 const loop_exit = try self.wip.block("AfterReduce");9580 const loop_exit = try self.wip.block(1, "AfterReduce");
9571 _ = self.builder.buildBr(loop.toLlvm(&self.wip));9581 _ = try self.wip.br(loop);
9572 {9582 {
9573 self.wip.cursor = .{ .block = loop };9583 self.wip.cursor = .{ .block = loop };
9574 self.builder.positionBuilderAtEnd(loop.toLlvm(&self.wip));
95759584
9576 // while (i < vec.len)9585 // while (i < vec.len)
9577 const i = self.builder.buildLoad(usize_ty.toLlvm(&o.builder), i_ptr, "");9586 const i = try self.wip.load(.normal, usize_ty, i_ptr, .default, "");
9578 const cond = self.builder.buildICmp(.ULT, i, llvm_vector_len.toLlvm(&o.builder), "");9587 const cond = try self.wip.icmp(.ult, i, llvm_vector_len, "");
9579 const loop_then = try self.wip.block("ReduceLoopThen");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
9583 {9592 {
9584 self.wip.cursor = .{ .block = loop_then };9593 self.wip.cursor = .{ .block = loop_then };
9585 self.builder.positionBuilderAtEnd(loop_then.toLlvm(&self.wip));
95869594
9587 // accum = f(accum, vec[i]);9595 // accum = f(accum, vec[i]);
9588 const accum = self.builder.buildLoad(llvm_result_ty, accum_ptr, "");9596 const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
9589 const element = self.builder.buildExtractElement(operand_vector, i, "");9597 const element = try self.wip.extractElement(operand_vector, i, "");
9590 const params = [2]*llvm.Value{ accum, element };9598 const params = [2]*llvm.Value{ accum.toLlvm(&self.wip), element.toLlvm(&self.wip) };
9591 const new_accum = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .C, .Auto, "");9599 const new_accum = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
9592 _ = self.builder.buildStore(new_accum, accum_ptr);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
9594 // i += 19613 // i += 1
9595 const new_i = self.builder.buildAdd(i, (try o.builder.intConst(usize_ty, 1)).toLlvm(&o.builder), "");9614 const new_i = try self.wip.bin(.add, i, try o.builder.intValue(usize_ty, 1), "");
9596 _ = self.builder.buildStore(new_i, i_ptr);9615 _ = try self.wip.store(.normal, new_i, i_ptr, .default);
9597 _ = self.builder.buildBr(loop.toLlvm(&self.wip));9616 _ = try self.wip.br(loop);
9598 }9617 }
9599 }9618 }
96009619
9601 self.wip.cursor = .{ .block = loop_exit };9620 self.wip.cursor = .{ .block = loop_exit };
9602 self.builder.positionBuilderAtEnd(loop_exit.toLlvm(&self.wip));9621 return self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, "");
9603 return self.builder.buildLoad(llvm_result_ty, accum_ptr, "");
9604 }9622 }
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 {
9607 self.builder.setFastMath(want_fast_math);9625 self.builder.setFastMath(want_fast_math);
9608 const o = self.dg.object;9626 const o = self.dg.object;
9609 const mod = o.module;9627 const mod = o.module;
...@@ -9613,40 +9631,70 @@ pub const FuncGen = struct {...@@ -9613,40 +9631,70 @@ pub const FuncGen = struct {
9613 const operand = try self.resolveInst(reduce.operand);9631 const operand = try self.resolveInst(reduce.operand);
9614 const operand_ty = self.typeOf(reduce.operand);9632 const operand_ty = self.typeOf(reduce.operand);
9615 const scalar_ty = self.typeOfIndex(inst);9633 const scalar_ty = self.typeOfIndex(inst);
9634 const llvm_scalar_ty = try o.lowerType(scalar_ty);
96169635
9617 switch (reduce.operation) {9636 switch (reduce.operation) {
9618 .And => return self.builder.buildAndReduce(operand),9637 .And => return (try self.wip.unimplemented(llvm_scalar_ty, ""))
9619 .Or => return self.builder.buildOrReduce(operand),9638 .finish(self.builder.buildAndReduce(operand.toLlvm(&self.wip)), &self.wip),
9620 .Xor => return self.builder.buildXorReduce(operand),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),
9621 .Min => switch (scalar_ty.zigTypeTag(mod)) {9643 .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 ),
9623 .Float => if (intrinsicsAllowed(scalar_ty, target)) {9651 .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);
9625 },9654 },
9626 else => unreachable,9655 else => unreachable,
9627 },9656 },
9628 .Max => switch (scalar_ty.zigTypeTag(mod)) {9657 .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 ),
9630 .Float => if (intrinsicsAllowed(scalar_ty, target)) {9665 .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);
9632 },9668 },
9633 else => unreachable,9669 else => unreachable,
9634 },9670 },
9635 .Add => switch (scalar_ty.zigTypeTag(mod)) {9671 .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),
9637 .Float => if (intrinsicsAllowed(scalar_ty, target)) {9674 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9638 const scalar_llvm_ty = try o.lowerType(scalar_ty);9675 const neutral_value = try o.builder.fpConst(llvm_scalar_ty, -0.0);
9639 const neutral_value = try o.builder.fpConst(scalar_llvm_ty, -0.0);9676 return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9640 return self.builder.buildFPAddReduce(neutral_value.toLlvm(&o.builder), operand);9677 self.builder.buildFPAddReduce(
9678 neutral_value.toLlvm(&o.builder),
9679 operand.toLlvm(&self.wip),
9680 ),
9681 &self.wip,
9682 );
9641 },9683 },
9642 else => unreachable,9684 else => unreachable,
9643 },9685 },
9644 .Mul => switch (scalar_ty.zigTypeTag(mod)) {9686 .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),
9646 .Float => if (intrinsicsAllowed(scalar_ty, target)) {9689 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9647 const scalar_llvm_ty = try o.lowerType(scalar_ty);9690 const neutral_value = try o.builder.fpConst(llvm_scalar_ty, 1.0);
9648 const neutral_value = try o.builder.fpConst(scalar_llvm_ty, 1.0);9691 return (try self.wip.unimplemented(llvm_scalar_ty, "")).finish(
9649 return self.builder.buildFPMulReduce(neutral_value.toLlvm(&o.builder), operand);9692 self.builder.buildFPMulReduce(
9693 neutral_value.toLlvm(&o.builder),
9694 operand.toLlvm(&self.wip),
9695 ),
9696 &self.wip,
9697 );
9650 },9698 },
9651 else => unreachable,9699 else => unreachable,
9652 },9700 },
...@@ -9671,34 +9719,54 @@ pub const FuncGen = struct {...@@ -9671,34 +9719,54 @@ pub const FuncGen = struct {
9671 else => unreachable,9719 else => unreachable,
9672 };9720 };
96739721
9674 const param_llvm_ty = try o.lowerType(scalar_ty);9722 const libc_fn =
9675 const libc_fn = try self.getLibcFunction(fn_name, &(.{param_llvm_ty} ** 2), param_llvm_ty);9723 try self.getLibcFunction(fn_name, &.{ llvm_scalar_ty, llvm_scalar_ty }, llvm_scalar_ty);
9676 const init_value = try o.lowerValue((try mod.floatValue(scalar_ty, switch (reduce.operation) {9724 const init_val = switch (llvm_scalar_ty) {
9677 .Min => std.math.nan(f32),9725 .i16 => try o.builder.intValue(.i16, @as(i16, @bitCast(
9678 .Max => std.math.nan(f32),9726 @as(f16, switch (reduce.operation) {
9679 .Add => -0.0,9727 .Min, .Max => std.math.nan(f16),
9680 .Mul => 1.0,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 ))),
9681 else => unreachable,9749 else => unreachable,
9682 })).toIntern());9750 };
9683 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value.toLlvm(&o.builder));9751 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_val);
9684 }9752 }
96859753
9686 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9754 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9687 const o = self.dg.object;9755 const o = self.dg.object;
9688 const mod = o.module;9756 const mod = o.module;
9689 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;9757 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
9690 const result_ty = self.typeOfIndex(inst);9758 const result_ty = self.typeOfIndex(inst);
9691 const len: usize = @intCast(result_ty.arrayLen(mod));9759 const len: usize = @intCast(result_ty.arrayLen(mod));
9692 const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]);9760 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
9695 switch (result_ty.zigTypeTag(mod)) {9763 switch (result_ty.zigTypeTag(mod)) {
9696 .Vector => {9764 .Vector => {
9697 var vector = llvm_result_ty.getUndef();9765 var vector = try o.builder.poisonValue(llvm_result_ty);
9698 for (elements, 0..) |elem, i| {9766 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);
9700 const llvm_elem = try self.resolveInst(elem);9768 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, "");
9702 }9770 }
9703 return vector;9771 return vector;
9704 },9772 },
...@@ -9710,7 +9778,7 @@ pub const FuncGen = struct {...@@ -9710,7 +9778,7 @@ pub const FuncGen = struct {
9710 const int_ty = try o.builder.intType(@intCast(big_bits));9778 const int_ty = try o.builder.intType(@intCast(big_bits));
9711 const fields = struct_obj.fields.values();9779 const fields = struct_obj.fields.values();
9712 comptime assert(Type.packed_struct_layout_version == 2);9780 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);
9714 var running_bits: u16 = 0;9782 var running_bits: u16 = 0;
9715 for (elements, 0..) |elem, i| {9783 for (elements, 0..) |elem, i| {
9716 const field = fields[i];9784 const field = fields[i];
...@@ -9718,18 +9786,18 @@ pub const FuncGen = struct {...@@ -9718,18 +9786,18 @@ pub const FuncGen = struct {
97189786
9719 const non_int_val = try self.resolveInst(elem);9787 const non_int_val = try self.resolveInst(elem);
9720 const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod));9788 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);
9722 const small_int_val = if (field.ty.isPtrAtRuntime(mod))9790 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, "")
9724 else9792 else
9725 self.builder.buildBitCast(non_int_val, small_int_ty, "");9793 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
9726 const shift_rhs = try o.builder.intConst(int_ty, running_bits);9794 const shift_rhs = try o.builder.intValue(int_ty, running_bits);
9727 // If the field is as large as the entire packed struct, this9795 // If the field is as large as the entire packed struct, this
9728 // zext would go from, e.g. i16 to i16. This is legal with9796 // zext would go from, e.g. i16 to i16. This is legal with
9729 // constZExtOrBitCast but not legal with constZExt.9797 // constZExtOrBitCast but not legal with constZExt.
9730 const extended_int_val = self.builder.buildZExtOrBitCast(small_int_val, int_ty.toLlvm(&o.builder), "");9798 const extended_int_val = try self.wip.conv(.unsigned, small_int_val, int_ty, "");
9731 const shifted = self.builder.buildShl(extended_int_val, shift_rhs.toLlvm(&o.builder), "");9799 const shifted = try self.wip.bin(.shl, extended_int_val, shift_rhs, "");
9732 running_int = self.builder.buildOr(running_int, shifted, "");9800 running_int = try self.wip.bin(.@"or", running_int, shifted, "");
9733 running_bits += ty_bit_size;9801 running_bits += ty_bit_size;
9734 }9802 }
9735 return running_int;9803 return running_int;
...@@ -9738,19 +9806,16 @@ pub const FuncGen = struct {...@@ -9738,19 +9806,16 @@ pub const FuncGen = struct {
9738 if (isByRef(result_ty, mod)) {9806 if (isByRef(result_ty, mod)) {
9739 // TODO in debug builds init to undef so that the padding will be 0xaa9807 // TODO in debug builds init to undef so that the padding will be 0xaa
9740 // even if we fully populate the fields.9808 // 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 };
9747 for (elements, 0..) |elem, i| {9812 for (elements, 0..) |elem, i| {
9748 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;9813 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
97499814
9750 const llvm_elem = try self.resolveInst(elem);9815 const llvm_elem = try self.resolveInst(elem);
9751 const llvm_i = llvmField(result_ty, i, mod).?.index;9816 const llvm_i = llvmField(result_ty, i, mod).?.index;
9752 indices[1] = (try o.builder.intConst(.i32, llvm_i)).toLlvm(&o.builder);9817 const field_ptr =
9753 const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");9818 try self.wip.gepStruct(llvm_result_ty, alloca_inst, llvm_i, "");
9754 const field_ptr_ty = try mod.ptrType(.{9819 const field_ptr_ty = try mod.ptrType(.{
9755 .child = self.typeOf(elem).toIntern(),9820 .child = self.typeOf(elem).toIntern(),
9756 .flags = .{9821 .flags = .{
...@@ -9759,18 +9824,18 @@ pub const FuncGen = struct {...@@ -9759,18 +9824,18 @@ pub const FuncGen = struct {
9759 ),9824 ),
9760 },9825 },
9761 });9826 });
9762 try self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic);9827 try self.store(field_ptr, field_ptr_ty, llvm_elem, .none);
9763 }9828 }
97649829
9765 return alloca_inst;9830 return alloca_inst;
9766 } else {9831 } else {
9767 var result = llvm_result_ty.getUndef();9832 var result = try o.builder.poisonValue(llvm_result_ty);
9768 for (elements, 0..) |elem, i| {9833 for (elements, 0..) |elem, i| {
9769 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;9834 if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue;
97709835
9771 const llvm_elem = try self.resolveInst(elem);9836 const llvm_elem = try self.resolveInst(elem);
9772 const llvm_i = llvmField(result_ty, i, mod).?.index;9837 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}, "");
9774 }9839 }
9775 return result;9840 return result;
9776 }9841 }
...@@ -9778,8 +9843,10 @@ pub const FuncGen = struct {...@@ -9778,8 +9843,10 @@ pub const FuncGen = struct {
9778 .Array => {9843 .Array => {
9779 assert(isByRef(result_ty, mod));9844 assert(isByRef(result_ty, mod));
97809845
9781 const usize_ty = try o.lowerType(Type.usize);9846 const llvm_usize = try o.lowerType(Type.usize);
9782 const alloca_inst = try self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(mod));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
9784 const array_info = result_ty.arrayInfo(mod);9851 const array_info = result_ty.arrayInfo(mod);
9785 const elem_ptr_ty = try mod.ptrType(.{9852 const elem_ptr_ty = try mod.ptrType(.{
...@@ -9787,26 +9854,21 @@ pub const FuncGen = struct {...@@ -9787,26 +9854,21 @@ pub const FuncGen = struct {
9787 });9854 });
97889855
9789 for (elements, 0..) |elem, i| {9856 for (elements, 0..) |elem, i| {
9790 const indices: [2]*llvm.Value = .{9857 const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{
9791 (try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder),9858 usize_zero, try o.builder.intValue(llvm_usize, i),
9792 (try o.builder.intConst(usize_ty, i)).toLlvm(&o.builder),9859 }, "");
9793 };
9794 const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
9795 const llvm_elem = try self.resolveInst(elem);9860 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);
9797 }9862 }
9798 if (array_info.sentinel) |sent_val| {9863 if (array_info.sentinel) |sent_val| {
9799 const indices: [2]*llvm.Value = .{9864 const elem_ptr = try self.wip.gep(.inbounds, llvm_result_ty, alloca_inst, &.{
9800 (try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder),9865 usize_zero, try o.builder.intValue(llvm_usize, array_info.len),
9801 (try o.builder.intConst(usize_ty, array_info.len)).toLlvm(&o.builder),9866 }, "");
9802 };
9803 const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, "");
9804 const llvm_elem = try self.resolveValue(.{9867 const llvm_elem = try self.resolveValue(.{
9805 .ty = array_info.elem_type,9868 .ty = array_info.elem_type,
9806 .val = sent_val,9869 .val = sent_val,
9807 });9870 });
98089871 try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toValue(), .none);
9809 try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toLlvm(&o.builder), .NotAtomic);
9810 }9872 }
98119873
9812 return alloca_inst;9874 return alloca_inst;
...@@ -9815,7 +9877,7 @@ pub const FuncGen = struct {...@@ -9815,7 +9877,7 @@ pub const FuncGen = struct {
9815 }9877 }
9816 }9878 }
98179879
9818 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {9880 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9819 const o = self.dg.object;9881 const o = self.dg.object;
9820 const mod = o.module;9882 const mod = o.module;
9821 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;9883 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -9827,15 +9889,15 @@ pub const FuncGen = struct {...@@ -9827,15 +9889,15 @@ pub const FuncGen = struct {
98279889
9828 if (union_obj.layout == .Packed) {9890 if (union_obj.layout == .Packed) {
9829 const big_bits = union_ty.bitSize(mod);9891 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));
9831 const field = union_obj.fields.values()[extra.field_index];9893 const field = union_obj.fields.values()[extra.field_index];
9832 const non_int_val = try self.resolveInst(extra.init);9894 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)));
9834 const small_int_val = if (field.ty.isPtrAtRuntime(mod))9896 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, "")
9836 else9898 else
9837 self.builder.buildBitCast(non_int_val, small_int_ty, "");9899 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
9838 return self.builder.buildZExtOrBitCast(small_int_val, int_llvm_ty, "");9900 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");
9839 }9901 }
98409902
9841 const tag_int = blk: {9903 const tag_int = blk: {
...@@ -9848,25 +9910,29 @@ pub const FuncGen = struct {...@@ -9848,25 +9910,29 @@ pub const FuncGen = struct {
9848 };9910 };
9849 if (layout.payload_size == 0) {9911 if (layout.payload_size == 0) {
9850 if (layout.tag_size == 0) {9912 if (layout.tag_size == 0) {
9851 return null;9913 return .none;
9852 }9914 }
9853 assert(!isByRef(union_ty, mod));9915 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);
9855 }9917 }
9856 assert(isByRef(union_ty, mod));9918 assert(isByRef(union_ty, mod));
9857 // The llvm type of the alloca will be the named LLVM union type, and will not9919 // The llvm type of the alloca will be the named LLVM union type, and will not
9858 // necessarily match the format that we need, depending on which tag is active.9920 // necessarily match the format that we need, depending on which tag is active.
9859 // We must construct the correct unnamed struct type here, in order to then set9921 // We must construct the correct unnamed struct type here, in order to then set
9860 // the fields appropriately.9922 // 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);
9862 const llvm_payload = try self.resolveInst(extra.init);9925 const llvm_payload = try self.resolveInst(extra.init);
9863 assert(union_obj.haveFieldTypes());9926 assert(union_obj.haveFieldTypes());
9864 const field = union_obj.fields.values()[extra.field_index];9927 const field = union_obj.fields.values()[extra.field_index];
9865 const field_llvm_ty = try o.lowerType(field.ty);9928 const field_llvm_ty = try o.lowerType(field.ty);
9866 const field_size = field.ty.abiSize(mod);9929 const field_size = field.ty.abiSize(mod);
9867 const field_align = field.normalAlignment(mod);9930 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: {
9870 const payload_ty = p: {9936 const payload_ty = p: {
9871 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) {9937 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) {
9872 const padding_len = layout.payload_size;9938 const padding_len = layout.payload_size;
...@@ -9894,52 +9960,46 @@ pub const FuncGen = struct {...@@ -9894,52 +9960,46 @@ pub const FuncGen = struct {
9894 fields_len += 1;9960 fields_len += 1;
9895 }9961 }
9896 break :t try o.builder.structType(.normal, fields[0..fields_len]);9962 break :t try o.builder.structType(.normal, fields[0..fields_len]);
9897 }).toLlvm(&o.builder);9963 };
98989964
9899 // Now we follow the layout as expressed above with GEP instructions to set the9965 // Now we follow the layout as expressed above with GEP instructions to set the
9900 // tag and the payload.9966 // tag and the payload.
9901 const field_ptr_ty = try mod.ptrType(.{9967 const field_ptr_ty = try mod.ptrType(.{
9902 .child = field.ty.toIntern(),9968 .child = field.ty.toIntern(),
9903 .flags = .{9969 .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },
9904 .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align),
9905 },
9906 });9970 });
9907 if (layout.tag_size == 0) {9971 if (layout.tag_size == 0) {
9908 const indices: [3]*llvm.Value = .{9972 const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero };
9909 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),9973 const len: usize = if (field_size == layout.payload_size) 2 else 3;
9910 } ** 3;9974 const field_ptr =
9911 const len: c_uint = if (field_size == layout.payload_size) 2 else 3;9975 try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], "");
9912 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, len, "");9976 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
9913 try self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic);
9914 return result_ptr;9977 return result_ptr;
9915 }9978 }
99169979
9917 {9980 {
9918 const indices: [3]*llvm.Value = .{9981 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
9919 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),9982 const indices: [3]Builder.Value =
9920 (try o.builder.intConst(.i32, @intFromBool(layout.tag_align >= layout.payload_align))).toLlvm(&o.builder),9983 .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero };
9921 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),9984 const len: usize = if (field_size == layout.payload_size) 2 else 3;
9922 };9985 const field_ptr =
9923 const len: c_uint = if (field_size == layout.payload_size) 2 else 3;9986 try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, indices[0..len], "");
9924 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, len, "");9987 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
9925 try self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic);
9926 }9988 }
9927 {9989 {
9928 const indices: [2]*llvm.Value = .{9990 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9929 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),9991 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
9930 (try o.builder.intConst(.i32, @intFromBool(layout.tag_align < layout.payload_align))).toLlvm(&o.builder),9992 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
9931 };
9932 const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, result_ptr, &indices, indices.len, "");
9933 const tag_ty = try o.lowerType(union_obj.tag_ty);9993 const tag_ty = try o.lowerType(union_obj.tag_ty);
9934 const llvm_tag = try o.builder.intConst(tag_ty, tag_int);9994 const llvm_tag = try o.builder.intValue(tag_ty, tag_int);
9935 const store_inst = self.builder.buildStore(llvm_tag.toLlvm(&o.builder), field_ptr);9995 const tag_alignment = Builder.Alignment.fromByteUnits(union_obj.tag_ty.abiAlignment(mod));
9936 store_inst.setAlignment(union_obj.tag_ty.abiAlignment(mod));9996 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
9937 }9997 }
99389998
9939 return result_ptr;9999 return result_ptr;
9940 }10000 }
994110001
9942 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10002 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9943 const o = self.dg.object;10003 const o = self.dg.object;
9944 const prefetch = self.air.instructions.items(.data)[inst].prefetch;10004 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
994510005
...@@ -9968,10 +10028,10 @@ pub const FuncGen = struct {...@@ -9968,10 +10028,10 @@ pub const FuncGen = struct {
9968 .powerpcle,10028 .powerpcle,
9969 .powerpc64,10029 .powerpc64,
9970 .powerpc64le,10030 .powerpc64le,
9971 => return null,10031 => return .none,
9972 .arm, .armeb, .thumb, .thumbeb => {10032 .arm, .armeb, .thumb, .thumbeb => {
9973 switch (prefetch.rw) {10033 switch (prefetch.rw) {
9974 .write => return null,10034 .write => return .none,
9975 else => {},10035 else => {},
9976 }10036 }
9977 },10037 },
...@@ -9981,48 +10041,63 @@ pub const FuncGen = struct {...@@ -9981,48 +10041,63 @@ pub const FuncGen = struct {
9981 }10041 }
998210042
9983 const llvm_fn_name = "llvm.prefetch.p0";10043 const llvm_fn_name = "llvm.prefetch.p0";
9984 const fn_val = o.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {10044 // declare void @llvm.prefetch(i8*, i32, i32, i32)
9985 // declare void @llvm.prefetch(i8*, i32, i32, i32)10045 const llvm_fn_ty = try o.builder.fnType(.void, &.{ .ptr, .i32, .i32, .i32 }, .normal);
9986 const fn_type = try o.builder.fnType(.void, &.{ .ptr, .i32, .i32, .i32 }, .normal);10046 const fn_val = o.llvm_module.getNamedFunction(llvm_fn_name) orelse
9987 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));10047 o.llvm_module.addFunction(llvm_fn_name, llvm_fn_ty.toLlvm(&o.builder));
9988 };
998910048
9990 const ptr = try self.resolveInst(prefetch.ptr);10049 const ptr = try self.resolveInst(prefetch.ptr);
999110050
9992 const params = [_]*llvm.Value{10051 const params = [_]*llvm.Value{
9993 ptr,10052 ptr.toLlvm(&self.wip),
9994 (try o.builder.intConst(.i32, @intFromEnum(prefetch.rw))).toLlvm(&o.builder),10053 (try o.builder.intConst(.i32, @intFromEnum(prefetch.rw))).toLlvm(&o.builder),
9995 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),10054 (try o.builder.intConst(.i32, prefetch.locality)).toLlvm(&o.builder),
9996 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),10055 (try o.builder.intConst(.i32, @intFromEnum(prefetch.cache))).toLlvm(&o.builder),
9997 };10056 };
9998 _ = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");10057 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildCall(
9999 return null;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;
10000 }10067 }
1000110068
10002 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10069 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
10003 const o = self.dg.object;10070 const o = self.dg.object;
10004 const ty_op = self.air.instructions.items(.data)[inst].ty_op;10071 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
10005 const inst_ty = self.typeOfIndex(inst);10072 const inst_ty = self.typeOfIndex(inst);
10006 const operand = try self.resolveInst(ty_op.operand);10073 const operand = try self.resolveInst(ty_op.operand);
1000710074
10008 const llvm_dest_ty = (try o.lowerType(inst_ty)).toLlvm(&o.builder);10075 return self.wip.cast(.addrspacecast, operand, try o.lowerType(inst_ty), "");
10009 return self.builder.buildAddrSpaceCast(operand, llvm_dest_ty, "");
10010 }10076 }
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;
10013 const llvm_fn_name = switch (dimension) {10080 const llvm_fn_name = switch (dimension) {
10014 0 => basename ++ ".x",10081 0 => basename ++ ".x",
10015 1 => basename ++ ".y",10082 1 => basename ++ ".y",
10016 2 => basename ++ ".z",10083 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),
10018 };10085 };
1001910086
10020 const args: [0]*llvm.Value = .{};10087 const args: [0]*llvm.Value = .{};
10021 const llvm_fn = try self.getIntrinsic(llvm_fn_name, &.{});10088 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);
10023 }10098 }
1002410099
10025 fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10100 fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
10026 const o = self.dg.object;10101 const o = self.dg.object;
10027 const target = o.module.getTarget();10102 const target = o.module.getTarget();
10028 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures10103 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
...@@ -10032,38 +10107,41 @@ pub const FuncGen = struct {...@@ -10032,38 +10107,41 @@ pub const FuncGen = struct {
10032 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workitem.id");10107 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workitem.id");
10033 }10108 }
1003410109
10035 fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10110 fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
10036 const o = self.dg.object;10111 const o = self.dg.object;
10037 const target = o.module.getTarget();10112 const target = o.module.getTarget();
10038 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures10113 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
1003910114
10040 const pl_op = self.air.instructions.items(.data)[inst].pl_op;10115 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
10041 const dimension = pl_op.payload;10116 const dimension = pl_op.payload;
10042 if (dimension >= 3) {10117 if (dimension >= 3) return o.builder.intValue(.i32, 1);
10043 return (try o.builder.intConst(.i32, 1)).toLlvm(&o.builder);
10044 }
1004510118
10046 // Fetch the dispatch pointer, which points to this structure:10119 // Fetch the dispatch pointer, which points to this structure:
10047 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L291310120 // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913
10048 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});10121 const llvm_fn = try self.getIntrinsic("llvm.amdgcn.dispatch.ptr", &.{});
10049 const args: [0]*llvm.Value = .{};10122 const args: [0]*llvm.Value = .{};
10050 const dispatch_ptr = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, "");10123 const llvm_ret_ty = try o.builder.ptrType(Builder.AddrSpace.amdgpu.constant);
10051 dispatch_ptr.setAlignment(4);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
10053 // Load the work_group_* member from the struct as u16.10135 // Load the work_group_* member from the struct as u16.
10054 // Just treat the dispatch pointer as an array of u16 to keep things simple.10136 // Just treat the dispatch pointer as an array of u16 to keep things simple.
10055 const offset = 2 + dimension;10137 const workgroup_size_ptr = try self.wip.gep(.inbounds, .i16, dispatch_ptr, &.{
10056 const index = [_]*llvm.Value{10138 try o.builder.intValue(try o.lowerType(Type.usize), 2 + dimension),
10057 (try o.builder.intConst(.i32, offset)).toLlvm(&o.builder),10139 }, "");
10058 };10140 const workgroup_size_alignment = comptime Builder.Alignment.fromByteUnits(2);
10059 const llvm_u16 = Builder.Type.i16.toLlvm(&o.builder);10141 return self.wip.load(.normal, .i16, workgroup_size_ptr, workgroup_size_alignment, "");
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;
10064 }10142 }
1006510143
10066 fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {10144 fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
10067 const o = self.dg.object;10145 const o = self.dg.object;
10068 const target = o.module.getTarget();10146 const target = o.module.getTarget();
10069 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures10147 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
...@@ -10095,13 +10173,13 @@ pub const FuncGen = struct {...@@ -10095,13 +10173,13 @@ pub const FuncGen = struct {
10095 .linkage = .private,10173 .linkage = .private,
10096 .unnamed_addr = .unnamed_addr,10174 .unnamed_addr = .unnamed_addr,
10097 .type = .ptr,10175 .type = .ptr,
10098 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
10099 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },10176 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
10100 };10177 };
10101 var variable = Builder.Variable{10178 var variable = Builder.Variable{
10102 .global = @enumFromInt(o.builder.globals.count()),10179 .global = @enumFromInt(o.builder.globals.count()),
10103 .mutability = .constant,10180 .mutability = .constant,
10104 .init = undef_init,10181 .init = undef_init,
10182 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
10105 };10183 };
10106 try o.builder.llvm.globals.append(o.gpa, error_name_table_global);10184 try o.builder.llvm.globals.append(o.gpa, error_name_table_global);
10107 _ = try o.builder.addGlobal(name, global);10185 _ = try o.builder.addGlobal(name, global);
...@@ -10112,97 +10190,95 @@ pub const FuncGen = struct {...@@ -10112,97 +10190,95 @@ pub const FuncGen = struct {
10112 }10190 }
1011310191
10114 /// Assumes the optional is not pointer-like and payload has bits.10192 /// Assumes the optional is not pointer-like and payload has bits.
10115 fn optIsNonNull(10193 fn optCmpNull(
10116 self: *FuncGen,10194 self: *FuncGen,
10117 opt_llvm_ty: *llvm.Type,10195 cond: Builder.IntegerCondition,
10118 opt_handle: *llvm.Value,10196 opt_llvm_ty: Builder.Type,
10197 opt_handle: Builder.Value,
10119 is_by_ref: bool,10198 is_by_ref: bool,
10120 ) Allocator.Error!*llvm.Value {10199 ) Allocator.Error!Builder.Value {
10200 const o = self.dg.object;
10121 const field = b: {10201 const field = b: {
10122 if (is_by_ref) {10202 if (is_by_ref) {
10123 const field_ptr = self.builder.buildStructGEP(opt_llvm_ty, opt_handle, 1, "");10203 const field_ptr = try self.wip.gepStruct(opt_llvm_ty, opt_handle, 1, "");
10124 break :b self.builder.buildLoad(Builder.Type.i8.toLlvm(&self.dg.object.builder), field_ptr, "");10204 break :b try self.wip.load(.normal, .i8, field_ptr, .default, "");
10125 }10205 }
10126 break :b self.builder.buildExtractValue(opt_handle, 1, "");10206 break :b try self.wip.extractValue(opt_handle, &.{1}, "");
10127 };10207 };
10128 comptime assert(optional_layout_version == 3);10208 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), "");
10131 }10211 }
1013210212
10133 /// Assumes the optional is not pointer-like and payload has bits.10213 /// Assumes the optional is not pointer-like and payload has bits.
10134 fn optPayloadHandle(10214 fn optPayloadHandle(
10135 fg: *FuncGen,10215 fg: *FuncGen,
10136 opt_llvm_ty: *llvm.Type,10216 opt_llvm_ty: Builder.Type,
10137 opt_handle: *llvm.Value,10217 opt_handle: Builder.Value,
10138 opt_ty: Type,10218 opt_ty: Type,
10139 can_elide_load: bool,10219 can_elide_load: bool,
10140 ) !*llvm.Value {10220 ) !Builder.Value {
10141 const o = fg.dg.object;10221 const o = fg.dg.object;
10142 const mod = o.module;10222 const mod = o.module;
10143 const payload_ty = opt_ty.optionalChild(mod);10223 const payload_ty = opt_ty.optionalChild(mod);
1014410224
10145 if (isByRef(opt_ty, mod)) {10225 if (isByRef(opt_ty, mod)) {
10146 // We have a pointer and we need to return a pointer to the first field.10226 // 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));
10150 if (isByRef(payload_ty, mod)) {10230 if (isByRef(payload_ty, mod)) {
10151 if (can_elide_load)10231 if (can_elide_load)
10152 return payload_ptr;10232 return payload_ptr;
1015310233
10154 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);10234 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
10155 }10235 }
10156 const payload_llvm_ty = (try o.lowerType(payload_ty)).toLlvm(&o.builder);10236 const payload_llvm_ty = try o.lowerType(payload_ty);
10157 const load_inst = fg.builder.buildLoad(payload_llvm_ty, payload_ptr, "");10237 return fg.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
10158 load_inst.setAlignment(payload_alignment);
10159 return load_inst;
10160 }10238 }
1016110239
10162 assert(!isByRef(payload_ty, mod));10240 assert(!isByRef(payload_ty, mod));
10163 return fg.builder.buildExtractValue(opt_handle, 0, "");10241 return fg.wip.extractValue(opt_handle, &.{0}, "");
10164 }10242 }
1016510243
10166 fn buildOptional(10244 fn buildOptional(
10167 self: *FuncGen,10245 self: *FuncGen,
10168 optional_ty: Type,10246 optional_ty: Type,
10169 payload: *llvm.Value,10247 payload: Builder.Value,
10170 non_null_bit: *llvm.Value,10248 non_null_bit: Builder.Value,
10171 ) !?*llvm.Value {10249 ) !Builder.Value {
10172 const o = self.dg.object;10250 const o = self.dg.object;
10173 const optional_llvm_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);10251 const optional_llvm_ty = try o.lowerType(optional_ty);
10174 const non_null_field = self.builder.buildZExt(non_null_bit, Builder.Type.i8.toLlvm(&o.builder), "");10252 const non_null_field = try self.wip.cast(.zext, non_null_bit, .i8, "");
10175 const mod = o.module;10253 const mod = o.module;
1017610254
10177 if (isByRef(optional_ty, mod)) {10255 if (isByRef(optional_ty, mod)) {
10178 const payload_alignment = optional_ty.abiAlignment(mod);10256 const payload_alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
10179 const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment);10257 const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment);
1018010258
10181 {10259 {
10182 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");10260 const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 0, "");
10183 const store_inst = self.builder.buildStore(payload, field_ptr);10261 _ = try self.wip.store(.normal, payload, field_ptr, payload_alignment);
10184 store_inst.setAlignment(payload_alignment);
10185 }10262 }
10186 {10263 {
10187 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 1, "");10264 const non_null_alignment = comptime Builder.Alignment.fromByteUnits(1);
10188 const store_inst = self.builder.buildStore(non_null_field, field_ptr);10265 const field_ptr = try self.wip.gepStruct(optional_llvm_ty, alloca_inst, 1, "");
10189 store_inst.setAlignment(1);10266 _ = try self.wip.store(.normal, non_null_field, field_ptr, non_null_alignment);
10190 }10267 }
1019110268
10192 return alloca_inst;10269 return alloca_inst;
10193 }10270 }
1019410271
10195 const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");10272 return self.wip.buildAggregate(optional_llvm_ty, &.{ payload, non_null_field }, "");
10196 return self.builder.buildInsertValue(partial, non_null_field, 1, "");
10197 }10273 }
1019810274
10199 fn fieldPtr(10275 fn fieldPtr(
10200 self: *FuncGen,10276 self: *FuncGen,
10201 inst: Air.Inst.Index,10277 inst: Air.Inst.Index,
10202 struct_ptr: *llvm.Value,10278 struct_ptr: Builder.Value,
10203 struct_ptr_ty: Type,10279 struct_ptr_ty: Type,
10204 field_index: u32,10280 field_index: u32,
10205 ) !?*llvm.Value {10281 ) !Builder.Value {
10206 const o = self.dg.object;10282 const o = self.dg.object;
10207 const mod = o.module;10283 const mod = o.module;
10208 const struct_ty = struct_ptr_ty.childType(mod);10284 const struct_ty = struct_ptr_ty.childType(mod);
...@@ -10224,25 +10300,25 @@ pub const FuncGen = struct {...@@ -10224,25 +10300,25 @@ pub const FuncGen = struct {
10224 // Offset our operand pointer by the correct number of bytes.10300 // Offset our operand pointer by the correct number of bytes.
10225 const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, mod);10301 const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, mod);
10226 if (byte_offset == 0) return struct_ptr;10302 if (byte_offset == 0) return struct_ptr;
10227 const byte_llvm_ty = Builder.Type.i8.toLlvm(&o.builder);
10228 const usize_ty = try o.lowerType(Type.usize);10303 const usize_ty = try o.lowerType(Type.usize);
10229 const llvm_index = try o.builder.intConst(usize_ty, byte_offset);10304 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);
10230 const indices: [1]*llvm.Value = .{llvm_index.toLlvm(&o.builder)};10305 return self.wip.gep(.inbounds, .i8, struct_ptr, &.{llvm_index}, "");
10231 return self.builder.buildInBoundsGEP(byte_llvm_ty, struct_ptr, &indices, indices.len, "");
10232 },10306 },
10233 else => {10307 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
10236 if (llvmField(struct_ty, field_index, mod)) |llvm_field| {10310 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, "");
10238 } else {10312 } else {
10239 // If we found no index then this means this is a zero sized field at the10313 // If we found no index then this means this is a zero sized field at the
10240 // end of the struct. Treat our struct pointer as an array of two and get10314 // end of the struct. Treat our struct pointer as an array of two and get
10241 // the index to the element at index `1` to get a pointer to the end of10315 // the index to the element at index `1` to get a pointer to the end of
10242 // the struct.10316 // the struct.
10243 const llvm_index = try o.builder.intConst(.i32, @intFromBool(struct_ty.hasRuntimeBitsIgnoreComptime(mod)));10317 const llvm_index = try o.builder.intValue(
10244 const indices: [1]*llvm.Value = .{llvm_index.toLlvm(&o.builder)};10318 try o.lowerType(Type.usize),
10245 return self.builder.buildInBoundsGEP(struct_llvm_ty, struct_ptr, &indices, indices.len, "");10319 @intFromBool(struct_ty.hasRuntimeBitsIgnoreComptime(mod)),
10320 );
10321 return self.wip.gep(.inbounds, struct_llvm_ty, struct_ptr, &.{llvm_index}, "");
10246 }10322 }
10247 },10323 },
10248 },10324 },
...@@ -10250,15 +10326,18 @@ pub const FuncGen = struct {...@@ -10250,15 +10326,18 @@ pub const FuncGen = struct {
10250 const layout = struct_ty.unionGetLayout(mod);10326 const layout = struct_ty.unionGetLayout(mod);
10251 if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr;10327 if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr;
10252 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);10328 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
10253 const union_llvm_ty = (try o.lowerType(struct_ty)).toLlvm(&o.builder);10329 const union_llvm_ty = try o.lowerType(struct_ty);
10254 const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_ptr, payload_index, "");10330 return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");
10255 return union_field_ptr;
10256 },10331 },
10257 else => unreachable,10332 else => unreachable,
10258 }10333 }
10259 }10334 }
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 {
10262 const o = fg.dg.object;10341 const o = fg.dg.object;
10263 const id = llvm.lookupIntrinsicID(name.ptr, name.len);10342 const id = llvm.lookupIntrinsicID(name.ptr, name.len);
10264 assert(id != 0);10343 assert(id != 0);
...@@ -10271,109 +10350,105 @@ pub const FuncGen = struct {...@@ -10271,109 +10350,105 @@ pub const FuncGen = struct {
10271 /// Load a by-ref type by constructing a new alloca and performing a memcpy.10350 /// Load a by-ref type by constructing a new alloca and performing a memcpy.
10272 fn loadByRef(10351 fn loadByRef(
10273 fg: *FuncGen,10352 fg: *FuncGen,
10274 ptr: *llvm.Value,10353 ptr: Builder.Value,
10275 pointee_type: Type,10354 pointee_type: Type,
10276 ptr_alignment: u32,10355 ptr_alignment: Builder.Alignment,
10277 is_volatile: bool,10356 is_volatile: bool,
10278 ) !*llvm.Value {10357 ) !Builder.Value {
10279 const o = fg.dg.object;10358 const o = fg.dg.object;
10280 const mod = o.module;10359 const mod = o.module;
10281 const pointee_llvm_ty = (try o.lowerType(pointee_type)).toLlvm(&o.builder);10360 const pointee_llvm_ty = try o.lowerType(pointee_type);
10282 const result_align = @max(ptr_alignment, pointee_type.abiAlignment(mod));10361 const result_align = Builder.Alignment.fromByteUnits(
10362 @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)),
10363 );
10283 const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);10364 const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);
10284 const usize_ty = try o.lowerType(Type.usize);10365 const usize_ty = try o.lowerType(Type.usize);
10285 const size_bytes = pointee_type.abiSize(mod);10366 const size_bytes = pointee_type.abiSize(mod);
10286 _ = fg.builder.buildMemCpy(10367 _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildMemCpy(
10287 result_ptr,10368 result_ptr.toLlvm(&fg.wip),
10288 result_align,10369 @intCast(result_align.toByteUnits() orelse 0),
10289 ptr,10370 ptr.toLlvm(&fg.wip),
10290 ptr_alignment,10371 @intCast(ptr_alignment.toByteUnits() orelse 0),
10291 (try o.builder.intConst(usize_ty, size_bytes)).toLlvm(&o.builder),10372 (try o.builder.intConst(usize_ty, size_bytes)).toLlvm(&o.builder),
10292 is_volatile,10373 is_volatile,
10293 );10374 ), &fg.wip);
10294 return result_ptr;10375 return result_ptr;
10295 }10376 }
1029610377
10297 /// This function always performs a copy. For isByRef=true types, it creates a new10378 /// This function always performs a copy. For isByRef=true types, it creates a new
10298 /// alloca and copies the value into it, then returns the alloca instruction.10379 /// alloca and copies the value into it, then returns the alloca instruction.
10299 /// For isByRef=false types, it creates a load instruction and returns it.10380 /// 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 {
10301 const o = self.dg.object;10382 const o = self.dg.object;
10302 const mod = o.module;10383 const mod = o.module;
10303 const info = ptr_ty.ptrInfo(mod);10384 const info = ptr_ty.ptrInfo(mod);
10304 const elem_ty = info.child.toType();10385 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() orelse10388 const ptr_alignment = Builder.Alignment.fromByteUnits(
10308 elem_ty.abiAlignment(mod));10389 info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod),
10309 const ptr_volatile = llvm.Bool.fromBool(info.flags.is_volatile);10390 );
10391 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
10392 false => .normal,
10393 true => .@"volatile",
10394 };
1031010395
10311 assert(info.flags.vector_index != .runtime);10396 assert(info.flags.vector_index != .runtime);
10312 if (info.flags.vector_index != .none) {10397 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));
10314 const vec_elem_ty = try o.lowerType(elem_ty);10399 const vec_elem_ty = try o.lowerType(elem_ty);
10315 const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty);10400 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, "");10402 const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, "");
10318 loaded_vector.setAlignment(ptr_alignment);10403 return self.wip.extractElement(loaded_vector, index_u32, "");
10319 loaded_vector.setVolatile(ptr_volatile);
10320
10321 return self.builder.buildExtractElement(loaded_vector, index_u32.toLlvm(&o.builder), "");
10322 }10404 }
1032310405
10324 if (info.packed_offset.host_size == 0) {10406 if (info.packed_offset.host_size == 0) {
10325 if (isByRef(elem_ty, mod)) {10407 if (isByRef(elem_ty, mod)) {
10326 return self.loadByRef(ptr, elem_ty, ptr_alignment, info.flags.is_volatile);10408 return self.loadByRef(ptr, elem_ty, ptr_alignment, info.flags.is_volatile);
10327 }10409 }
10328 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);10410 return self.wip.load(ptr_kind, try o.lowerType(elem_ty), ptr, ptr_alignment, "");
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;
10333 }10411 }
1033410412
10335 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));10413 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, "");10414 const containing_int = try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
10337 containing_int.setAlignment(ptr_alignment);
10338 containing_int.setVolatile(ptr_volatile);
1033910415
10340 const elem_bits = ptr_ty.childType(mod).bitSize(mod);10416 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);10417 const shift_amt = try o.builder.intValue(containing_int_ty, info.packed_offset.bit_offset);
10342 const shifted_value = self.builder.buildLShr(containing_int, shift_amt.toLlvm(&o.builder), "");10418 const shifted_value = try self.wip.bin(.lshr, containing_int, shift_amt, "");
10343 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);10419 const elem_llvm_ty = try o.lowerType(elem_ty);
1034410420
10345 if (isByRef(elem_ty, mod)) {10421 if (isByRef(elem_ty, mod)) {
10346 const result_align = elem_ty.abiAlignment(mod);10422 const result_align = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
10347 const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align);10423 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);10425 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10350 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");10426 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10351 const store_inst = self.builder.buildStore(truncated_int, result_ptr);10427 _ = try self.wip.store(.normal, truncated_int, result_ptr, result_align);
10352 store_inst.setAlignment(result_align);
10353 return result_ptr;10428 return result_ptr;
10354 }10429 }
1035510430
10356 if (elem_ty.zigTypeTag(mod) == .Float or elem_ty.zigTypeTag(mod) == .Vector) {10431 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);10432 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10358 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");10433 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10359 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");10434 return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
10360 }10435 }
1036110436
10362 if (elem_ty.isPtrAtRuntime(mod)) {10437 if (elem_ty.isPtrAtRuntime(mod)) {
10363 const same_size_int = (try o.builder.intType(@intCast(elem_bits))).toLlvm(&o.builder);10438 const same_size_int = try o.builder.intType(@intCast(elem_bits));
10364 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");10439 const truncated_int = try self.wip.cast(.trunc, shifted_value, same_size_int, "");
10365 return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, "");10440 return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
10366 }10441 }
1036710442
10368 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");10443 return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
10369 }10444 }
1037010445
10371 fn store(10446 fn store(
10372 self: *FuncGen,10447 self: *FuncGen,
10373 ptr: *llvm.Value,10448 ptr: Builder.Value,
10374 ptr_ty: Type,10449 ptr_ty: Type,
10375 elem: *llvm.Value,10450 elem: Builder.Value,
10376 ordering: llvm.AtomicOrdering,10451 ordering: Builder.AtomicOrdering,
10377 ) !void {10452 ) !void {
10378 const o = self.dg.object;10453 const o = self.dg.object;
10379 const mod = o.module;10454 const mod = o.module;
...@@ -10382,43 +10457,41 @@ pub const FuncGen = struct {...@@ -10382,43 +10457,41 @@ pub const FuncGen = struct {
10382 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {10457 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
10383 return;10458 return;
10384 }10459 }
10385 const ptr_alignment = ptr_ty.ptrAlignment(mod);10460 const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
10386 const ptr_volatile = llvm.Bool.fromBool(info.flags.is_volatile);10461 const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
10462 false => .normal,
10463 true => .@"volatile",
10464 };
1038710465
10388 assert(info.flags.vector_index != .runtime);10466 assert(info.flags.vector_index != .runtime);
10389 if (info.flags.vector_index != .none) {10467 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));
10391 const vec_elem_ty = try o.lowerType(elem_ty);10469 const vec_elem_ty = try o.lowerType(elem_ty);
10392 const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty);10470 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, "");10472 const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, "");
10395 loaded_vector.setAlignment(ptr_alignment);
10396 loaded_vector.setVolatile(ptr_volatile);
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);10476 assert(ordering == .none);
10401 assert(ordering == .NotAtomic);10477 _ = try self.wip.store(ptr_kind, modified_vector, ptr, ptr_alignment);
10402 store_inst.setAlignment(ptr_alignment);
10403 store_inst.setVolatile(ptr_volatile);
10404 return;10478 return;
10405 }10479 }
1040610480
10407 if (info.packed_offset.host_size != 0) {10481 if (info.packed_offset.host_size != 0) {
10408 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));10482 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, "");10483 assert(ordering == .none);
10410 assert(ordering == .NotAtomic);10484 const containing_int =
10411 containing_int.setAlignment(ptr_alignment);10485 try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
10412 containing_int.setVolatile(ptr_volatile);
10413 const elem_bits = ptr_ty.childType(mod).bitSize(mod);10486 const elem_bits = ptr_ty.childType(mod).bitSize(mod);
10414 const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset);10487 const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset);
10415 // Convert to equally-sized integer type in order to perform the bit10488 // Convert to equally-sized integer type in order to perform the bit
10416 // operations on the value to store10489 // operations on the value to store
10417 const value_bits_type = try o.builder.intType(@intCast(elem_bits));10490 const value_bits_type = try o.builder.intType(@intCast(elem_bits));
10418 const value_bits = if (elem_ty.isPtrAtRuntime(mod))10491 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, "")
10420 else10493 else
10421 self.builder.buildBitCast(elem, value_bits_type.toLlvm(&o.builder), "");10494 try self.wip.cast(.bitcast, elem, value_bits_type, "");
1042210495
10423 var mask_val = try o.builder.intConst(value_bits_type, -1);10496 var mask_val = try o.builder.intConst(value_bits_type, -1);
10424 mask_val = try o.builder.castConst(.zext, mask_val, containing_int_ty);10497 mask_val = try o.builder.castConst(.zext, mask_val, containing_int_ty);
...@@ -10426,79 +10499,73 @@ pub const FuncGen = struct {...@@ -10426,79 +10499,73 @@ pub const FuncGen = struct {
10426 mask_val =10499 mask_val =
10427 try o.builder.binConst(.xor, mask_val, try o.builder.intConst(containing_int_ty, -1));10500 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), "");10502 const anded_containing_int =
10430 const extended_value = self.builder.buildZExt(value_bits, containing_int_ty.toLlvm(&o.builder), "");10503 try self.wip.bin(.@"and", containing_int, mask_val.toValue(), "");
10431 const shifted_value = self.builder.buildShl(extended_value, shift_amt.toLlvm(&o.builder), "");10504 const extended_value = try self.wip.cast(.zext, value_bits, containing_int_ty, "");
10432 const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, "");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);10508 assert(ordering == .none);
10435 assert(ordering == .NotAtomic);10509 _ = try self.wip.store(ptr_kind, ored_value, ptr, ptr_alignment);
10436 store_inst.setAlignment(ptr_alignment);
10437 store_inst.setVolatile(ptr_volatile);
10438 return;10510 return;
10439 }10511 }
10440 if (!isByRef(elem_ty, mod)) {10512 if (!isByRef(elem_ty, mod)) {
10441 const store_inst = self.builder.buildStore(elem, ptr);10513 _ = try self.wip.storeAtomic(ptr_kind, elem, ptr, self.sync_scope, ordering, ptr_alignment);
10442 store_inst.setOrdering(ordering);
10443 store_inst.setAlignment(ptr_alignment);
10444 store_inst.setVolatile(ptr_volatile);
10445 return;10514 return;
10446 }10515 }
10447 assert(ordering == .NotAtomic);10516 assert(ordering == .none);
10448 const size_bytes = elem_ty.abiSize(mod);10517 const size_bytes = elem_ty.abiSize(mod);
10449 _ = self.builder.buildMemCpy(10518 _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
10450 ptr,10519 ptr.toLlvm(&self.wip),
10451 ptr_alignment,10520 @intCast(ptr_alignment.toByteUnits() orelse 0),
10452 elem,10521 elem.toLlvm(&self.wip),
10453 elem_ty.abiAlignment(mod),10522 elem_ty.abiAlignment(mod),
10454 (try o.builder.intConst(try o.lowerType(Type.usize), size_bytes)).toLlvm(&o.builder),10523 (try o.builder.intConst(try o.lowerType(Type.usize), size_bytes)).toLlvm(&o.builder),
10455 info.flags.is_volatile,10524 info.flags.is_volatile,
10456 );10525 ), &self.wip);
10457 }10526 }
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 {
10460 const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;10529 const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
10461 const o = fg.dg.object;10530 const o = fg.dg.object;
10462 const usize_ty = try o.lowerType(Type.usize);10531 const usize_ty = try o.lowerType(Type.usize);
10463 const zero = (try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder);10532 const zero = try o.builder.intValue(usize_ty, 0);
10464 const req = (try o.builder.intConst(usize_ty, VG_USERREQ__MAKE_MEM_UNDEFINED)).toLlvm(&o.builder);10533 const req = try o.builder.intValue(usize_ty, VG_USERREQ__MAKE_MEM_UNDEFINED);
10465 const ptr_as_usize = fg.builder.buildPtrToInt(ptr, usize_ty.toLlvm(&o.builder), "");10534 const ptr_as_usize = try fg.wip.cast(.ptrtoint, ptr, usize_ty, "");
10466 _ = try valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);10535 _ = try valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
10467 }10536 }
1046810537
10469 fn valgrindClientRequest(10538 fn valgrindClientRequest(
10470 fg: *FuncGen,10539 fg: *FuncGen,
10471 default_value: *llvm.Value,10540 default_value: Builder.Value,
10472 request: *llvm.Value,10541 request: Builder.Value,
10473 a1: *llvm.Value,10542 a1: Builder.Value,
10474 a2: *llvm.Value,10543 a2: Builder.Value,
10475 a3: *llvm.Value,10544 a3: Builder.Value,
10476 a4: *llvm.Value,10545 a4: Builder.Value,
10477 a5: *llvm.Value,10546 a5: Builder.Value,
10478 ) Allocator.Error!*llvm.Value {10547 ) Allocator.Error!Builder.Value {
10479 const o = fg.dg.object;10548 const o = fg.dg.object;
10480 const mod = o.module;10549 const mod = o.module;
10481 const target = mod.getTarget();10550 const target = mod.getTarget();
10482 if (!target_util.hasValgrindSupport(target)) return default_value;10551 if (!target_util.hasValgrindSupport(target)) return default_value;
1048310552
10484 const llvm_usize = try o.lowerType(Type.usize);10553 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);10556 const array_llvm_ty = try o.builder.arrayType(6, llvm_usize);
10488 const array_ptr = fg.valgrind_client_request_array orelse a: {10557 const array_ptr = if (fg.valgrind_client_request_array == .none) a: {
10489 const array_ptr = try fg.buildAlloca(array_llvm_ty, @intCast(usize_alignment));10558 const array_ptr = try fg.buildAlloca(array_llvm_ty, usize_alignment);
10490 fg.valgrind_client_request_array = array_ptr;10559 fg.valgrind_client_request_array = array_ptr;
10491 break :a array_ptr;10560 break :a array_ptr;
10492 };10561 } else fg.valgrind_client_request_array;
10493 const array_elements = [_]*llvm.Value{ request, a1, a2, a3, a4, a5 };10562 const array_elements = [_]Builder.Value{ request, a1, a2, a3, a4, a5 };
10494 const zero = (try o.builder.intConst(llvm_usize, 0)).toLlvm(&o.builder);10563 const zero = try o.builder.intValue(llvm_usize, 0);
10495 for (array_elements, 0..) |elem, i| {10564 for (array_elements, 0..) |elem, i| {
10496 const indexes = [_]*llvm.Value{10565 const elem_ptr = try fg.wip.gep(.inbounds, array_llvm_ty, array_ptr, &.{
10497 zero, (try o.builder.intConst(llvm_usize, i)).toLlvm(&o.builder),10566 zero, try o.builder.intValue(llvm_usize, i),
10498 };10567 }, "");
10499 const elem_ptr = fg.builder.buildInBoundsGEP(array_llvm_ty, array_ptr, &indexes, indexes.len, "");10568 _ = try fg.wip.store(.normal, elem, elem_ptr, usize_alignment);
10500 const store_inst = fg.builder.buildStore(elem, elem_ptr);
10501 store_inst.setAlignment(@intCast(usize_alignment));
10502 }10569 }
1050310570
10504 const arch_specific: struct {10571 const arch_specific: struct {
...@@ -10533,8 +10600,8 @@ pub const FuncGen = struct {...@@ -10533,8 +10600,8 @@ pub const FuncGen = struct {
10533 };10600 };
1053410601
10535 const fn_llvm_ty = (try o.builder.fnType(llvm_usize, &(.{llvm_usize} ** 2), .normal)).toLlvm(&o.builder);10602 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), "");10603 const array_ptr_as_usize = try fg.wip.cast(.ptrtoint, array_ptr, llvm_usize, "");
10537 const args = [_]*llvm.Value{ array_ptr_as_usize, default_value };10604 const args = [_]*llvm.Value{ array_ptr_as_usize.toLlvm(&fg.wip), default_value.toLlvm(&fg.wip) };
10538 const asm_fn = llvm.getInlineAsm(10605 const asm_fn = llvm.getInlineAsm(
10539 fn_llvm_ty,10606 fn_llvm_ty,
10540 arch_specific.template.ptr,10607 arch_specific.template.ptr,
...@@ -10547,14 +10614,9 @@ pub const FuncGen = struct {...@@ -10547,14 +10614,9 @@ pub const FuncGen = struct {
10547 .False, // can throw10614 .False, // can throw
10548 );10615 );
1054910616
10550 const call = fg.builder.buildCall(10617 const call = (try fg.wip.unimplemented(llvm_usize, "")).finish(
10551 fn_llvm_ty,10618 fg.builder.buildCall(fn_llvm_ty, asm_fn, &args, args.len, .C, .Auto, ""),
10552 asm_fn,10619 &fg.wip,
10553 &args,
10554 args.len,
10555 .C,
10556 .Auto,
10557 "",
10558 );10620 );
10559 return call;10621 return call;
10560 }10622 }
...@@ -10764,14 +10826,14 @@ fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {...@@ -10764,14 +10826,14 @@ fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
10764 }10826 }
10765}10827}
1076610828
10767fn toLlvmAtomicOrdering(atomic_order: std.builtin.AtomicOrder) llvm.AtomicOrdering {10829fn toLlvmAtomicOrdering(atomic_order: std.builtin.AtomicOrder) Builder.AtomicOrdering {
10768 return switch (atomic_order) {10830 return switch (atomic_order) {
10769 .Unordered => .Unordered,10831 .Unordered => .unordered,
10770 .Monotonic => .Monotonic,10832 .Monotonic => .monotonic,
10771 .Acquire => .Acquire,10833 .Acquire => .acquire,
10772 .Release => .Release,10834 .Release => .release,
10773 .AcqRel => .AcquireRelease,10835 .AcqRel => .acq_rel,
10774 .SeqCst => .SequentiallyConsistent,10836 .SeqCst => .seq_cst,
10775 };10837 };
10776}10838}
1077710839
...@@ -11718,12 +11780,40 @@ fn compilerRtIntBits(bits: u16) u16 {...@@ -11718,12 +11780,40 @@ fn compilerRtIntBits(bits: u16) u16 {
11718 return bits;11780 return bits;
11719}11781}
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
11721fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 {11811fn 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));
11723}11813}
1172411814
11725fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 {11815fn 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));
11727}11817}
1172811818
11729/// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location11819/// 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),...@@ -43,6 +43,8 @@ constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb),
4343
44pub const expected_fields_len = 32;44pub const expected_fields_len = 32;
45pub const expected_gep_indices_len = 8;45pub const expected_gep_indices_len = 8;
46pub const expected_cases_len = 8;
47pub const expected_incoming_len = 8;
4648
47pub const Options = struct {49pub const Options = struct {
48 allocator: Allocator,50 allocator: Allocator,
...@@ -186,6 +188,7 @@ pub const Type = enum(u32) {...@@ -186,6 +188,7 @@ pub const Type = enum(u32) {
186 pub const Function = struct {188 pub const Function = struct {
187 ret: Type,189 ret: Type,
188 params_len: u32,190 params_len: u32,
191 //params: [params_len]Value,
189192
190 pub const Kind = enum { normal, vararg };193 pub const Kind = enum { normal, vararg };
191 };194 };
...@@ -194,12 +197,18 @@ pub const Type = enum(u32) {...@@ -194,12 +197,18 @@ pub const Type = enum(u32) {
194 name: String,197 name: String,
195 types_len: u32,198 types_len: u32,
196 ints_len: u32,199 ints_len: u32,
200 //types: [types_len]Type,
201 //ints: [ints_len]u32,
197 };202 };
198203
199 pub const Vector = extern struct {204 pub const Vector = extern struct {
200 len: u32,205 len: u32,
201 child: Type,206 child: Type,
202207
208 fn length(self: Vector) u32 {
209 return self.len;
210 }
211
203 pub const Kind = enum { normal, scalable };212 pub const Kind = enum { normal, scalable };
204 };213 };
205214
...@@ -208,13 +217,14 @@ pub const Type = enum(u32) {...@@ -208,13 +217,14 @@ pub const Type = enum(u32) {
208 len_hi: u32,217 len_hi: u32,
209 child: Type,218 child: Type,
210219
211 fn len(self: Array) u64 {220 fn length(self: Array) u64 {
212 return @as(u64, self.len_hi) << 32 | self.len_lo;221 return @as(u64, self.len_hi) << 32 | self.len_lo;
213 }222 }
214 };223 };
215224
216 pub const Structure = struct {225 pub const Structure = struct {
217 fields_len: u32,226 fields_len: u32,
227 //fields: [fields_len]Type,
218228
219 pub const Kind = enum { normal, @"packed" };229 pub const Kind = enum { normal, @"packed" };
220 };230 };
...@@ -295,6 +305,29 @@ pub const Type = enum(u32) {...@@ -295,6 +305,29 @@ pub const Type = enum(u32) {
295 };305 };
296 }306 }
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
298 pub fn isVector(self: Type, builder: *const Builder) bool {331 pub fn isVector(self: Type, builder: *const Builder) bool {
299 return switch (self.tag(builder)) {332 return switch (self.tag(builder)) {
300 .vector, .scalable_vector => true,333 .vector, .scalable_vector => true,
...@@ -325,6 +358,13 @@ pub const Type = enum(u32) {...@@ -325,6 +358,13 @@ pub const Type = enum(u32) {
325 };358 };
326 }359 }
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
328 pub fn scalarBits(self: Type, builder: *const Builder) u24 {368 pub fn scalarBits(self: Type, builder: *const Builder) u24 {
329 return switch (self) {369 return switch (self) {
330 .void, .label, .token, .metadata, .none, .x86_amx => unreachable,370 .void, .label, .token, .metadata, .none, .x86_amx => unreachable,
...@@ -388,6 +428,33 @@ pub const Type = enum(u32) {...@@ -388,6 +428,33 @@ pub const Type = enum(u32) {
388 };428 };
389 }429 }
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
391 pub fn vectorLen(self: Type, builder: *const Builder) u32 {458 pub fn vectorLen(self: Type, builder: *const Builder) u32 {
392 const item = builder.type_items.items[@intFromEnum(self)];459 const item = builder.type_items.items[@intFromEnum(self)];
393 return switch (item.tag) {460 return switch (item.tag) {
...@@ -398,6 +465,37 @@ pub const Type = enum(u32) {...@@ -398,6 +465,37 @@ pub const Type = enum(u32) {
398 };465 };
399 }466 }
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
401 pub fn aggregateLen(self: Type, builder: *const Builder) u64 {499 pub fn aggregateLen(self: Type, builder: *const Builder) u64 {
402 const item = builder.type_items.items[@intFromEnum(self)];500 const item = builder.type_items.items[@intFromEnum(self)];
403 return switch (item.tag) {501 return switch (item.tag) {
...@@ -405,7 +503,7 @@ pub const Type = enum(u32) {...@@ -405,7 +503,7 @@ pub const Type = enum(u32) {
405 .scalable_vector,503 .scalable_vector,
406 .small_array,504 .small_array,
407 => builder.typeExtraData(Type.Vector, item.data).len,505 => 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(),
409 .structure,507 .structure,
410 .packed_structure,508 .packed_structure,
411 => builder.typeExtraData(Type.Structure, item.data).fields_len,509 => builder.typeExtraData(Type.Structure, item.data).fields_len,
...@@ -430,7 +528,40 @@ pub const Type = enum(u32) {...@@ -430,7 +528,40 @@ pub const Type = enum(u32) {
430 }528 }
431 }529 }
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 {
434 type: Type,565 type: Type,
435 builder: *const Builder,566 builder: *const Builder,
436 };567 };
...@@ -441,11 +572,90 @@ pub const Type = enum(u32) {...@@ -441,11 +572,90 @@ pub const Type = enum(u32) {
441 writer: anytype,572 writer: anytype,
442 ) @TypeOf(writer).Error!void {573 ) @TypeOf(writer).Error!void {
443 assert(data.type != .none);574 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 }
444 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);654 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
445 const item = data.builder.type_items.items[@intFromEnum(data.type)];655 const item = data.builder.type_items.items[@intFromEnum(data.type)];
446 switch (item.tag) {656 switch (item.tag) {
447 .simple => unreachable,657 .simple => unreachable,
448 .function, .vararg_function => {658 .function, .vararg_function => |kind| {
449 const extra = data.builder.typeExtraDataTrail(Type.Function, item.data);659 const extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
450 const params: []const Type =660 const params: []const Type =
451 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.params_len]);661 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.params_len]);
...@@ -457,7 +667,7 @@ pub const Type = enum(u32) {...@@ -457,7 +667,7 @@ pub const Type = enum(u32) {
457 if (index > 0) try writer.writeAll(", ");667 if (index > 0) try writer.writeAll(", ");
458 try writer.print("{%}", .{param.fmt(data.builder)});668 try writer.print("{%}", .{param.fmt(data.builder)});
459 }669 }
460 switch (item.tag) {670 switch (kind) {
461 .function => {},671 .function => {},
462 .vararg_function => {672 .vararg_function => {
463 if (params.len > 0) try writer.writeAll(", ");673 if (params.len > 0) try writer.writeAll(", ");
...@@ -483,29 +693,31 @@ pub const Type = enum(u32) {...@@ -483,29 +693,31 @@ pub const Type = enum(u32) {
483 for (ints) |int| try writer.print(", {d}", .{int});693 for (ints) |int| try writer.print(", {d}", .{int});
484 try writer.writeByte(')');694 try writer.writeByte(')');
485 },695 },
486 .vector => {696 .vector, .scalable_vector => |kind| {
487 const extra = data.builder.typeExtraData(Type.Vector, item.data);697 const extra = data.builder.typeExtraData(Type.Vector, item.data);
488 try writer.print("<{d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });698 try writer.print("<{s}{d} x {%}>", .{
489 },699 switch (kind) {
490 .scalable_vector => {700 .vector => "",
491 const extra = data.builder.typeExtraData(Type.Vector, item.data);701 .scalable_vector => "vscale x ",
492 try writer.print("<vscale x {d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });702 else => unreachable,
493 },703 },
494 .small_array => {704 extra.len,
495 const extra = data.builder.typeExtraData(Type.Vector, item.data);705 extra.child.fmt(data.builder),
496 try writer.print("[{d} x {%}]", .{ extra.len, extra.child.fmt(data.builder) });706 });
497 },707 },
498 .array => {708 inline .small_array, .array => |kind| {
499 const extra = data.builder.typeExtraData(Type.Array, item.data);709 const extra = data.builder.typeExtraData(switch (kind) {
500 try writer.print("[{d} x {%}]", .{ extra.len(), extra.child.fmt(data.builder) });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) });
501 },715 },
502 .structure,716 .structure, .packed_structure => |kind| {
503 .packed_structure,
504 => {
505 const extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);717 const extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
506 const fields: []const Type =718 const fields: []const Type =
507 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.fields_len]);719 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.fields_len]);
508 switch (item.tag) {720 switch (kind) {
509 .structure => {},721 .structure => {},
510 .packed_structure => try writer.writeByte('<'),722 .packed_structure => try writer.writeByte('<'),
511 else => unreachable,723 else => unreachable,
...@@ -516,7 +728,7 @@ pub const Type = enum(u32) {...@@ -516,7 +728,7 @@ pub const Type = enum(u32) {
516 try writer.print("{%}", .{field.fmt(data.builder)});728 try writer.print("{%}", .{field.fmt(data.builder)});
517 }729 }
518 try writer.writeAll(" }");730 try writer.writeAll(" }");
519 switch (item.tag) {731 switch (kind) {
520 .structure => {},732 .structure => {},
521 .packed_structure => try writer.writeByte('>'),733 .packed_structure => try writer.writeByte('>'),
522 else => unreachable,734 else => unreachable,
...@@ -544,6 +756,82 @@ pub const Type = enum(u32) {...@@ -544,6 +756,82 @@ pub const Type = enum(u32) {
544 assert(builder.useLibLlvm());756 assert(builder.useLibLlvm());
545 return builder.llvm.types.items[@intFromEnum(self)];757 return builder.llvm.types.items[@intFromEnum(self)];
546 }758 }
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 }
547};835};
548836
549pub const Linkage = enum {837pub const Linkage = enum {
...@@ -727,11 +1015,11 @@ pub const AddrSpace = enum(u24) {...@@ -727,11 +1015,11 @@ pub const AddrSpace = enum(u24) {
7271015
728 pub fn format(1016 pub fn format(
729 self: AddrSpace,1017 self: AddrSpace,
730 comptime _: []const u8,1018 comptime prefix: []const u8,
731 _: std.fmt.FormatOptions,1019 _: std.fmt.FormatOptions,
732 writer: anytype,1020 writer: anytype,
733 ) @TypeOf(writer).Error!void {1021 ) @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) });
735 }1023 }
736};1024};
7371025
...@@ -785,9 +1073,7 @@ pub const Global = struct {...@@ -785,9 +1073,7 @@ pub const Global = struct {
785 addr_space: AddrSpace = .default,1073 addr_space: AddrSpace = .default,
786 externally_initialized: ExternallyInitialized = .default,1074 externally_initialized: ExternallyInitialized = .default,
787 type: Type,1075 type: Type,
788 section: String = .none,
789 partition: String = .none,1076 partition: String = .none,
790 alignment: Alignment = .default,
791 kind: union(enum) {1077 kind: union(enum) {
792 alias: Alias.Index,1078 alias: Alias.Index,
793 variable: Variable.Index,1079 variable: Variable.Index,
...@@ -824,6 +1110,10 @@ pub const Global = struct {...@@ -824,6 +1110,10 @@ pub const Global = struct {
824 return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];1110 return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
825 }1111 }
8261112
1113 pub fn typeOf(self: Index, builder: *const Builder) Type {
1114 return self.ptrConst(builder).type;
1115 }
1116
827 pub fn toConst(self: Index) Constant {1117 pub fn toConst(self: Index) Constant {
828 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));1118 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));
829 }1119 }
...@@ -943,11 +1233,19 @@ pub const Global = struct {...@@ -943,11 +1233,19 @@ pub const Global = struct {
9431233
944pub const Alias = struct {1234pub const Alias = struct {
945 global: Global.Index,1235 global: Global.Index,
1236 thread_local: ThreadLocal = .default,
1237 init: Constant = .no_init,
9461238
947 pub const Index = enum(u32) {1239 pub const Index = enum(u32) {
948 none = std.math.maxInt(u32),1240 none = std.math.maxInt(u32),
949 _,1241 _,
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
951 pub fn ptr(self: Index, builder: *Builder) *Alias {1249 pub fn ptr(self: Index, builder: *Builder) *Alias {
952 return &builder.aliases.items[@intFromEnum(self)];1250 return &builder.aliases.items[@intFromEnum(self)];
953 }1251 }
...@@ -956,6 +1254,18 @@ pub const Alias = struct {...@@ -956,6 +1254,18 @@ pub const Alias = struct {
956 return &builder.aliases.items[@intFromEnum(self)];1254 return &builder.aliases.items[@intFromEnum(self)];
957 }1255 }
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
959 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {1269 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
960 return self.ptrConst(builder).global.toLlvm(builder);1270 return self.ptrConst(builder).global.toLlvm(builder);
961 }1271 }
...@@ -967,6 +1277,8 @@ pub const Variable = struct {...@@ -967,6 +1277,8 @@ pub const Variable = struct {
967 thread_local: ThreadLocal = .default,1277 thread_local: ThreadLocal = .default,
968 mutability: enum { global, constant } = .global,1278 mutability: enum { global, constant } = .global,
969 init: Constant = .no_init,1279 init: Constant = .no_init,
1280 section: String = .none,
1281 alignment: Alignment = .default,
9701282
971 pub const Index = enum(u32) {1283 pub const Index = enum(u32) {
972 none = std.math.maxInt(u32),1284 none = std.math.maxInt(u32),
...@@ -980,6 +1292,18 @@ pub const Variable = struct {...@@ -980,6 +1292,18 @@ pub const Variable = struct {
980 return &builder.variables.items[@intFromEnum(self)];1292 return &builder.variables.items[@intFromEnum(self)];
981 }1293 }
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
983 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {1307 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
984 return self.ptrConst(builder).global.toLlvm(builder);1308 return self.ptrConst(builder).global.toLlvm(builder);
985 }1309 }
...@@ -988,9 +1312,11 @@ pub const Variable = struct {...@@ -988,9 +1312,11 @@ pub const Variable = struct {
9881312
989pub const Function = struct {1313pub const Function = struct {
990 global: Global.Index,1314 global: Global.Index,
1315 section: String = .none,
1316 alignment: Alignment = .default,
991 blocks: []const Block = &.{},1317 blocks: []const Block = &.{},
992 instructions: std.MultiArrayList(Instruction) = .{},1318 instructions: std.MultiArrayList(Instruction) = .{},
993 names: ?[*]const String = null,1319 names: [*]const String = &[0]String{},
994 metadata: ?[*]const Metadata = null,1320 metadata: ?[*]const Metadata = null,
995 extra: []const u32 = &.{},1321 extra: []const u32 = &.{},
9961322
...@@ -1006,6 +1332,18 @@ pub const Function = struct {...@@ -1006,6 +1332,18 @@ pub const Function = struct {
1006 return &builder.functions.items[@intFromEnum(self)];1332 return &builder.functions.items[@intFromEnum(self)];
1007 }1333 }
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
1009 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {1347 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
1010 return self.ptrConst(builder).global.toLlvm(builder);1348 return self.ptrConst(builder).global.toLlvm(builder);
1011 }1349 }
...@@ -1021,82 +1359,843 @@ pub const Function = struct {...@@ -1021,82 +1359,843 @@ pub const Function = struct {
1021 tag: Tag,1359 tag: Tag,
1022 data: u32,1360 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",
1025 arg,1371 arg,
1372 ashr,
1373 @"ashr exact",
1374 bitcast,
1026 block,1375 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,
1028 ret,1472 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,
1029 };1505 };
10301506
1031 pub const Index = enum(u32) {1507 pub const Index = enum(u32) {
1508 none = std.math.maxInt(u31),
1032 _,1509 _,
10331510
1034 pub fn name(self: Instruction.Index, function: *const Function) String {1511 pub fn name(self: Instruction.Index, function: *const Function) String {
1035 return if (function.names) |names|1512 return function.names[@intFromEnum(self)];
1036 names[@intFromEnum(self)]
1037 else
1038 @enumFromInt(@intFromEnum(self));
1039 }1513 }
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 {1515 pub fn toValue(self: Instruction.Index) Value {
1070 name: String,1516 return @enumFromInt(@intFromEnum(self));
1071 incoming: u32,1517 }
1072 instructions: std.ArrayListUnmanaged(Instruction.Index),
10731518
1074 const Index = enum(u32) {1519 pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool {
1075 entry,1520 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
1076 _,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 {1531 pub fn hasResultWip(self: Instruction.Index, wip: *const WipFunction) bool {
1079 assert(wip.builder.useLibLlvm());1532 return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
1080 return wip.llvm.blocks.items[@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 };
1081 }1546 }
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 {1733 pub fn typeOf(
1088 if (builder.useLibLlvm()) {1734 self: Instruction.Index,
1089 const llvm_function = function.toLlvm(builder);1735 function_index: Function.Index,
1090 while (llvm_function.getFirstBasicBlock()) |bb| bb.deleteBasicBlock();1736 builder: *Builder,
1091 }1737 ) Type {
1092 return .{1738 const function = function_index.ptrConst(builder);
1093 .builder = builder,1739 const instruction = function.instructions.get(@intFromEnum(self));
1094 .function = function,1740 return switch (instruction.tag) {
1095 .llvm = if (builder.useLibLlvm()) .{1741 .add,
1096 .builder = builder.llvm.context.createBuilder(),1742 .@"add nsw",
1097 .blocks = .{},1743 .@"add nuw",
1098 .instructions = .{},1744 .@"add nuw nsw",
1099 } else undefined,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,
1100 .cursor = undefined,2199 .cursor = undefined,
1101 .blocks = .{},2200 .blocks = .{},
1102 .instructions = .{},2201 .instructions = .{},
...@@ -1104,102 +2203,1447 @@ pub const WipFunction = struct {...@@ -1104,102 +2203,1447 @@ pub const WipFunction = struct {
1104 .metadata = .{},2203 .metadata = .{},
1105 .extra = .{},2204 .extra = .{},
1106 };2205 };
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;
1107 }2223 }
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 {
1110 try self.blocks.ensureUnusedCapacity(self.builder.gpa, 1);2235 try self.blocks.ensureUnusedCapacity(self.builder.gpa, 1);
1111 if (self.builder.useLibLlvm()) try self.llvm.blocks.ensureUnusedCapacity(self.builder.gpa, 1);2236 if (self.builder.useLibLlvm()) try self.llvm.blocks.ensureUnusedCapacity(self.builder.gpa, 1);
11122237
1113 const index: Block.Index = @enumFromInt(self.blocks.items.len);2238 const index: Block.Index = @enumFromInt(self.blocks.items.len);
1114 const final_name = if (self.builder.strip) .empty else try self.builder.string(name);2239 const final_name = if (self.builder.strip) .empty else try self.builder.string(name);
1115 self.blocks.appendAssumeCapacity(.{ .name = final_name, .incoming = 0, .instructions = .{} });2240 self.blocks.appendAssumeCapacity(.{
1116 if (self.builder.useLibLlvm()) self.llvm.blocks.appendAssumeCapacity(2241 .name = final_name,
1117 self.builder.llvm.context.appendBasicBlock(2242 .incoming = incoming,
1118 self.function.toLlvm(self.builder),2243 .instructions = .{},
1119 final_name.toSlice(self.builder).?,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),
1120 ),3192 ),
1121 );3193 );
1122 return index;3194 return instruction.toValue();
1123 }3195 }
11243196
1125 pub fn retVoid(self: *WipFunction) Allocator.Error!void {3197 pub const WipUnimplemented = struct {
1126 _ = try self.addInst(.{ .tag = .@"ret void", .data = undefined }, .none);3198 instruction: Instruction.Index,
1127 if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(3199
1128 self.llvm.builder.buildRetVoid(),3200 pub fn finish(self: WipUnimplemented, val: *llvm.Value, wip: *WipFunction) Value {
1129 );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 };
1130 }3219 }
11313220
1132 pub fn finish(self: *WipFunction) Allocator.Error!void {3221 pub fn finish(self: *WipFunction) Allocator.Error!void {
1133 const gpa = self.builder.gpa;3222 const gpa = self.builder.gpa;
1134 const function = self.function.ptr(self.builder);3223 const function = self.function.ptr(self.builder);
3224 const params_len = self.function.typeOf(self.builder).functionParameters(self.builder).len;
1135 const final_instructions_len = self.blocks.items.len + self.instructions.len;3225 const final_instructions_len = self.blocks.items.len + self.instructions.len;
11363226
1137 const blocks = try gpa.alloc(Function.Block, self.blocks.items.len);3227 const blocks = try gpa.alloc(Function.Block, self.blocks.items.len);
1138 errdefer gpa.free(blocks);3228 errdefer gpa.free(blocks);
11393229
1140 const instructions = try gpa.alloc(Instruction.Index, self.instructions.len);3230 const instructions: struct {
1141 defer gpa.free(instructions);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);3245 const names = try gpa.alloc(String, final_instructions_len);
1144 errdefer if (names) |new_names| gpa.free(new_names);3246 errdefer gpa.free(names);
11453247
1146 const metadata =3248 const metadata =
1147 if (self.builder.strip) null else try gpa.alloc(Metadata, final_instructions_len);3249 if (self.builder.strip) null else try gpa.alloc(Metadata, final_instructions_len);
1148 errdefer if (metadata) |new_metadata| gpa.free(new_metadata);3250 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
1150 gpa.free(function.blocks);3291 gpa.free(function.blocks);
1151 function.blocks = &.{};3292 function.blocks = &.{};
1152 if (function.names) |old_names| gpa.free(old_names[0..function.instructions.len]);3293 gpa.free(function.names[0..function.instructions.len]);
1153 function.names = null;
1154 if (function.metadata) |old_metadata| gpa.free(old_metadata[0..function.instructions.len]);3294 if (function.metadata) |old_metadata| gpa.free(old_metadata[0..function.instructions.len]);
1155 function.metadata = null;3295 function.metadata = null;
3296 gpa.free(function.extra);
3297 function.extra = &.{};
11563298
1157 function.instructions.shrinkRetainingCapacity(0);3299 function.instructions.shrinkRetainingCapacity(0);
1158 try function.instructions.setCapacity(gpa, final_instructions_len);3300 try function.instructions.setCapacity(gpa, final_instructions_len);
1159 errdefer function.instructions.shrinkRetainingCapacity(0);3301 errdefer function.instructions.shrinkRetainingCapacity(0);
11603302
1161 {3303 {
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 }
1163 for (blocks, self.blocks.items) |*final_block, current_block| {3309 for (blocks, self.blocks.items) |*final_block, current_block| {
1164 final_block.instruction = final_instruction;3310 assert(current_block.incoming == current_block.branches);
1165 final_instruction = @enumFromInt(@intFromEnum(final_instruction) + 1);3311 final_block.instruction = final_instruction_index;
3312 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
1166 for (current_block.instructions.items) |instruction| {3313 for (current_block.instructions.items) |instruction| {
1167 instructions[@intFromEnum(instruction)] = final_instruction;3314 instructions.items[@intFromEnum(instruction)] = final_instruction_index;
1168 final_instruction = @enumFromInt(@intFromEnum(final_instruction) + 1);3315 final_instruction_index = @enumFromInt(@intFromEnum(final_instruction_index) + 1);
1169 }3316 }
1170 }3317 }
1171 }3318 }
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 }
1174 for (self.blocks.items) |current_block| {3342 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);
1176 function.instructions.appendAssumeCapacity(.{3344 function.instructions.appendAssumeCapacity(.{
1177 .tag = .block,3345 .tag = .block,
1178 .data = current_block.incoming,3346 .data = current_block.incoming,
1179 });3347 });
1180 if (names) |new_names|3348 names[@intFromEnum(new_block_index)] = wip_name.map(current_block.name);
1181 new_names[@intFromEnum(block_instruction)] = switch (current_block.name) {3349 for (current_block.instructions.items) |old_instruction_index| {
1182 .empty => name: {3350 const new_instruction_index: Instruction.Index =
1183 const name = next_name;3351 @enumFromInt(function.instructions.len);
1184 next_name = @enumFromInt(@intFromEnum(name) + 1);3352 var instruction = self.instructions.get(@intFromEnum(old_instruction_index));
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));
1191 switch (instruction.tag) {3353 switch (instruction.tag) {
1192 .block => unreachable,3354 .add,
1193 .@"ret void" => {},3355 .@"add nsw",
1194 else => unreachable,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 },
1195 }3634 }
1196 function.instructions.appendAssumeCapacity(instruction);3635 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)]);
1197 }3640 }
1198 }3641 }
11993642
1200 function.extra = try self.extra.toOwnedSlice(gpa);3643 assert(function.instructions.len == final_instructions_len);
3644 function.extra = wip_extra.finish();
1201 function.blocks = blocks;3645 function.blocks = blocks;
1202 function.names = if (names) |new_names| new_names.ptr else null;3646 function.names = names.ptr;
1203 function.metadata = if (metadata) |new_metadata| new_metadata.ptr else null;3647 function.metadata = if (metadata) |new_metadata| new_metadata.ptr else null;
1204 }3648 }
12053649
...@@ -1212,36 +3656,330 @@ pub const WipFunction = struct {...@@ -1212,36 +3656,330 @@ pub const WipFunction = struct {
1212 self.* = undefined;3656 self.* = undefined;
1213 }3657 }
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
1215 fn addInst(3915 fn addInst(
1216 self: *WipFunction,3916 self: *WipFunction,
3917 name: ?[]const u8,
1217 instruction: Instruction,3918 instruction: Instruction,
1218 name: String,
1219 ) Allocator.Error!Instruction.Index {3919 ) 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;
1221 try self.instructions.ensureUnusedCapacity(self.builder.gpa, 1);3921 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);
1223 try block_instructions.ensureUnusedCapacity(self.builder.gpa, 1);3923 try block_instructions.ensureUnusedCapacity(self.builder.gpa, 1);
1224 if (self.builder.useLibLlvm()) {3924 if (self.builder.useLibLlvm())
1225 try self.llvm.instructions.ensureUnusedCapacity(self.builder.gpa, 1);3925 try self.llvm.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
12263926 const final_name = if (name) |n|
1227 self.llvm.builder.positionBuilder(3927 if (self.builder.strip) .empty else try self.builder.string(n)
1228 self.cursor.block.toLlvm(self),3928 else
1229 if (self.cursor.instruction < block_instructions.items.len)3929 .none;
1230 self.llvm.instructions.items[3930
1231 @intFromEnum(block_instructions.items[self.cursor.instruction])3931 if (self.builder.useLibLlvm()) self.llvm.builder.positionBuilder(
1232 ]3932 self.cursor.block.toLlvm(self),
1233 else3933 for (block_instructions.items[self.cursor.instruction..]) |instruction_index| {
1234 null,3934 const llvm_instruction =
1235 );3935 self.llvm.instructions.items[@intFromEnum(instruction_index)];
1236 }3936 // TODO: remove when constant propagation is implemented
3937 if (!llvm_instruction.isConstant().toBool()) break llvm_instruction;
3938 } else null,
3939 );
12373940
1238 const index: Instruction.Index = @enumFromInt(self.instructions.len);3941 const index: Instruction.Index = @enumFromInt(self.instructions.len);
1239 self.instructions.appendAssumeCapacity(instruction);3942 self.instructions.appendAssumeCapacity(instruction);
1240 self.names.appendAssumeCapacity(name);3943 if (!self.builder.strip) self.names.appendAssumeCapacity(final_name);
1241 block_instructions.insertAssumeCapacity(self.cursor.instruction, index);3944 block_instructions.insertAssumeCapacity(self.cursor.instruction, index);
1242 self.cursor.instruction += 1;3945 self.cursor.instruction += 1;
1243 return index;3946 return index;
1244 }3947 }
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 }
1245};3983};
12463984
1247pub const FloatCondition = enum(u4) {3985pub const FloatCondition = enum(u4) {
...@@ -1274,6 +4012,73 @@ pub const IntegerCondition = enum(u6) {...@@ -1274,6 +4012,73 @@ pub const IntegerCondition = enum(u6) {
1274 sle = 41,4012 sle = 41,
1275};4013};
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
1277pub const Constant = enum(u32) {4082pub const Constant = enum(u32) {
1278 false,4083 false,
1279 true,4084 true,
...@@ -1379,6 +4184,7 @@ pub const Constant = enum(u32) {...@@ -1379,6 +4184,7 @@ pub const Constant = enum(u32) {
13794184
1380 pub const Aggregate = struct {4185 pub const Aggregate = struct {
1381 type: Type,4186 type: Type,
4187 //fields: [type.aggregateLen(builder)]Constant,
1382 };4188 };
13834189
1384 pub const Splat = extern struct {4190 pub const Splat = extern struct {
...@@ -1391,12 +4197,8 @@ pub const Constant = enum(u32) {...@@ -1391,12 +4197,8 @@ pub const Constant = enum(u32) {
1391 block: Function.Block.Index,4197 block: Function.Block.Index,
1392 };4198 };
13934199
1394 pub const FunctionReference = struct {
1395 function: Function.Index,
1396 };
1397
1398 pub const Cast = extern struct {4200 pub const Cast = extern struct {
1399 arg: Constant,4201 val: Constant,
1400 type: Type,4202 type: Type,
14014203
1402 pub const Signedness = enum { unsigned, signed, unneeded };4204 pub const Signedness = enum { unsigned, signed, unneeded };
...@@ -1405,9 +4207,12 @@ pub const Constant = enum(u32) {...@@ -1405,9 +4207,12 @@ pub const Constant = enum(u32) {
1405 pub const GetElementPtr = struct {4207 pub const GetElementPtr = struct {
1406 type: Type,4208 type: Type,
1407 base: Constant,4209 base: Constant,
1408 indices_len: u32,4210 info: Info,
4211 //indices: [info.indices_len]Constant,
14094212
1410 pub const Kind = enum { normal, inbounds };4213 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 };
1411 };4216 };
14124217
1413 pub const Compare = extern struct {4218 pub const Compare = extern struct {
...@@ -1417,12 +4222,12 @@ pub const Constant = enum(u32) {...@@ -1417,12 +4222,12 @@ pub const Constant = enum(u32) {
1417 };4222 };
14184223
1419 pub const ExtractElement = extern struct {4224 pub const ExtractElement = extern struct {
1420 arg: Constant,4225 val: Constant,
1421 index: Constant,4226 index: Constant,
1422 };4227 };
14234228
1424 pub const InsertElement = extern struct {4229 pub const InsertElement = extern struct {
1425 arg: Constant,4230 val: Constant,
1426 elem: Constant,4231 elem: Constant,
1427 index: Constant,4232 index: Constant,
1428 };4233 };
...@@ -1448,6 +4253,10 @@ pub const Constant = enum(u32) {...@@ -1448,6 +4253,10 @@ pub const Constant = enum(u32) {
1448 .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };4253 .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
1449 }4254 }
14504255
4256 pub fn toValue(self: Constant) Value {
4257 return @enumFromInt(@intFromEnum(Value.first_constant) + @intFromEnum(self));
4258 }
4259
1451 pub fn typeOf(self: Constant, builder: *Builder) Type {4260 pub fn typeOf(self: Constant, builder: *Builder) Type {
1452 switch (self.unwrap()) {4261 switch (self.unwrap()) {
1453 .constant => |constant| {4262 .constant => |constant| {
...@@ -1491,10 +4300,8 @@ pub const Constant = enum(u32) {...@@ -1491,10 +4300,8 @@ pub const Constant = enum(u32) {
1491 ),4300 ),
1492 .dso_local_equivalent,4301 .dso_local_equivalent,
1493 .no_cfi,4302 .no_cfi,
1494 => builder.ptrTypeAssumeCapacity(4303 => builder.ptrTypeAssumeCapacity(@as(Function.Index, @enumFromInt(item.data))
1495 builder.constantExtraData(FunctionReference, item.data)4304 .ptrConst(builder).global.ptrConst(builder).addr_space),
1496 .function.ptrConst(builder).global.ptrConst(builder).addr_space,
1497 ),
1498 .trunc,4305 .trunc,
1499 .zext,4306 .zext,
1500 .sext,4307 .sext,
...@@ -1514,42 +4321,29 @@ pub const Constant = enum(u32) {...@@ -1514,42 +4321,29 @@ pub const Constant = enum(u32) {
1514 => {4321 => {
1515 const extra = builder.constantExtraDataTrail(GetElementPtr, item.data);4322 const extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
1516 const indices: []const Constant = @ptrCast(builder.constant_extra4323 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]);
1518 const base_ty = extra.data.base.typeOf(builder);4325 const base_ty = extra.data.base.typeOf(builder);
1519 if (!base_ty.isVector(builder)) for (indices) |index| {4326 if (!base_ty.isVector(builder)) for (indices) |index| {
1520 const index_ty = index.typeOf(builder);4327 const index_ty = index.typeOf(builder);
1521 if (!index_ty.isVector(builder)) continue;4328 if (!index_ty.isVector(builder)) continue;
1522 switch (index_ty.vectorKind(builder)) {4329 return index_ty.changeScalarAssumeCapacity(base_ty, builder);
1523 inline else => |kind| return builder.vectorTypeAssumeCapacity(
1524 kind,
1525 index_ty.vectorLen(builder),
1526 base_ty,
1527 ),
1528 }
1529 };4330 };
1530 return base_ty;4331 return base_ty;
1531 },4332 },
1532 .icmp, .fcmp => {4333 .icmp,
1533 const ty = builder.constantExtraData(Compare, item.data).lhs.typeOf(builder);4334 .fcmp,
1534 return if (ty.isVector(builder)) switch (ty.vectorKind(builder)) {4335 => builder.constantExtraData(Compare, item.data).lhs.typeOf(builder)
1535 inline else => |kind| builder4336 .changeScalarAssumeCapacity(.i1, builder),
1536 .vectorTypeAssumeCapacity(kind, ty.vectorLen(builder), .i1),
1537 } else ty;
1538 },
1539 .extractelement => builder.constantExtraData(ExtractElement, item.data)4337 .extractelement => builder.constantExtraData(ExtractElement, item.data)
1540 .arg.typeOf(builder).childType(builder),4338 .val.typeOf(builder).childType(builder),
1541 .insertelement => builder.constantExtraData(InsertElement, item.data)4339 .insertelement => builder.constantExtraData(InsertElement, item.data)
1542 .arg.typeOf(builder),4340 .val.typeOf(builder),
1543 .shufflevector => {4341 .shufflevector => {
1544 const extra = builder.constantExtraData(ShuffleVector, item.data);4342 const extra = builder.constantExtraData(ShuffleVector, item.data);
1545 const ty = extra.lhs.typeOf(builder);4343 return extra.lhs.typeOf(builder).changeLengthAssumeCapacity(
1546 return switch (ty.vectorKind(builder)) {4344 extra.mask.typeOf(builder).vectorLen(builder),
1547 inline else => |kind| builder.vectorTypeAssumeCapacity(4345 builder,
1548 kind,4346 );
1549 extra.mask.typeOf(builder).vectorLen(builder),
1550 ty.childType(builder),
1551 ),
1552 };
1553 },4347 },
1554 .add,4348 .add,
1555 .@"add nsw",4349 .@"add nsw",
...@@ -1617,7 +4411,42 @@ pub const Constant = enum(u32) {...@@ -1617,7 +4411,42 @@ pub const Constant = enum(u32) {
1617 }4411 }
1618 }4412 }
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 {
1621 constant: Constant,4450 constant: Constant,
1622 builder: *Builder,4451 builder: *Builder,
1623 };4452 };
...@@ -1627,12 +4456,18 @@ pub const Constant = enum(u32) {...@@ -1627,12 +4456,18 @@ pub const Constant = enum(u32) {
1627 _: std.fmt.FormatOptions,4456 _: std.fmt.FormatOptions,
1628 writer: anytype,4457 writer: anytype,
1629 ) @TypeOf(writer).Error!void {4458 ) @TypeOf(writer).Error!void {
1630 if (comptime std.mem.eql(u8, fmt_str, "%")) {4459 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
1631 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});4460 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1632 } else if (comptime std.mem.eql(u8, 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) {
1633 if (data.constant == .no_init) return;4466 if (data.constant == .no_init) return;
1634 try writer.writeByte(' ');4467 try writer.writeByte(' ');
1635 }4468 }
4469 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null)
4470 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
1636 assert(data.constant != .no_init);4471 assert(data.constant != .no_init);
1637 if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);4472 if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
1638 switch (data.constant.unwrap()) {4473 switch (data.constant.unwrap()) {
...@@ -1770,10 +4605,10 @@ pub const Constant = enum(u32) {...@@ -1770,10 +4605,10 @@ pub const Constant = enum(u32) {
1770 .dso_local_equivalent,4605 .dso_local_equivalent,
1771 .no_cfi,4606 .no_cfi,
1772 => |tag| {4607 => |tag| {
1773 const extra = data.builder.constantExtraData(FunctionReference, item.data);4608 const function: Function.Index = @enumFromInt(item.data);
1774 try writer.print("{s} {}", .{4609 try writer.print("{s} {}", .{
1775 @tagName(tag),4610 @tagName(tag),
1776 extra.function.ptrConst(data.builder).global.fmt(data.builder),4611 function.ptrConst(data.builder).global.fmt(data.builder),
1777 });4612 });
1778 },4613 },
1779 .trunc,4614 .trunc,
...@@ -1793,7 +4628,7 @@ pub const Constant = enum(u32) {...@@ -1793,7 +4628,7 @@ pub const Constant = enum(u32) {
1793 const extra = data.builder.constantExtraData(Cast, item.data);4628 const extra = data.builder.constantExtraData(Cast, item.data);
1794 try writer.print("{s} ({%} to {%})", .{4629 try writer.print("{s} ({%} to {%})", .{
1795 @tagName(tag),4630 @tagName(tag),
1796 extra.arg.fmt(data.builder),4631 extra.val.fmt(data.builder),
1797 extra.type.fmt(data.builder),4632 extra.type.fmt(data.builder),
1798 });4633 });
1799 },4634 },
...@@ -1802,7 +4637,7 @@ pub const Constant = enum(u32) {...@@ -1802,7 +4637,7 @@ pub const Constant = enum(u32) {
1802 => |tag| {4637 => |tag| {
1803 const extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);4638 const extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
1804 const indices: []const Constant = @ptrCast(data.builder.constant_extra4639 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]);
1806 try writer.print("{s} ({%}, {%}", .{4641 try writer.print("{s} ({%}, {%}", .{
1807 @tagName(tag),4642 @tagName(tag),
1808 extra.data.type.fmt(data.builder),4643 extra.data.type.fmt(data.builder),
...@@ -1830,7 +4665,7 @@ pub const Constant = enum(u32) {...@@ -1830,7 +4665,7 @@ pub const Constant = enum(u32) {
1830 const extra = data.builder.constantExtraData(ExtractElement, item.data);4665 const extra = data.builder.constantExtraData(ExtractElement, item.data);
1831 try writer.print("{s} ({%}, {%})", .{4666 try writer.print("{s} ({%}, {%})", .{
1832 @tagName(tag),4667 @tagName(tag),
1833 extra.arg.fmt(data.builder),4668 extra.val.fmt(data.builder),
1834 extra.index.fmt(data.builder),4669 extra.index.fmt(data.builder),
1835 });4670 });
1836 },4671 },
...@@ -1838,7 +4673,7 @@ pub const Constant = enum(u32) {...@@ -1838,7 +4673,7 @@ pub const Constant = enum(u32) {
1838 const extra = data.builder.constantExtraData(InsertElement, item.data);4673 const extra = data.builder.constantExtraData(InsertElement, item.data);
1839 try writer.print("{s} ({%}, {%}, {%})", .{4674 try writer.print("{s} ({%}, {%}, {%})", .{
1840 @tagName(tag),4675 @tagName(tag),
1841 extra.arg.fmt(data.builder),4676 extra.val.fmt(data.builder),
1842 extra.elem.fmt(data.builder),4677 extra.elem.fmt(data.builder),
1843 extra.index.fmt(data.builder),4678 extra.index.fmt(data.builder),
1844 });4679 });
...@@ -1894,6 +4729,7 @@ pub const Constant = enum(u32) {...@@ -1894,6 +4729,7 @@ pub const Constant = enum(u32) {
1894};4729};
18954730
1896pub const Value = enum(u32) {4731pub const Value = enum(u32) {
4732 none = std.math.maxInt(u31),
1897 _,4733 _,
18984734
1899 const first_constant: Value = @enumFromInt(1 << 31);4735 const first_constant: Value = @enumFromInt(1 << 31);
...@@ -1903,10 +4739,65 @@ pub const Value = enum(u32) {...@@ -1903,10 +4739,65 @@ pub const Value = enum(u32) {
1903 constant: Constant,4739 constant: Constant,
1904 } {4740 } {
1905 return if (@intFromEnum(self) < @intFromEnum(first_constant))4741 return if (@intFromEnum(self) < @intFromEnum(first_constant))
1906 .{ .instruction = @intFromEnum(self) }4742 .{ .instruction = @enumFromInt(@intFromEnum(self)) }
1907 else4743 else
1908 .{ .constant = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_constant)) };4744 .{ .constant = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_constant)) };
1909 }4745 }
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 }
1910};4801};
19114802
1912pub const Metadata = enum(u32) { _ };4803pub const Metadata = enum(u32) { _ };
...@@ -2297,12 +5188,12 @@ pub fn fnType(...@@ -2297,12 +5188,12 @@ pub fn fnType(
2297}5188}
22985189
2299pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {5190pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
2300 try self.ensureUnusedTypeCapacity(1, null, 0);5191 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
2301 return self.intTypeAssumeCapacity(bits);5192 return self.intTypeAssumeCapacity(bits);
2302}5193}
23035194
2304pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {5195pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {
2305 try self.ensureUnusedTypeCapacity(1, null, 0);5196 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
2306 return self.ptrTypeAssumeCapacity(addr_space);5197 return self.ptrTypeAssumeCapacity(addr_space);
2307}5198}
23085199
...@@ -2376,7 +5267,7 @@ pub fn namedTypeSetBody(...@@ -2376,7 +5267,7 @@ pub fn namedTypeSetBody(
23765267
2377pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {5268pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
2378 assert(!name.isAnon());5269 assert(!name.isAnon());
2379 try self.ensureUnusedTypeCapacity(1, null, 0);5270 try self.ensureUnusedTypeCapacity(1, NoExtra, 0);
2380 try self.ensureUnusedGlobalCapacity(name);5271 try self.ensureUnusedGlobalCapacity(name);
2381 return self.addGlobalAssumeCapacity(name, global);5272 return self.addGlobalAssumeCapacity(name, global);
2382}5273}
...@@ -2422,6 +5313,10 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta...@@ -2422,6 +5313,10 @@ pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Consta
2422 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());5313 return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());
2423}5314}
24245315
5316pub fn intValue(self: *Builder, ty: Type, value: anytype) Allocator.Error!Value {
5317 return (try self.intConst(ty, value)).toValue();
5318}
5319
2425pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Constant {5320pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Constant {
2426 try self.constant_map.ensureUnusedCapacity(self.gpa, 1);5321 try self.constant_map.ensureUnusedCapacity(self.gpa, 1);
2427 try self.constant_items.ensureUnusedCapacity(self.gpa, 1);5322 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...@@ -2430,6 +5325,10 @@ pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allo
2430 return self.bigIntConstAssumeCapacity(ty, value);5325 return self.bigIntConstAssumeCapacity(ty, value);
2431}5326}
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
2433pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator.Error!Constant {5332pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator.Error!Constant {
2434 return switch (ty) {5333 return switch (ty) {
2435 .half => try self.halfConst(val),5334 .half => try self.halfConst(val),
...@@ -2438,88 +5337,169 @@ pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator...@@ -2438,88 +5337,169 @@ pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator
2438 .double => try self.doubleConst(val),5337 .double => try self.doubleConst(val),
2439 .fp128 => try self.fp128Const(val),5338 .fp128 => try self.fp128Const(val),
2440 .x86_fp80 => try self.x86_fp80Const(val),5339 .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),
2442 else => unreachable,5358 else => unreachable,
2443 };5359 };
2444}5360}
24455361
5362pub fn nanValue(self: *Builder, ty: Type) Allocator.Error!Value {
5363 return (try self.nanConst(ty)).toValue();
5364}
5365
2446pub fn halfConst(self: *Builder, val: f16) Allocator.Error!Constant {5366pub fn halfConst(self: *Builder, val: f16) Allocator.Error!Constant {
2447 try self.ensureUnusedConstantCapacity(1, null, 0);5367 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
2448 return self.halfConstAssumeCapacity(val);5368 return self.halfConstAssumeCapacity(val);
2449}5369}
24505370
5371pub fn halfValue(self: *Builder, ty: Type, value: f16) Allocator.Error!Value {
5372 return (try self.halfConst(ty, value)).toValue();
5373}
5374
2451pub fn bfloatConst(self: *Builder, val: f32) Allocator.Error!Constant {5375pub fn bfloatConst(self: *Builder, val: f32) Allocator.Error!Constant {
2452 try self.ensureUnusedConstantCapacity(1, null, 0);5376 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
2453 return self.bfloatConstAssumeCapacity(val);5377 return self.bfloatConstAssumeCapacity(val);
2454}5378}
24555379
5380pub fn bfloatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
5381 return (try self.bfloatConst(ty, value)).toValue();
5382}
5383
2456pub fn floatConst(self: *Builder, val: f32) Allocator.Error!Constant {5384pub fn floatConst(self: *Builder, val: f32) Allocator.Error!Constant {
2457 try self.ensureUnusedConstantCapacity(1, null, 0);5385 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
2458 return self.floatConstAssumeCapacity(val);5386 return self.floatConstAssumeCapacity(val);
2459}5387}
24605388
5389pub fn floatValue(self: *Builder, ty: Type, value: f32) Allocator.Error!Value {
5390 return (try self.floatConst(ty, value)).toValue();
5391}
5392
2461pub fn doubleConst(self: *Builder, val: f64) Allocator.Error!Constant {5393pub fn doubleConst(self: *Builder, val: f64) Allocator.Error!Constant {
2462 try self.ensureUnusedConstantCapacity(1, Constant.Double, 0);5394 try self.ensureUnusedConstantCapacity(1, Constant.Double, 0);
2463 return self.doubleConstAssumeCapacity(val);5395 return self.doubleConstAssumeCapacity(val);
2464}5396}
24655397
5398pub fn doubleValue(self: *Builder, ty: Type, value: f64) Allocator.Error!Value {
5399 return (try self.doubleConst(ty, value)).toValue();
5400}
5401
2466pub fn fp128Const(self: *Builder, val: f128) Allocator.Error!Constant {5402pub fn fp128Const(self: *Builder, val: f128) Allocator.Error!Constant {
2467 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);5403 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
2468 return self.fp128ConstAssumeCapacity(val);5404 return self.fp128ConstAssumeCapacity(val);
2469}5405}
24705406
5407pub fn fp128Value(self: *Builder, ty: Type, value: f128) Allocator.Error!Value {
5408 return (try self.fp128Const(ty, value)).toValue();
5409}
5410
2471pub fn x86_fp80Const(self: *Builder, val: f80) Allocator.Error!Constant {5411pub fn x86_fp80Const(self: *Builder, val: f80) Allocator.Error!Constant {
2472 try self.ensureUnusedConstantCapacity(1, Constant.Fp80, 0);5412 try self.ensureUnusedConstantCapacity(1, Constant.Fp80, 0);
2473 return self.x86_fp80ConstAssumeCapacity(val);5413 return self.x86_fp80ConstAssumeCapacity(val);
2474}5414}
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
2476pub fn ppc_fp128Const(self: *Builder, val: [2]f64) Allocator.Error!Constant {5420pub fn ppc_fp128Const(self: *Builder, val: [2]f64) Allocator.Error!Constant {
2477 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);5421 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
2478 return self.ppc_fp128ConstAssumeCapacity(val);5422 return self.ppc_fp128ConstAssumeCapacity(val);
2479}5423}
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
2481pub fn nullConst(self: *Builder, ty: Type) Allocator.Error!Constant {5429pub fn nullConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2482 try self.ensureUnusedConstantCapacity(1, null, 0);5430 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
2483 return self.nullConstAssumeCapacity(ty);5431 return self.nullConstAssumeCapacity(ty);
2484}5432}
24855433
5434pub fn nullValue(self: *Builder, ty: Type) Allocator.Error!Value {
5435 return (try self.nullConst(ty)).toValue();
5436}
5437
2486pub fn noneConst(self: *Builder, ty: Type) Allocator.Error!Constant {5438pub fn noneConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2487 try self.ensureUnusedConstantCapacity(1, null, 0);5439 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
2488 return self.noneConstAssumeCapacity(ty);5440 return self.noneConstAssumeCapacity(ty);
2489}5441}
24905442
5443pub fn noneValue(self: *Builder, ty: Type) Allocator.Error!Value {
5444 return (try self.noneConst(ty)).toValue();
5445}
5446
2491pub fn structConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {5447pub fn structConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
2492 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);5448 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
2493 return self.structConstAssumeCapacity(ty, vals);5449 return self.structConstAssumeCapacity(ty, vals);
2494}5450}
24955451
5452pub fn structValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
5453 return (try self.structConst(ty, vals)).toValue();
5454}
5455
2496pub fn arrayConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {5456pub fn arrayConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
2497 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);5457 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
2498 return self.arrayConstAssumeCapacity(ty, vals);5458 return self.arrayConstAssumeCapacity(ty, vals);
2499}5459}
25005460
5461pub fn arrayValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
5462 return (try self.arrayConst(ty, vals)).toValue();
5463}
5464
2501pub fn stringConst(self: *Builder, val: String) Allocator.Error!Constant {5465pub fn stringConst(self: *Builder, val: String) Allocator.Error!Constant {
2502 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);5466 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
2503 try self.ensureUnusedConstantCapacity(1, null, 0);5467 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
2504 return self.stringConstAssumeCapacity(val);5468 return self.stringConstAssumeCapacity(val);
2505}5469}
25065470
5471pub fn stringValue(self: *Builder, val: String) Allocator.Error!Value {
5472 return (try self.stringConst(val)).toValue();
5473}
5474
2507pub fn stringNullConst(self: *Builder, val: String) Allocator.Error!Constant {5475pub fn stringNullConst(self: *Builder, val: String) Allocator.Error!Constant {
2508 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);5476 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
2509 try self.ensureUnusedConstantCapacity(1, null, 0);5477 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
2510 return self.stringNullConstAssumeCapacity(val);5478 return self.stringNullConstAssumeCapacity(val);
2511}5479}
25125480
5481pub fn stringNullValue(self: *Builder, val: String) Allocator.Error!Value {
5482 return (try self.stringNullConst(val)).toValue();
5483}
5484
2513pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {5485pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
2514 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);5486 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
2515 return self.vectorConstAssumeCapacity(ty, vals);5487 return self.vectorConstAssumeCapacity(ty, vals);
2516}5488}
25175489
5490pub fn vectorValue(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Value {
5491 return (try self.vectorConst(ty, vals)).toValue();
5492}
5493
2518pub fn splatConst(self: *Builder, ty: Type, val: Constant) Allocator.Error!Constant {5494pub fn splatConst(self: *Builder, ty: Type, val: Constant) Allocator.Error!Constant {
2519 try self.ensureUnusedConstantCapacity(1, Constant.Splat, 0);5495 try self.ensureUnusedConstantCapacity(1, Constant.Splat, 0);
2520 return self.splatConstAssumeCapacity(ty, val);5496 return self.splatConstAssumeCapacity(ty, val);
2521}5497}
25225498
5499pub fn splatValue(self: *Builder, ty: Type, val: Constant) Allocator.Error!Value {
5500 return (try self.splatConst(ty, val)).toValue();
5501}
5502
2523pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {5503pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2524 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);5504 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
2525 try self.constant_limbs.ensureUnusedCapacity(5505 try self.constant_limbs.ensureUnusedCapacity(
...@@ -2529,16 +5509,28 @@ pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {...@@ -2529,16 +5509,28 @@ pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2529 return self.zeroInitConstAssumeCapacity(ty);5509 return self.zeroInitConstAssumeCapacity(ty);
2530}5510}
25315511
5512pub fn zeroInitValue(self: *Builder, ty: Type) Allocator.Error!Value {
5513 return (try self.zeroInitConst(ty)).toValue();
5514}
5515
2532pub fn undefConst(self: *Builder, ty: Type) Allocator.Error!Constant {5516pub fn undefConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2533 try self.ensureUnusedConstantCapacity(1, null, 0);5517 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
2534 return self.undefConstAssumeCapacity(ty);5518 return self.undefConstAssumeCapacity(ty);
2535}5519}
25365520
5521pub fn undefValue(self: *Builder, ty: Type) Allocator.Error!Value {
5522 return (try self.undefConst(ty)).toValue();
5523}
5524
2537pub fn poisonConst(self: *Builder, ty: Type) Allocator.Error!Constant {5525pub fn poisonConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2538 try self.ensureUnusedConstantCapacity(1, null, 0);5526 try self.ensureUnusedConstantCapacity(1, NoExtra, 0);
2539 return self.poisonConstAssumeCapacity(ty);5527 return self.poisonConstAssumeCapacity(ty);
2540}5528}
25415529
5530pub fn poisonValue(self: *Builder, ty: Type) Allocator.Error!Value {
5531 return (try self.poisonConst(ty)).toValue();
5532}
5533
2542pub fn blockAddrConst(5534pub fn blockAddrConst(
2543 self: *Builder,5535 self: *Builder,
2544 function: Function.Index,5536 function: Function.Index,
...@@ -2548,29 +5540,58 @@ pub fn blockAddrConst(...@@ -2548,29 +5540,58 @@ pub fn blockAddrConst(
2548 return self.blockAddrConstAssumeCapacity(function, block);5540 return self.blockAddrConstAssumeCapacity(function, block);
2549}5541}
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
2551pub fn dsoLocalEquivalentConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {5551pub 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);
2553 return self.dsoLocalEquivalentConstAssumeCapacity(function);5553 return self.dsoLocalEquivalentConstAssumeCapacity(function);
2554}5554}
25555555
5556pub fn dsoLocalEquivalentValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
5557 return (try self.dsoLocalEquivalentConst(function)).toValue();
5558}
5559
2556pub fn noCfiConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {5560pub 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);
2558 return self.noCfiConstAssumeCapacity(function);5562 return self.noCfiConstAssumeCapacity(function);
2559}5563}
25605564
5565pub fn noCfiValue(self: *Builder, function: Function.Index) Allocator.Error!Value {
5566 return (try self.noCfiConst(function)).toValue();
5567}
5568
2561pub fn convConst(5569pub fn convConst(
2562 self: *Builder,5570 self: *Builder,
2563 signedness: Constant.Cast.Signedness,5571 signedness: Constant.Cast.Signedness,
2564 arg: Constant,5572 val: Constant,
2565 ty: Type,5573 ty: Type,
2566) Allocator.Error!Constant {5574) Allocator.Error!Constant {
2567 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);5575 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();
2569}5586}
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 {
2572 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);5589 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();
2574}5595}
25755596
2576pub fn gepConst(5597pub fn gepConst(
...@@ -2578,11 +5599,23 @@ pub fn gepConst(...@@ -2578,11 +5599,23 @@ pub fn gepConst(
2578 comptime kind: Constant.GetElementPtr.Kind,5599 comptime kind: Constant.GetElementPtr.Kind,
2579 ty: Type,5600 ty: Type,
2580 base: Constant,5601 base: Constant,
5602 inrange: ?u16,
2581 indices: []const Constant,5603 indices: []const Constant,
2582) Allocator.Error!Constant {5604) Allocator.Error!Constant {
2583 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);5605 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
2584 try self.ensureUnusedConstantCapacity(1, Constant.GetElementPtr, indices.len);5606 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();
2586}5619}
25875620
2588pub fn icmpConst(5621pub fn icmpConst(
...@@ -2595,6 +5628,15 @@ pub fn icmpConst(...@@ -2595,6 +5628,15 @@ pub fn icmpConst(
2595 return self.icmpConstAssumeCapacity(cond, lhs, rhs);5628 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
2596}5629}
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
2598pub fn fcmpConst(5640pub fn fcmpConst(
2599 self: *Builder,5641 self: *Builder,
2600 cond: FloatCondition,5642 cond: FloatCondition,
...@@ -2605,19 +5647,41 @@ pub fn fcmpConst(...@@ -2605,19 +5647,41 @@ pub fn fcmpConst(
2605 return self.icmpConstAssumeCapacity(cond, lhs, rhs);5647 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
2606}5648}
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 {
2609 try self.ensureUnusedConstantCapacity(1, Constant.ExtractElement, 0);5660 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();
2611}5666}
26125667
2613pub fn insertElementConst(5668pub fn insertElementConst(
2614 self: *Builder,5669 self: *Builder,
2615 arg: Constant,5670 val: Constant,
2616 elem: Constant,5671 elem: Constant,
2617 index: Constant,5672 index: Constant,
2618) Allocator.Error!Constant {5673) Allocator.Error!Constant {
2619 try self.ensureUnusedConstantCapacity(1, Constant.InsertElement, 0);5674 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();
2621}5685}
26225686
2623pub fn shuffleVectorConst(5687pub fn shuffleVectorConst(
...@@ -2626,10 +5690,20 @@ pub fn shuffleVectorConst(...@@ -2626,10 +5690,20 @@ pub fn shuffleVectorConst(
2626 rhs: Constant,5690 rhs: Constant,
2627 mask: Constant,5691 mask: Constant,
2628) Allocator.Error!Constant {5692) Allocator.Error!Constant {
5693 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
2629 try self.ensureUnusedConstantCapacity(1, Constant.ShuffleVector, 0);5694 try self.ensureUnusedConstantCapacity(1, Constant.ShuffleVector, 0);
2630 return self.shuffleVectorConstAssumeCapacity(lhs, rhs, mask);5695 return self.shuffleVectorConstAssumeCapacity(lhs, rhs, mask);
2631}5696}
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
2633pub fn binConst(5707pub fn binConst(
2634 self: *Builder,5708 self: *Builder,
2635 tag: Constant.Tag,5709 tag: Constant.Tag,
...@@ -2640,6 +5714,10 @@ pub fn binConst(...@@ -2640,6 +5714,10 @@ pub fn binConst(
2640 return self.binConstAssumeCapacity(tag, lhs, rhs);5714 return self.binConstAssumeCapacity(tag, lhs, rhs);
2641}5715}
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
2643pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void {5721pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void {
2644 if (self.source_filename != .none) try writer.print(5722 if (self.source_filename != .none) try writer.print(
2645 \\; ModuleID = '{s}'5723 \\; ModuleID = '{s}'
...@@ -2679,17 +5757,15 @@ pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator...@@ -2679,17 +5757,15 @@ pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator
2679 @tagName(variable.mutability),5757 @tagName(variable.mutability),
2680 global.type.fmt(self),5758 global.type.fmt(self),
2681 variable.init.fmt(self),5759 variable.init.fmt(self),
2682 global.alignment,5760 variable.alignment,
2683 });5761 });
2684 }5762 }
2685 try writer.writeByte('\n');5763 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);
2687 if (function.global.getReplacement(self) != .none) continue;5766 if (function.global.getReplacement(self) != .none) continue;
2688 const global = function.global.ptrConst(self);5767 const global = function.global.ptrConst(self);
2689 const item = self.type_items.items[@intFromEnum(global.type)];5768 const params_len = global.type.functionParameters(self).len;
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]);
2693 try writer.print(5769 try writer.print(
2694 \\{s}{}{}{}{} {} {}(5770 \\{s}{}{}{}{} {} {}(
2695 , .{5771 , .{
...@@ -2698,31 +5774,398 @@ pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator...@@ -2698,31 +5774,398 @@ pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator
2698 global.preemption,5774 global.preemption,
2699 global.visibility,5775 global.visibility,
2700 global.dll_storage_class,5776 global.dll_storage_class,
2701 extra.data.ret.fmt(self),5777 global.type.functionReturn(self).fmt(self),
2702 function.global.fmt(self),5778 function.global.fmt(self),
2703 });5779 });
2704 for (params, 0..) |param, index| {5780 for (0..params_len) |arg| {
2705 if (index > 0) try writer.writeAll(", ");5781 if (arg > 0) try writer.writeAll(", ");
2706 try writer.print("{%} %{d}", .{ param.fmt(self), index });5782 try writer.print("{%}", .{function.arg(@intCast(arg)).fmt(function_index, self)});
2707 }5783 }
2708 switch (item.tag) {5784 switch (global.type.functionKind(self)) {
2709 .function => {},5785 .normal => {},
2710 .vararg_function => {5786 .vararg => {
2711 if (params.len > 0) try writer.writeAll(", ");5787 if (params_len > 0) try writer.writeAll(", ");
2712 try writer.writeAll("...");5788 try writer.writeAll("...");
2713 },5789 },
2714 else => unreachable,
2715 }5790 }
2716 try writer.print("){}{}", .{ global.unnamed_addr, global.alignment });5791 try writer.print("){}{}", .{ global.unnamed_addr, function.alignment });
2717 if (function.instructions.len > 0) {5792 if (function.instructions.len > 0) {
2718 try writer.writeAll(" {\n");5793 try writer.writeAll(" {\n");
2719 for (0..function.instructions.len) |index| {5794 for (params_len..function.instructions.len) |instruction_i| {
2720 const instruction_index: Function.Instruction.Index = @enumFromInt(index);5795 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
2721 const instruction = function.instructions.get(index);5796 const instruction = function.instructions.get(@intFromEnum(instruction_index));
2722 switch (instruction.tag) {5797 switch (instruction.tag) {
2723 .block => try writer.print("{}:\n", .{instruction_index.name(&function).fmt(self)}),5798 .add,
2724 .@"ret void" => |tag| try writer.print(" {s}\n", .{@tagName(tag)}),5799 .@"add nsw",
2725 else => unreachable,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 },
2726 }6169 }
2727 }6170 }
2728 try writer.writeByte('}');6171 try writer.writeByte('}');
...@@ -2731,6 +6174,12 @@ pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator...@@ -2731,6 +6174,12 @@ pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator
2731 }6174 }
2732}6175}
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
2734fn isValidIdentifier(id: []const u8) bool {6183fn isValidIdentifier(id: []const u8) bool {
2735 for (id, 0..) |character, index| switch (character) {6184 for (id, 0..) |character, index| switch (character) {
2736 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},6185 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
...@@ -3048,15 +6497,15 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {...@@ -3048,15 +6497,15 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
3048fn ensureUnusedTypeCapacity(6497fn ensureUnusedTypeCapacity(
3049 self: *Builder,6498 self: *Builder,
3050 count: usize,6499 count: usize,
3051 comptime Extra: ?type,6500 comptime Extra: type,
3052 trail_len: usize,6501 trail_len: usize,
3053) Allocator.Error!void {6502) Allocator.Error!void {
3054 try self.type_map.ensureUnusedCapacity(self.gpa, count);6503 try self.type_map.ensureUnusedCapacity(self.gpa, count);
3055 try self.type_items.ensureUnusedCapacity(self.gpa, count);6504 try self.type_items.ensureUnusedCapacity(self.gpa, count);
3056 if (Extra) |E| try self.type_extra.ensureUnusedCapacity(6505 try self.type_extra.ensureUnusedCapacity(
3057 self.gpa,6506 self.gpa,
3058 count * (@typeInfo(E).Struct.fields.len + trail_len),6507 count * (@typeInfo(Extra).Struct.fields.len + trail_len),
3059 ) else assert(trail_len == 0);6508 );
3060 if (self.useLibLlvm()) try self.llvm.types.ensureUnusedCapacity(self.gpa, count);6509 if (self.useLibLlvm()) try self.llvm.types.ensureUnusedCapacity(self.gpa, count);
3061}6510}
30626511
...@@ -3104,10 +6553,10 @@ fn typeExtraDataTrail(...@@ -3104,10 +6553,10 @@ fn typeExtraDataTrail(
3104) struct { data: T, end: Type.Item.ExtraIndex } {6553) struct { data: T, end: Type.Item.ExtraIndex } {
3105 var result: T = undefined;6554 var result: T = undefined;
3106 const fields = @typeInfo(T).Struct.fields;6555 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|
3108 @field(result, field.name) = switch (field.type) {6557 @field(result, field.name) = switch (field.type) {
3109 u32 => data,6558 u32 => value,
3110 String, Type => @enumFromInt(data),6559 String, Type => @enumFromInt(value),
3111 else => @compileError("bad field type: " ++ @typeName(field.type)),6560 else => @compileError("bad field type: " ++ @typeName(field.type)),
3112 };6561 };
3113 return .{ .data = result, .end = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) };6562 return .{ .data = result, .end = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) };
...@@ -3519,13 +6968,13 @@ fn arrayConstAssumeCapacity(...@@ -3519,13 +6968,13 @@ fn arrayConstAssumeCapacity(
3519) if (build_options.have_llvm) Allocator.Error!Constant else Constant {6968) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
3520 const type_item = self.type_items.items[@intFromEnum(ty)];6969 const type_item = self.type_items.items[@intFromEnum(ty)];
3521 const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) {6970 const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) {
3522 .small_array => extra: {6971 inline .small_array, .array => |kind| extra: {
3523 const extra = self.typeExtraData(Type.Vector, type_item.data);6972 const extra = self.typeExtraData(switch (kind) {
3524 break :extra .{ .len = extra.len, .child = extra.child };6973 .small_array => Type.Vector,
3525 },6974 .array => Type.Array,
3526 .array => extra: {6975 else => unreachable,
3527 const extra = self.typeExtraData(Type.Array, type_item.data);6976 }, type_item.data);
3528 break :extra .{ .len = extra.len(), .child = extra.child };6977 break :extra .{ .len = extra.length(), .child = extra.child };
3529 },6978 },
3530 else => unreachable,6979 else => unreachable,
3531 };6980 };
...@@ -3738,7 +7187,7 @@ fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant {...@@ -3738,7 +7187,7 @@ fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant {
3738 .{ .tag = .poison, .data = @intFromEnum(ty) },7187 .{ .tag = .poison, .data = @intFromEnum(ty) },
3739 );7188 );
3740 if (self.useLibLlvm() and result.new)7189 if (self.useLibLlvm() and result.new)
3741 self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).getUndef());7190 self.llvm.constants.appendAssumeCapacity(ty.toLlvm(self).getPoison());
3742 return result.constant;7191 return result.constant;
3743}7192}
37447193
...@@ -3794,17 +7243,17 @@ fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {...@@ -3794,17 +7243,17 @@ fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
3794 return result.constant;7243 return result.constant;
3795}7244}
37967245
3797fn convConstAssumeCapacity(7246fn convTag(
3798 self: *Builder,7247 self: *Builder,
7248 comptime Tag: type,
3799 signedness: Constant.Cast.Signedness,7249 signedness: Constant.Cast.Signedness,
3800 arg: Constant,7250 val_ty: Type,
3801 ty: Type,7251 ty: Type,
3802) Constant {7252) Tag {
3803 const arg_ty = arg.typeOf(self);7253 assert(val_ty != ty);
3804 if (arg_ty == ty) return arg;7254 return switch (val_ty.scalarTag(self)) {
3805 return self.castConstAssumeCapacity(switch (arg_ty.scalarTag(self)) {
3806 .simple => switch (ty.scalarTag(self)) {7255 .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))) {
3808 .lt => .fpext,7257 .lt => .fpext,
3809 .eq => unreachable,7258 .eq => unreachable,
3810 .gt => .fptrunc,7259 .gt => .fptrunc,
...@@ -3816,13 +7265,13 @@ fn convConstAssumeCapacity(...@@ -3816,13 +7265,13 @@ fn convConstAssumeCapacity(
3816 },7265 },
3817 else => unreachable,7266 else => unreachable,
3818 },7267 },
3819 .integer => switch (ty.tag(self)) {7268 .integer => switch (ty.scalarTag(self)) {
3820 .simple => switch (signedness) {7269 .simple => switch (signedness) {
3821 .unsigned => .uitofp,7270 .unsigned => .uitofp,
3822 .signed => .sitofp,7271 .signed => .sitofp,
3823 .unneeded => unreachable,7272 .unneeded => unreachable,
3824 },7273 },
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))) {
3826 .lt => switch (signedness) {7275 .lt => switch (signedness) {
3827 .unsigned => .zext,7276 .unsigned => .zext,
3828 .signed => .sext,7277 .signed => .sext,
...@@ -3834,16 +7283,27 @@ fn convConstAssumeCapacity(...@@ -3834,16 +7283,27 @@ fn convConstAssumeCapacity(
3834 .pointer => .inttoptr,7283 .pointer => .inttoptr,
3835 else => unreachable,7284 else => unreachable,
3836 },7285 },
3837 .pointer => switch (ty.tag(self)) {7286 .pointer => switch (ty.scalarTag(self)) {
3838 .integer => .ptrtoint,7287 .integer => .ptrtoint,
3839 .pointer => .addrspacecast,7288 .pointer => .addrspacecast,
3840 else => unreachable,7289 else => unreachable,
3841 },7290 },
3842 else => unreachable,7291 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);
3844}7304}
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 {
3847 const Key = struct { tag: Constant.Tag, cast: Constant.Cast };7307 const Key = struct { tag: Constant.Tag, cast: Constant.Cast };
3848 const Adapter = struct {7308 const Adapter = struct {
3849 builder: *const Builder,7309 builder: *const Builder,
...@@ -3860,7 +7320,7 @@ fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty:...@@ -3860,7 +7320,7 @@ fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty:
3860 return std.meta.eql(lhs_key.cast, rhs_extra);7320 return std.meta.eql(lhs_key.cast, rhs_extra);
3861 }7321 }
3862 };7322 };
3863 const data = Key{ .tag = tag, .cast = .{ .arg = arg, .type = ty } };7323 const data = Key{ .tag = tag, .cast = .{ .val = val, .type = ty } };
3864 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });7324 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3865 if (!gop.found_existing) {7325 if (!gop.found_existing) {
3866 gop.key_ptr.* = {};7326 gop.key_ptr.* = {};
...@@ -3883,7 +7343,7 @@ fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty:...@@ -3883,7 +7343,7 @@ fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty:
3883 .inttoptr => &llvm.Value.constIntToPtr,7343 .inttoptr => &llvm.Value.constIntToPtr,
3884 .bitcast => &llvm.Value.constBitCast,7344 .bitcast => &llvm.Value.constBitCast,
3885 else => unreachable,7345 else => unreachable,
3886 }(arg.toLlvm(self), ty.toLlvm(self)));7346 }(val.toLlvm(self), ty.toLlvm(self)));
3887 }7347 }
3888 return @enumFromInt(gop.index);7348 return @enumFromInt(gop.index);
3889}7349}
...@@ -3893,6 +7353,7 @@ fn gepConstAssumeCapacity(...@@ -3893,6 +7353,7 @@ fn gepConstAssumeCapacity(
3893 comptime kind: Constant.GetElementPtr.Kind,7353 comptime kind: Constant.GetElementPtr.Kind,
3894 ty: Type,7354 ty: Type,
3895 base: Constant,7355 base: Constant,
7356 inrange: ?u16,
3896 indices: []const Constant,7357 indices: []const Constant,
3897) if (build_options.have_llvm) Allocator.Error!Constant else Constant {7358) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
3898 const tag: Constant.Tag = switch (kind) {7359 const tag: Constant.Tag = switch (kind) {
...@@ -3929,13 +7390,19 @@ fn gepConstAssumeCapacity(...@@ -3929,13 +7390,19 @@ fn gepConstAssumeCapacity(
3929 inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty),7390 inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty),
3930 };7391 };
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 };
3933 const Adapter = struct {7399 const Adapter = struct {
3934 builder: *const Builder,7400 builder: *const Builder,
3935 pub fn hash(_: @This(), key: Key) u32 {7401 pub fn hash(_: @This(), key: Key) u32 {
3936 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));7402 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
3937 hasher.update(std.mem.asBytes(&key.type));7403 hasher.update(std.mem.asBytes(&key.type));
3938 hasher.update(std.mem.asBytes(&key.base));7404 hasher.update(std.mem.asBytes(&key.base));
7405 hasher.update(std.mem.asBytes(&key.inrange));
3939 hasher.update(std.mem.sliceAsBytes(key.indices));7406 hasher.update(std.mem.sliceAsBytes(key.indices));
3940 return @truncate(hasher.final());7407 return @truncate(hasher.final());
3941 }7408 }
...@@ -3944,12 +7411,18 @@ fn gepConstAssumeCapacity(...@@ -3944,12 +7411,18 @@ fn gepConstAssumeCapacity(
3944 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];7411 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3945 const rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data);7412 const rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data);
3946 const rhs_indices: []const Constant = @ptrCast(ctx.builder.constant_extra7413 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]);
3948 return lhs_key.type == rhs_extra.data.type and lhs_key.base == rhs_extra.data.base and7415 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
3949 std.mem.eql(Constant, lhs_key.indices, rhs_indices);7417 std.mem.eql(Constant, lhs_key.indices, rhs_indices);
3950 }7418 }
3951 };7419 };
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 };
3953 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });7426 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3954 if (!gop.found_existing) {7427 if (!gop.found_existing) {
3955 gop.key_ptr.* = {};7428 gop.key_ptr.* = {};
...@@ -3959,7 +7432,7 @@ fn gepConstAssumeCapacity(...@@ -3959,7 +7432,7 @@ fn gepConstAssumeCapacity(
3959 .data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{7432 .data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{
3960 .type = ty,7433 .type = ty,
3961 .base = base,7434 .base = base,
3962 .indices_len = @intCast(indices.len),7435 .info = .{ .indices_len = @intCast(indices.len), .inrange = data.inrange },
3963 }),7436 }),
3964 });7437 });
3965 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices));7438 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices));
...@@ -3976,7 +7449,7 @@ fn gepConstAssumeCapacity(...@@ -3976,7 +7449,7 @@ fn gepConstAssumeCapacity(
3976 self.llvm.constants.appendAssumeCapacity(switch (kind) {7449 self.llvm.constants.appendAssumeCapacity(switch (kind) {
3977 .normal => &llvm.Type.constGEP,7450 .normal => &llvm.Type.constGEP,
3978 .inbounds => &llvm.Type.constInBoundsGEP,7451 .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)));
3980 }7453 }
3981 }7454 }
3982 return @enumFromInt(gop.index);7455 return @enumFromInt(gop.index);
...@@ -4058,7 +7531,7 @@ fn fcmpConstAssumeCapacity(...@@ -4058,7 +7531,7 @@ fn fcmpConstAssumeCapacity(
40587531
4059fn extractElementConstAssumeCapacity(7532fn extractElementConstAssumeCapacity(
4060 self: *Builder,7533 self: *Builder,
4061 arg: Constant,7534 val: Constant,
4062 index: Constant,7535 index: Constant,
4063) Constant {7536) Constant {
4064 const Adapter = struct {7537 const Adapter = struct {
...@@ -4076,7 +7549,7 @@ fn extractElementConstAssumeCapacity(...@@ -4076,7 +7549,7 @@ fn extractElementConstAssumeCapacity(
4076 return std.meta.eql(lhs_key, rhs_extra);7549 return std.meta.eql(lhs_key, rhs_extra);
4077 }7550 }
4078 };7551 };
4079 const data = Constant.ExtractElement{ .arg = arg, .index = index };7552 const data = Constant.ExtractElement{ .val = val, .index = index };
4080 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });7553 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
4081 if (!gop.found_existing) {7554 if (!gop.found_existing) {
4082 gop.key_ptr.* = {};7555 gop.key_ptr.* = {};
...@@ -4086,7 +7559,7 @@ fn extractElementConstAssumeCapacity(...@@ -4086,7 +7559,7 @@ fn extractElementConstAssumeCapacity(
4086 .data = self.addConstantExtraAssumeCapacity(data),7559 .data = self.addConstantExtraAssumeCapacity(data),
4087 });7560 });
4088 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(7561 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
4089 arg.toLlvm(self).constExtractElement(index.toLlvm(self)),7562 val.toLlvm(self).constExtractElement(index.toLlvm(self)),
4090 );7563 );
4091 }7564 }
4092 return @enumFromInt(gop.index);7565 return @enumFromInt(gop.index);
...@@ -4094,7 +7567,7 @@ fn extractElementConstAssumeCapacity(...@@ -4094,7 +7567,7 @@ fn extractElementConstAssumeCapacity(
40947567
4095fn insertElementConstAssumeCapacity(7568fn insertElementConstAssumeCapacity(
4096 self: *Builder,7569 self: *Builder,
4097 arg: Constant,7570 val: Constant,
4098 elem: Constant,7571 elem: Constant,
4099 index: Constant,7572 index: Constant,
4100) Constant {7573) Constant {
...@@ -4113,7 +7586,7 @@ fn insertElementConstAssumeCapacity(...@@ -4113,7 +7586,7 @@ fn insertElementConstAssumeCapacity(
4113 return std.meta.eql(lhs_key, rhs_extra);7586 return std.meta.eql(lhs_key, rhs_extra);
4114 }7587 }
4115 };7588 };
4116 const data = Constant.InsertElement{ .arg = arg, .elem = elem, .index = index };7589 const data = Constant.InsertElement{ .val = val, .elem = elem, .index = index };
4117 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });7590 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
4118 if (!gop.found_existing) {7591 if (!gop.found_existing) {
4119 gop.key_ptr.* = {};7592 gop.key_ptr.* = {};
...@@ -4123,7 +7596,7 @@ fn insertElementConstAssumeCapacity(...@@ -4123,7 +7596,7 @@ fn insertElementConstAssumeCapacity(
4123 .data = self.addConstantExtraAssumeCapacity(data),7596 .data = self.addConstantExtraAssumeCapacity(data),
4124 });7597 });
4125 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(7598 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)),
4127 );7600 );
4128 }7601 }
4129 return @enumFromInt(gop.index);7602 return @enumFromInt(gop.index);
...@@ -4135,6 +7608,10 @@ fn shuffleVectorConstAssumeCapacity(...@@ -4135,6 +7608,10 @@ fn shuffleVectorConstAssumeCapacity(
4135 rhs: Constant,7608 rhs: Constant,
4136 mask: Constant,7609 mask: Constant,
4137) Constant {7610) 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);
4138 const Adapter = struct {7615 const Adapter = struct {
4139 builder: *const Builder,7616 builder: *const Builder,
4140 pub fn hash(_: @This(), key: Constant.ShuffleVector) u32 {7617 pub fn hash(_: @This(), key: Constant.ShuffleVector) u32 {
...@@ -4235,15 +7712,15 @@ fn binConstAssumeCapacity(...@@ -4235,15 +7712,15 @@ fn binConstAssumeCapacity(
4235fn ensureUnusedConstantCapacity(7712fn ensureUnusedConstantCapacity(
4236 self: *Builder,7713 self: *Builder,
4237 count: usize,7714 count: usize,
4238 comptime Extra: ?type,7715 comptime Extra: type,
4239 trail_len: usize,7716 trail_len: usize,
4240) Allocator.Error!void {7717) Allocator.Error!void {
4241 try self.constant_map.ensureUnusedCapacity(self.gpa, count);7718 try self.constant_map.ensureUnusedCapacity(self.gpa, count);
4242 try self.constant_items.ensureUnusedCapacity(self.gpa, count);7719 try self.constant_items.ensureUnusedCapacity(self.gpa, count);
4243 if (Extra) |E| try self.constant_extra.ensureUnusedCapacity(7720 try self.constant_extra.ensureUnusedCapacity(
4244 self.gpa,7721 self.gpa,
4245 count * (@typeInfo(E).Struct.fields.len + trail_len),7722 count * (@typeInfo(Extra).Struct.fields.len + trail_len),
4246 ) else assert(trail_len == 0);7723 );
4247 if (self.useLibLlvm()) try self.llvm.constants.ensureUnusedCapacity(self.gpa, count);7724 if (self.useLibLlvm()) try self.llvm.constants.ensureUnusedCapacity(self.gpa, count);
4248}7725}
42497726
...@@ -4323,11 +7800,8 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item....@@ -4323,11 +7800,8 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.
4323 const value = @field(extra, field.name);7800 const value = @field(extra, field.name);
4324 self.constant_extra.appendAssumeCapacity(switch (field.type) {7801 self.constant_extra.appendAssumeCapacity(switch (field.type) {
4325 u32 => value,7802 u32 => value,
4326 Type,7803 Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
4327 Constant,7804 Constant.GetElementPtr.Info => @bitCast(value),
4328 Function.Index,
4329 Function.Block.Index,
4330 => @intFromEnum(value),
4331 else => @compileError("bad field type: " ++ @typeName(field.type)),7805 else => @compileError("bad field type: " ++ @typeName(field.type)),
4332 });7806 });
4333 }7807 }
...@@ -4341,14 +7815,11 @@ fn constantExtraDataTrail(...@@ -4341,14 +7815,11 @@ fn constantExtraDataTrail(
4341) struct { data: T, end: Constant.Item.ExtraIndex } {7815) struct { data: T, end: Constant.Item.ExtraIndex } {
4342 var result: T = undefined;7816 var result: T = undefined;
4343 const fields = @typeInfo(T).Struct.fields;7817 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|
4345 @field(result, field.name) = switch (field.type) {7819 @field(result, field.name) = switch (field.type) {
4346 u32 => data,7820 u32 => value,
4347 Type,7821 Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
4348 Constant,7822 Constant.GetElementPtr.Info => @bitCast(value),
4349 Function.Index,
4350 Function.Block.Index,
4351 => @enumFromInt(data),
4352 else => @compileError("bad field type: " ++ @typeName(field.type)),7823 else => @compileError("bad field type: " ++ @typeName(field.type)),
4353 };7824 };
4354 return .{ .data = result, .end = index + @as(Constant.Item.ExtraIndex, @intCast(fields.len)) };7825 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...@@ -4358,10 +7829,6 @@ fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Ite
4358 return self.constantExtraDataTrail(T, index).data;7829 return self.constantExtraDataTrail(T, index).data;
4359}7830}
43607831
4361pub inline fn useLibLlvm(self: *const Builder) bool {
4362 return build_options.have_llvm and self.use_lib_llvm;
4363}
4364
4365const assert = std.debug.assert;7832const assert = std.debug.assert;
4366const build_options = @import("build_options");7833const build_options = @import("build_options");
4367const builtin = @import("builtin");7834const builtin = @import("builtin");
src/codegen/llvm/bindings.zig+20-73
...@@ -135,9 +135,6 @@ pub const Value = opaque {...@@ -135,9 +135,6 @@ pub const Value = opaque {
135 pub const getNextInstruction = LLVMGetNextInstruction;135 pub const getNextInstruction = LLVMGetNextInstruction;
136 extern fn LLVMGetNextInstruction(Inst: *Value) ?*Value;136 extern fn LLVMGetNextInstruction(Inst: *Value) ?*Value;
137137
138 pub const typeOf = LLVMTypeOf;
139 extern fn LLVMTypeOf(Val: *Value) *Type;
140
141 pub const setGlobalConstant = LLVMSetGlobalConstant;138 pub const setGlobalConstant = LLVMSetGlobalConstant;
142 extern fn LLVMSetGlobalConstant(GlobalVar: *Value, IsConstant: Bool) void;139 extern fn LLVMSetGlobalConstant(GlobalVar: *Value, IsConstant: Bool) void;
143140
...@@ -291,6 +288,9 @@ pub const Value = opaque {...@@ -291,6 +288,9 @@ pub const Value = opaque {
291 MaskConstant: *Value,288 MaskConstant: *Value,
292 ) *Value;289 ) *Value;
293290
291 pub const isConstant = LLVMIsConstant;
292 extern fn LLVMIsConstant(Val: *Value) Bool;
293
294 pub const blockAddress = LLVMBlockAddress;294 pub const blockAddress = LLVMBlockAddress;
295 extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;295 extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;
296296
...@@ -303,6 +303,9 @@ pub const Value = opaque {...@@ -303,6 +303,9 @@ pub const Value = opaque {
303 pub const setVolatile = LLVMSetVolatile;303 pub const setVolatile = LLVMSetVolatile;
304 extern fn LLVMSetVolatile(MemoryAccessInst: *Value, IsVolatile: Bool) void;304 extern fn LLVMSetVolatile(MemoryAccessInst: *Value, IsVolatile: Bool) void;
305305
306 pub const setAtomicSingleThread = LLVMSetAtomicSingleThread;
307 extern fn LLVMSetAtomicSingleThread(AtomicInst: *Value, SingleThread: Bool) void;
308
306 pub const setAlignment = LLVMSetAlignment;309 pub const setAlignment = LLVMSetAlignment;
307 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;310 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;
308311
...@@ -348,17 +351,9 @@ pub const Value = opaque {...@@ -348,17 +351,9 @@ pub const Value = opaque {
348 pub const addCase = LLVMAddCase;351 pub const addCase = LLVMAddCase;
349 extern fn LLVMAddCase(Switch: *Value, OnVal: *Value, Dest: *BasicBlock) void;352 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
356 pub const replaceAllUsesWith = LLVMReplaceAllUsesWith;354 pub const replaceAllUsesWith = LLVMReplaceAllUsesWith;
357 extern fn LLVMReplaceAllUsesWith(OldVal: *Value, NewVal: *Value) void;355 extern fn LLVMReplaceAllUsesWith(OldVal: *Value, NewVal: *Value) void;
358356
359 pub const globalGetValueType = LLVMGlobalGetValueType;
360 extern fn LLVMGlobalGetValueType(Global: *Value) *Type;
361
362 pub const getLinkage = LLVMGetLinkage;357 pub const getLinkage = LLVMGetLinkage;
363 extern fn LLVMGetLinkage(Global: *Value) Linkage;358 extern fn LLVMGetLinkage(Global: *Value) Linkage;
364359
...@@ -410,6 +405,9 @@ pub const Type = opaque {...@@ -410,6 +405,9 @@ pub const Type = opaque {
410 pub const getUndef = LLVMGetUndef;405 pub const getUndef = LLVMGetUndef;
411 extern fn LLVMGetUndef(Ty: *Type) *Value;406 extern fn LLVMGetUndef(Ty: *Type) *Value;
412407
408 pub const getPoison = LLVMGetPoison;
409 extern fn LLVMGetPoison(Ty: *Type) *Value;
410
413 pub const arrayType = LLVMArrayType;411 pub const arrayType = LLVMArrayType;
414 extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) *Type;412 extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) *Type;
415413
...@@ -427,24 +425,6 @@ pub const Type = opaque {...@@ -427,24 +425,6 @@ pub const Type = opaque {
427 Packed: Bool,425 Packed: Bool,
428 ) void;426 ) 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
448 pub const constGEP = LLVMConstGEP2;428 pub const constGEP = LLVMConstGEP2;
449 extern fn LLVMConstGEP2(429 extern fn LLVMConstGEP2(
450 Ty: *Type,430 Ty: *Type,
...@@ -815,6 +795,16 @@ pub const Builder = opaque {...@@ -815,6 +795,16 @@ pub const Builder = opaque {
815 pub const buildBitCast = LLVMBuildBitCast;795 pub const buildBitCast = LLVMBuildBitCast;
816 extern fn LLVMBuildBitCast(*Builder, Val: *Value, DestTy: *Type, Name: [*:0]const u8) *Value;796 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
818 pub const buildInBoundsGEP = LLVMBuildInBoundsGEP2;808 pub const buildInBoundsGEP = LLVMBuildInBoundsGEP2;
819 extern fn LLVMBuildInBoundsGEP2(809 extern fn LLVMBuildInBoundsGEP2(
820 B: *Builder,810 B: *Builder,
...@@ -868,14 +858,6 @@ pub const Builder = opaque {...@@ -868,14 +858,6 @@ pub const Builder = opaque {
868 Name: [*:0]const u8,858 Name: [*:0]const u8,
869 ) *Value;859 ) *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
879 pub const buildPtrToInt = LLVMBuildPtrToInt;861 pub const buildPtrToInt = LLVMBuildPtrToInt;
880 extern fn LLVMBuildPtrToInt(862 extern fn LLVMBuildPtrToInt(
881 *Builder,863 *Builder,
...@@ -892,15 +874,6 @@ pub const Builder = opaque {...@@ -892,15 +874,6 @@ pub const Builder = opaque {
892 Name: [*:0]const u8,874 Name: [*:0]const u8,
893 ) *Value;875 ) *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
904 pub const buildTrunc = LLVMBuildTrunc;877 pub const buildTrunc = LLVMBuildTrunc;
905 extern fn LLVMBuildTrunc(878 extern fn LLVMBuildTrunc(
906 *Builder,879 *Builder,
...@@ -1156,9 +1129,6 @@ pub const RealPredicate = enum(c_uint) {...@@ -1156,9 +1129,6 @@ pub const RealPredicate = enum(c_uint) {
1156pub const BasicBlock = opaque {1129pub const BasicBlock = opaque {
1157 pub const deleteBasicBlock = LLVMDeleteBasicBlock;1130 pub const deleteBasicBlock = LLVMDeleteBasicBlock;
1158 extern fn LLVMDeleteBasicBlock(BB: *BasicBlock) void;1131 extern fn LLVMDeleteBasicBlock(BB: *BasicBlock) void;
1159
1160 pub const getFirstInstruction = LLVMGetFirstInstruction;
1161 extern fn LLVMGetFirstInstruction(BB: *BasicBlock) ?*Value;
1162};1132};
11631133
1164pub const TargetMachine = opaque {1134pub const TargetMachine = opaque {
...@@ -1580,29 +1550,6 @@ pub const AtomicRMWBinOp = enum(c_int) {...@@ -1580,29 +1550,6 @@ pub const AtomicRMWBinOp = enum(c_int) {
1580 FMin,1550 FMin,
1581};1551};
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
1606pub const CallConv = enum(c_uint) {1553pub const CallConv = enum(c_uint) {
1607 C = 0,1554 C = 0,
1608 Fast = 8,1555 Fast = 8,
...@@ -1729,7 +1676,7 @@ pub const address_space = struct {...@@ -1729,7 +1676,7 @@ pub const address_space = struct {
1729 pub const constant_buffer_15: c_uint = 23;1676 pub const constant_buffer_15: c_uint = 23;
1730 };1677 };
17311678
1732 // See llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h1679 // See llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypetilities.h
1733 pub const wasm = struct {1680 pub const wasm = struct {
1734 pub const variable: c_uint = 1;1681 pub const variable: c_uint = 1;
1735 pub const externref: c_uint = 10;1682 pub const externref: c_uint = 10;
src/zig_llvm.cpp-4
...@@ -560,10 +560,6 @@ LLVMValueRef ZigLLVMBuildUShlSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRe...@@ -560,10 +560,6 @@ LLVMValueRef ZigLLVMBuildUShlSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRe
560 return wrap(call_inst);560 return wrap(call_inst);
561}561}
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
567void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) {563void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) {
568 assert( isa<Function>(unwrap(fn)) );564 assert( isa<Function>(unwrap(fn)) );
569 Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn));565 Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn));