authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-23 05:01:12-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-23 23:48:19-04:00
log533111e849c5f8010f4e9b97c09c433058c5a3e0
treedbb7dfde4863bf6e5e7c30872970cf09723b0214
parentc610cde1eb460ddf80910f34e19c8a68d1bc86a9

llvm: convert inline assembly

Also, implement TODOs from a previous commit.

2 files changed, 297 insertions(+), 68 deletions(-)

src/codegen/llvm.zig+16-32
...@@ -6780,7 +6780,7 @@ pub const FuncGen = struct {...@@ -6780,7 +6780,7 @@ pub const FuncGen = struct {
67806780
6781 const max_param_count = inputs.len + outputs.len;6781 const max_param_count = inputs.len + outputs.len;
6782 const llvm_param_types = try arena.alloc(Builder.Type, max_param_count);6782 const llvm_param_types = try arena.alloc(Builder.Type, max_param_count);
6783 const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);6783 const llvm_param_values = try arena.alloc(Builder.Value, max_param_count);
6784 // This stores whether we need to add an elementtype attribute and6784 // This stores whether we need to add an elementtype attribute and
6785 // if so, the element type itself.6785 // if so, the element type itself.
6786 const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);6786 const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);
...@@ -6820,7 +6820,7 @@ pub const FuncGen = struct {...@@ -6820,7 +6820,7 @@ pub const FuncGen = struct {
6820 // Pass the result by reference as an indirect output (e.g. "=*m")6820 // Pass the result by reference as an indirect output (e.g. "=*m")
6821 llvm_constraints.appendAssumeCapacity('*');6821 llvm_constraints.appendAssumeCapacity('*');
68226822
6823 llvm_param_values[llvm_param_i] = output_inst.toLlvm(&self.wip);6823 llvm_param_values[llvm_param_i] = output_inst;
6824 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);6824 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
6825 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;6825 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
6826 llvm_param_i += 1;6826 llvm_param_i += 1;
...@@ -6870,25 +6870,25 @@ pub const FuncGen = struct {...@@ -6870,25 +6870,25 @@ pub const FuncGen = struct {
6870 if (isByRef(arg_ty, mod)) {6870 if (isByRef(arg_ty, mod)) {
6871 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);6871 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
6872 if (constraintAllowsMemory(constraint)) {6872 if (constraintAllowsMemory(constraint)) {
6873 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);6873 llvm_param_values[llvm_param_i] = arg_llvm_value;
6874 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);6874 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6875 } else {6875 } else {
6876 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));6876 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6877 const arg_llvm_ty = try o.lowerType(arg_ty);6877 const arg_llvm_ty = try o.lowerType(arg_ty);
6878 const load_inst =6878 const load_inst =
6879 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");6879 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
6880 llvm_param_values[llvm_param_i] = load_inst.toLlvm(&self.wip);6880 llvm_param_values[llvm_param_i] = load_inst;
6881 llvm_param_types[llvm_param_i] = arg_llvm_ty;6881 llvm_param_types[llvm_param_i] = arg_llvm_ty;
6882 }6882 }
6883 } else {6883 } else {
6884 if (constraintAllowsRegister(constraint)) {6884 if (constraintAllowsRegister(constraint)) {
6885 llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);6885 llvm_param_values[llvm_param_i] = arg_llvm_value;
6886 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);6886 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6887 } else {6887 } else {
6888 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));6888 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6889 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);6889 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
6890 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);6890 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
6891 llvm_param_values[llvm_param_i] = arg_ptr.toLlvm(&self.wip);6891 llvm_param_values[llvm_param_i] = arg_ptr;
6892 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);6892 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
6893 }6893 }
6894 }6894 }
...@@ -7037,40 +7037,24 @@ pub const FuncGen = struct {...@@ -7037,40 +7037,24 @@ pub const FuncGen = struct {
70377037
7038 var attributes: Builder.FunctionAttributes.Wip = .{};7038 var attributes: Builder.FunctionAttributes.Wip = .{};
7039 defer attributes.deinit(&o.builder);7039 defer attributes.deinit(&o.builder);
7040 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| if (llvm_elem_ty != .none)
7041 try attributes.addParamAttr(i, .{ .elementtype = llvm_elem_ty }, &o.builder);
70407042
7041 const ret_llvm_ty = switch (return_count) {7043 const ret_llvm_ty = switch (return_count) {
7042 0 => .void,7044 0 => .void,
7043 1 => llvm_ret_types[0],7045 1 => llvm_ret_types[0],
7044 else => try o.builder.structType(.normal, llvm_ret_types),7046 else => try o.builder.structType(.normal, llvm_ret_types),
7045 };7047 };
7046
7047 const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);7048 const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);
7048 const asm_fn = llvm.getInlineAsm(7049 const call = try self.wip.callAsm(
7049 llvm_fn_ty.toLlvm(&o.builder),7050 try attributes.finish(&o.builder),
7050 rendered_template.items.ptr,7051 llvm_fn_ty,
7051 rendered_template.items.len,7052 .{ .sideeffect = is_volatile },
7052 llvm_constraints.items.ptr,7053 try o.builder.string(rendered_template.items),
7053 llvm_constraints.items.len,7054 try o.builder.string(llvm_constraints.items),
7054 llvm.Bool.fromBool(is_volatile),7055 llvm_param_values[0..param_count],
7055 .False,
7056 .ATT,
7057 .False,
7058 );
7059 const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCallOld(
7060 llvm_fn_ty.toLlvm(&o.builder),
7061 asm_fn,
7062 llvm_param_values.ptr,
7063 @intCast(param_count),
7064 .C,
7065 .Auto,
7066 "",7056 "",
7067 ), &self.wip);7057 );
7068 for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
7069 if (llvm_elem_ty != .none) {
7070 try attributes.addParamAttr(i, .{ .elementtype = llvm_elem_ty }, &o.builder);
7071 llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
7072 }
7073 }
70747058
7075 var ret_val = call;7059 var ret_val = call;
7076 llvm_ret_i = 0;7060 llvm_ret_i = 0;
src/codegen/llvm/Builder.zig+281-36
...@@ -1072,7 +1072,7 @@ pub const Attribute = union(Kind) {...@@ -1072,7 +1072,7 @@ pub const Attribute = union(Kind) {
1072 _: std.fmt.FormatOptions,1072 _: std.fmt.FormatOptions,
1073 writer: anytype,1073 writer: anytype,
1074 ) @TypeOf(writer).Error!void {1074 ) @TypeOf(writer).Error!void {
1075 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"")) |_|1075 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_|
1076 @compileError("invalid format string: '" ++ fmt_str ++ "'");1076 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1077 const attribute = data.attribute_index.toAttribute(data.builder);1077 const attribute = data.attribute_index.toAttribute(data.builder);
1078 switch (attribute) {1078 switch (attribute) {
...@@ -1154,17 +1154,72 @@ pub const Attribute = union(Kind) {...@@ -1154,17 +1154,72 @@ pub const Attribute = union(Kind) {
1154 .sret,1154 .sret,
1155 .elementtype,1155 .elementtype,
1156 => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),1156 => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
1157 .@"align" => @panic("todo"),1157 .@"align" => |alignment| try writer.print("{}", .{alignment}),
1158 .dereferenceable,1158 .dereferenceable,
1159 .dereferenceable_or_null,1159 .dereferenceable_or_null,
1160 => @panic("todo"),1160 => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }),
1161 .nofpclass => @panic("todo"),1161 .nofpclass => |fpclass| {
1162 .alignstack => @panic("todo"),1162 const Int = @typeInfo(FpClass).Struct.backing_integer.?;
1163 .allockind => @panic("todo"),1163 try writer.print("{s}(", .{@tagName(attribute)});
1164 .allocsize => @panic("todo"),1164 var any = false;
1165 .memory => @panic("todo"),1165 var remaining: Int = @bitCast(fpclass);
1166 .uwtable => @panic("todo"),1166 inline for (@typeInfo(FpClass).Struct.decls) |decl| {
1167 .vscale_range => @panic("todo"),1167 if (!decl.is_pub) continue;
1168 const pattern: Int = @bitCast(@field(FpClass, decl.name));
1169 if (remaining & pattern == pattern) {
1170 if (!any) {
1171 try writer.writeByte(' ');
1172 any = true;
1173 }
1174 try writer.writeAll(decl.name);
1175 remaining &= ~pattern;
1176 }
1177 }
1178 try writer.writeByte(')');
1179 },
1180 .alignstack => |alignment| try writer.print(
1181 if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null)
1182 "{s}={d}"
1183 else
1184 "{s}({d})",
1185 .{ @tagName(attribute), alignment.toByteUnits() orelse return },
1186 ),
1187 .allockind => |allockind| {
1188 try writer.print("{s}(\"", .{@tagName(attribute)});
1189 var any = false;
1190 inline for (@typeInfo(AllocKind).Struct.fields) |field| {
1191 if (comptime std.mem.eql(u8, field.name, "_")) continue;
1192 if (@field(allockind, field.name)) {
1193 if (!any) {
1194 try writer.writeByte(',');
1195 any = true;
1196 }
1197 try writer.writeAll(field.name);
1198 }
1199 }
1200 try writer.writeAll("\")");
1201 },
1202 .allocsize => |allocsize| {
1203 try writer.print("{s}({d}", .{ @tagName(attribute), allocsize.elem_size });
1204 if (allocsize.num_elems != AllocSize.none)
1205 try writer.print(",{d}", .{allocsize.num_elems});
1206 try writer.writeByte(')');
1207 },
1208 .memory => |memory| try writer.print("{s}({s}, argmem: {s}, inaccessiblemem: {s})", .{
1209 @tagName(attribute),
1210 @tagName(memory.other),
1211 @tagName(memory.argmem),
1212 @tagName(memory.inaccessiblemem),
1213 }),
1214 .uwtable => |uwtable| if (uwtable != .none) {
1215 try writer.writeAll(@tagName(attribute));
1216 if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)});
1217 },
1218 .vscale_range => |vscale_range| try writer.print("{s}({d},{d})", .{
1219 @tagName(attribute),
1220 vscale_range.min.toByteUnits().?,
1221 vscale_range.max.toByteUnits() orelse 0,
1222 }),
1168 .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {1223 .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {
1169 try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});1224 try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});
1170 if (string_attr.value != .empty)1225 if (string_attr.value != .empty)
...@@ -1314,11 +1369,6 @@ pub const Attribute = union(Kind) {...@@ -1314,11 +1369,6 @@ pub const Attribute = union(Kind) {
1314 positive_infinity: bool = false,1369 positive_infinity: bool = false,
1315 _: u22 = 0,1370 _: u22 = 0,
13161371
1317 pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
1318 pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
1319 pub const norm = FpClass{ .positive_normal = true, .negative_normal = true };
1320 pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true };
1321 pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
1322 pub const all = FpClass{1372 pub const all = FpClass{
1323 .signaling_nan = true,1373 .signaling_nan = true,
1324 .quiet_nan = true,1374 .quiet_nan = true,
...@@ -1331,16 +1381,26 @@ pub const Attribute = union(Kind) {...@@ -1331,16 +1381,26 @@ pub const Attribute = union(Kind) {
1331 .positive_normal = true,1381 .positive_normal = true,
1332 .positive_infinity = true,1382 .positive_infinity = true,
1333 };1383 };
1384
1385 pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
1334 pub const snan = FpClass{ .signaling_nan = true };1386 pub const snan = FpClass{ .signaling_nan = true };
1335 pub const qnan = FpClass{ .quiet_nan = true };1387 pub const qnan = FpClass{ .quiet_nan = true };
1388
1389 pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
1336 pub const ninf = FpClass{ .negative_infinity = true };1390 pub const ninf = FpClass{ .negative_infinity = true };
1337 pub const nnorm = FpClass{ .negative_normal = true };1391 pub const pinf = FpClass{ .positive_infinity = true };
1338 pub const nsub = FpClass{ .negative_subnormal = true };1392
1393 pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
1339 pub const nzero = FpClass{ .negative_zero = true };1394 pub const nzero = FpClass{ .negative_zero = true };
1340 pub const pzero = FpClass{ .positive_zero = true };1395 pub const pzero = FpClass{ .positive_zero = true };
1396
1397 pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true };
1398 pub const nsub = FpClass{ .negative_subnormal = true };
1341 pub const psub = FpClass{ .positive_subnormal = true };1399 pub const psub = FpClass{ .positive_subnormal = true };
1400
1401 pub const norm = FpClass{ .positive_normal = true, .negative_normal = true };
1402 pub const nnorm = FpClass{ .negative_normal = true };
1342 pub const pnorm = FpClass{ .positive_normal = true };1403 pub const pnorm = FpClass{ .positive_normal = true };
1343 pub const pinf = FpClass{ .positive_infinity = true };
1344 };1404 };
13451405
1346 pub const AllocKind = packed struct(u32) {1406 pub const AllocKind = packed struct(u32) {
...@@ -1924,7 +1984,7 @@ pub const CallConv = enum(u10) {...@@ -1924,7 +1984,7 @@ pub const CallConv = enum(u10) {
1924 writer: anytype,1984 writer: anytype,
1925 ) @TypeOf(writer).Error!void {1985 ) @TypeOf(writer).Error!void {
1926 switch (self) {1986 switch (self) {
1927 .ccc => {},1987 default => {},
1928 .fastcc,1988 .fastcc,
1929 .coldcc,1989 .coldcc,
1930 .ghccc,1990 .ghccc,
...@@ -2445,6 +2505,7 @@ pub const Function = struct {...@@ -2445,6 +2505,7 @@ pub const Function = struct {
2445 .br_cond,2505 .br_cond,
2446 .ret,2506 .ret,
2447 .@"ret void",2507 .@"ret void",
2508 .@"switch",
2448 .@"unreachable",2509 .@"unreachable",
2449 => true,2510 => true,
2450 else => false,2511 else => false,
...@@ -2462,6 +2523,7 @@ pub const Function = struct {...@@ -2462,6 +2523,7 @@ pub const Function = struct {
2462 .@"store atomic",2523 .@"store atomic",
2463 .@"store atomic volatile",2524 .@"store atomic volatile",
2464 .@"store volatile",2525 .@"store volatile",
2526 .@"switch",
2465 .@"unreachable",2527 .@"unreachable",
2466 => false,2528 => false,
2467 .call,2529 .call,
...@@ -2472,6 +2534,7 @@ pub const Function = struct {...@@ -2472,6 +2534,7 @@ pub const Function = struct {
2472 .@"notail call fast",2534 .@"notail call fast",
2473 .@"tail call",2535 .@"tail call",
2474 .@"tail call fast",2536 .@"tail call fast",
2537 .unimplemented,
2475 => self.typeOfWip(wip) != .void,2538 => self.typeOfWip(wip) != .void,
2476 else => true,2539 else => true,
2477 };2540 };
...@@ -4165,7 +4228,7 @@ pub const WipFunction = struct {...@@ -4165,7 +4228,7 @@ pub const WipFunction = struct {
4165 callee: Value,4228 callee: Value,
4166 args: []const Value,4229 args: []const Value,
4167 name: []const u8,4230 name: []const u8,
4168 ) if (build_options.have_llvm) Allocator.Error!Value else Value {4231 ) Allocator.Error!Value {
4169 const ret_ty = ty.functionReturn(self.builder);4232 const ret_ty = ty.functionReturn(self.builder);
4170 assert(ty.isFunction(self.builder));4233 assert(ty.isFunction(self.builder));
4171 assert(callee.typeOfWip(self).isPointer(self.builder));4234 assert(callee.typeOfWip(self).isPointer(self.builder));
...@@ -4238,6 +4301,20 @@ pub const WipFunction = struct {...@@ -4238,6 +4301,20 @@ pub const WipFunction = struct {
4238 return instruction.toValue();4301 return instruction.toValue();
4239 }4302 }
42404303
4304 pub fn callAsm(
4305 self: *WipFunction,
4306 function_attributes: FunctionAttributes,
4307 ty: Type,
4308 kind: Constant.Asm.Info,
4309 assembly: String,
4310 constraints: String,
4311 args: []const Value,
4312 name: []const u8,
4313 ) Allocator.Error!Value {
4314 const callee = try self.builder.asmValue(ty, kind, assembly, constraints);
4315 return self.call(.normal, CallConv.default, function_attributes, ty, callee, args, name);
4316 }
4317
4241 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {4318 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
4242 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);4319 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
4243 const instruction = try self.addInst(name, .{4320 const instruction = try self.addInst(name, .{
...@@ -5216,7 +5293,7 @@ pub const Constant = enum(u32) {...@@ -5216,7 +5293,7 @@ pub const Constant = enum(u32) {
52165293
5217 const first_global: Constant = @enumFromInt(1 << 30);5294 const first_global: Constant = @enumFromInt(1 << 30);
52185295
5219 pub const Tag = enum(u6) {5296 pub const Tag = enum(u7) {
5220 positive_integer,5297 positive_integer,
5221 negative_integer,5298 negative_integer,
5222 half,5299 half,
...@@ -5276,6 +5353,22 @@ pub const Constant = enum(u32) {...@@ -5276,6 +5353,22 @@ pub const Constant = enum(u32) {
5276 @"and",5353 @"and",
5277 @"or",5354 @"or",
5278 xor,5355 xor,
5356 @"asm",
5357 @"asm sideeffect",
5358 @"asm alignstack",
5359 @"asm sideeffect alignstack",
5360 @"asm inteldialect",
5361 @"asm sideeffect inteldialect",
5362 @"asm alignstack inteldialect",
5363 @"asm sideeffect alignstack inteldialect",
5364 @"asm unwind",
5365 @"asm sideeffect unwind",
5366 @"asm alignstack unwind",
5367 @"asm sideeffect alignstack unwind",
5368 @"asm inteldialect unwind",
5369 @"asm sideeffect inteldialect unwind",
5370 @"asm alignstack inteldialect unwind",
5371 @"asm sideeffect alignstack inteldialect unwind",
5279 };5372 };
52805373
5281 pub const Item = struct {5374 pub const Item = struct {
...@@ -5371,6 +5464,19 @@ pub const Constant = enum(u32) {...@@ -5371,6 +5464,19 @@ pub const Constant = enum(u32) {
5371 rhs: Constant,5464 rhs: Constant,
5372 };5465 };
53735466
5467 pub const Asm = extern struct {
5468 type: Type,
5469 assembly: String,
5470 constraints: String,
5471
5472 pub const Info = packed struct {
5473 sideeffect: bool = false,
5474 alignstack: bool = false,
5475 inteldialect: bool = false,
5476 unwind: bool = false,
5477 };
5478 };
5479
5374 pub fn unwrap(self: Constant) union(enum) {5480 pub fn unwrap(self: Constant) union(enum) {
5375 constant: u30,5481 constant: u30,
5376 global: Global.Index,5482 global: Global.Index,
...@@ -5489,6 +5595,23 @@ pub const Constant = enum(u32) {...@@ -5489,6 +5595,23 @@ pub const Constant = enum(u32) {
5489 .@"or",5595 .@"or",
5490 .xor,5596 .xor,
5491 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),5597 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
5598 .@"asm",
5599 .@"asm sideeffect",
5600 .@"asm alignstack",
5601 .@"asm sideeffect alignstack",
5602 .@"asm inteldialect",
5603 .@"asm sideeffect inteldialect",
5604 .@"asm alignstack inteldialect",
5605 .@"asm sideeffect alignstack inteldialect",
5606 .@"asm unwind",
5607 .@"asm sideeffect unwind",
5608 .@"asm alignstack unwind",
5609 .@"asm sideeffect alignstack unwind",
5610 .@"asm inteldialect unwind",
5611 .@"asm sideeffect inteldialect unwind",
5612 .@"asm alignstack inteldialect unwind",
5613 .@"asm sideeffect alignstack inteldialect unwind",
5614 => .ptr,
5492 };5615 };
5493 },5616 },
5494 .global => |global| return builder.ptrTypeAssumeCapacity(5617 .global => |global| return builder.ptrTypeAssumeCapacity(
...@@ -5836,6 +5959,30 @@ pub const Constant = enum(u32) {...@@ -5836,6 +5959,30 @@ pub const Constant = enum(u32) {
5836 extra.rhs.fmt(data.builder),5959 extra.rhs.fmt(data.builder),
5837 });5960 });
5838 },5961 },
5962 .@"asm",
5963 .@"asm sideeffect",
5964 .@"asm alignstack",
5965 .@"asm sideeffect alignstack",
5966 .@"asm inteldialect",
5967 .@"asm sideeffect inteldialect",
5968 .@"asm alignstack inteldialect",
5969 .@"asm sideeffect alignstack inteldialect",
5970 .@"asm unwind",
5971 .@"asm sideeffect unwind",
5972 .@"asm alignstack unwind",
5973 .@"asm sideeffect alignstack unwind",
5974 .@"asm inteldialect unwind",
5975 .@"asm sideeffect inteldialect unwind",
5976 .@"asm alignstack inteldialect unwind",
5977 .@"asm sideeffect alignstack inteldialect unwind",
5978 => |tag| {
5979 const extra = data.builder.constantExtraData(Asm, item.data);
5980 try writer.print("{s} {\"}, {\"}", .{
5981 @tagName(tag),
5982 extra.assembly.fmt(data.builder),
5983 extra.constraints.fmt(data.builder),
5984 });
5985 },
5839 }5986 }
5840 },5987 },
5841 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),5988 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
...@@ -6972,6 +7119,27 @@ pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant)...@@ -6972,6 +7119,27 @@ pub fn binValue(self: *Builder, tag: Constant.Tag, lhs: Constant, rhs: Constant)
6972 return (try self.binConst(tag, lhs, rhs)).toValue();7119 return (try self.binConst(tag, lhs, rhs)).toValue();
6973}7120}
69747121
7122pub fn asmConst(
7123 self: *Builder,
7124 ty: Type,
7125 info: Constant.Asm.Info,
7126 assembly: String,
7127 constraints: String,
7128) Allocator.Error!Constant {
7129 try self.ensureUnusedConstantCapacity(1, Constant.Asm, 0);
7130 return self.asmConstAssumeCapacity(ty, info, assembly, constraints);
7131}
7132
7133pub fn asmValue(
7134 self: *Builder,
7135 ty: Type,
7136 info: Constant.Asm.Info,
7137 assembly: String,
7138 constraints: String,
7139) Allocator.Error!Value {
7140 return (try self.asmConst(ty, info, assembly, constraints)).toValue();
7141}
7142
6975pub fn dump(self: *Builder) void {7143pub fn dump(self: *Builder) void {
6976 if (self.useLibLlvm())7144 if (self.useLibLlvm())
6977 self.llvm.module.?.dump()7145 self.llvm.module.?.dump()
...@@ -7303,7 +7471,15 @@ pub fn printUnbuffered(...@@ -7303,7 +7471,15 @@ pub fn printUnbuffered(
7303 arg.fmt(function_index, self),7471 arg.fmt(function_index, self),
7304 });7472 });
7305 }7473 }
7306 try writer.print("){}\n", .{extra.data.attributes.func(self).fmt(self)});7474 try writer.writeByte(')');
7475 const call_function_attributes = extra.data.attributes.func(self);
7476 if (call_function_attributes != .none) try writer.print(" #{d}", .{
7477 (try attribute_groups.getOrPutValue(
7478 self.gpa,
7479 call_function_attributes,
7480 {},
7481 )).index,
7482 });
7307 },7483 },
7308 .extractelement => |tag| {7484 .extractelement => |tag| {
7309 const extra =7485 const extra =
...@@ -7401,13 +7577,19 @@ pub fn printUnbuffered(...@@ -7401,13 +7577,19 @@ pub fn printUnbuffered(
7401 => |tag| {7577 => |tag| {
7402 const extra = function.extraData(Function.Instruction.Binary, instruction.data);7578 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
7403 const ty = instruction_index.typeOf(function_index, self);7579 const ty = instruction_index.typeOf(function_index, self);
7404 try writer.print(" %{} = call {%} @{s}{m}({%}, {%})\n", .{7580 try writer.print(" %{} = call {%} @{s}{m}({%}, {%}{s})\n", .{
7405 instruction_index.name(&function).fmt(self),7581 instruction_index.name(&function).fmt(self),
7406 ty.fmt(self),7582 ty.fmt(self),
7407 @tagName(tag),7583 @tagName(tag),
7408 ty.fmt(self),7584 ty.fmt(self),
7409 extra.lhs.fmt(function_index, self),7585 extra.lhs.fmt(function_index, self),
7410 extra.rhs.fmt(function_index, self),7586 extra.rhs.fmt(function_index, self),
7587 switch (tag) {
7588 .@"llvm.smul.fix.sat.",
7589 .@"llvm.umul.fix.sat.",
7590 => ", i32 0",
7591 else => "",
7592 },
7411 });7593 });
7412 },7594 },
7413 .load,7595 .load,
...@@ -7494,7 +7676,7 @@ pub fn printUnbuffered(...@@ -7494,7 +7676,7 @@ pub fn printUnbuffered(
7494 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);7676 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
7495 const blocks =7677 const blocks =
7496 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);7678 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
7497 try writer.print(" {s} {%}, {%} [", .{7679 try writer.print(" {s} {%}, {%} [\n", .{
7498 @tagName(tag),7680 @tagName(tag),
7499 extra.data.val.fmt(function_index, self),7681 extra.data.val.fmt(function_index, self),
7500 extra.data.default.toInst(&function).fmt(function_index, self),7682 extra.data.default.toInst(&function).fmt(function_index, self),
...@@ -7507,14 +7689,22 @@ pub fn printUnbuffered(...@@ -7507,14 +7689,22 @@ pub fn printUnbuffered(
7507 },7689 },
7508 .unimplemented => |tag| {7690 .unimplemented => |tag| {
7509 const ty: Type = @enumFromInt(instruction.data);7691 const ty: Type = @enumFromInt(instruction.data);
7510 try writer.writeAll(" ");7692 if (true) {
7511 switch (ty) {7693 try writer.writeAll(" ");
7694 switch (ty) {
7695 .none, .void => {},
7696 else => try writer.print("%{} = ", .{
7697 instruction_index.name(&function).fmt(self),
7698 }),
7699 }
7700 try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
7701 } else switch (ty) {
7512 .none, .void => {},7702 .none, .void => {},
7513 else => try writer.print("%{} = ", .{7703 else => try writer.print(" %{} = load {%}, ptr undef\n", .{
7514 instruction_index.name(&function).fmt(self),7704 instruction_index.name(&function).fmt(self),
7705 ty.fmt(self),
7515 }),7706 }),
7516 }7707 }
7517 try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
7518 },7708 },
7519 .va_arg => |tag| {7709 .va_arg => |tag| {
7520 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);7710 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
...@@ -7534,7 +7724,7 @@ pub fn printUnbuffered(...@@ -7534,7 +7724,7 @@ pub fn printUnbuffered(
75347724
7535 for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|7725 for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|
7536 try writer.print(7726 try writer.print(
7537 \\attribute #{d} = {{{"} }}7727 \\attributes #{d} = {{{#"} }}
7538 \\7728 \\
7539 , .{ attribute_group_index, attribute_group.fmt(self) });7729 , .{ attribute_group_index, attribute_group.fmt(self) });
7540}7730}
...@@ -9080,30 +9270,30 @@ fn binConstAssumeCapacity(...@@ -9080,30 +9270,30 @@ fn binConstAssumeCapacity(
9080 => {},9270 => {},
9081 else => unreachable,9271 else => unreachable,
9082 }9272 }
9083 const Key = struct { tag: Constant.Tag, bin: Constant.Binary };9273 const Key = struct { tag: Constant.Tag, extra: Constant.Binary };
9084 const Adapter = struct {9274 const Adapter = struct {
9085 builder: *const Builder,9275 builder: *const Builder,
9086 pub fn hash(_: @This(), key: Key) u32 {9276 pub fn hash(_: @This(), key: Key) u32 {
9087 return @truncate(std.hash.Wyhash.hash(9277 return @truncate(std.hash.Wyhash.hash(
9088 std.hash.uint32(@intFromEnum(key.tag)),9278 std.hash.uint32(@intFromEnum(key.tag)),
9089 std.mem.asBytes(&key.bin),9279 std.mem.asBytes(&key.extra),
9090 ));9280 ));
9091 }9281 }
9092 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {9282 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
9093 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;9283 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
9094 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];9284 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
9095 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);9285 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);
9096 return std.meta.eql(lhs_key.bin, rhs_extra);9286 return std.meta.eql(lhs_key.extra, rhs_extra);
9097 }9287 }
9098 };9288 };
9099 const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } };9289 const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } };
9100 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });9290 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
9101 if (!gop.found_existing) {9291 if (!gop.found_existing) {
9102 gop.key_ptr.* = {};9292 gop.key_ptr.* = {};
9103 gop.value_ptr.* = {};9293 gop.value_ptr.* = {};
9104 self.constant_items.appendAssumeCapacity(.{9294 self.constant_items.appendAssumeCapacity(.{
9105 .tag = tag,9295 .tag = tag,
9106 .data = self.addConstantExtraAssumeCapacity(data.bin),9296 .data = self.addConstantExtraAssumeCapacity(data.extra),
9107 });9297 });
9108 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) {9298 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) {
9109 .add => &llvm.Value.constAdd,9299 .add => &llvm.Value.constAdd,
...@@ -9121,6 +9311,61 @@ fn binConstAssumeCapacity(...@@ -9121,6 +9311,61 @@ fn binConstAssumeCapacity(
9121 return @enumFromInt(gop.index);9311 return @enumFromInt(gop.index);
9122}9312}
91239313
9314fn asmConstAssumeCapacity(
9315 self: *Builder,
9316 ty: Type,
9317 info: Constant.Asm.Info,
9318 assembly: String,
9319 constraints: String,
9320) Constant {
9321 const Key = struct { tag: Constant.Tag, extra: Constant.Asm };
9322 const Adapter = struct {
9323 builder: *const Builder,
9324 pub fn hash(_: @This(), key: Key) u32 {
9325 return @truncate(std.hash.Wyhash.hash(
9326 std.hash.uint32(@intFromEnum(key.tag)),
9327 std.mem.asBytes(&key.extra),
9328 ));
9329 }
9330 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
9331 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
9332 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
9333 const rhs_extra = ctx.builder.constantExtraData(Constant.Asm, rhs_data);
9334 return std.meta.eql(lhs_key.extra, rhs_extra);
9335 }
9336 };
9337
9338 const data = Key{
9339 .tag = @enumFromInt(@intFromEnum(Constant.Tag.@"asm") + @as(u4, @bitCast(info))),
9340 .extra = .{ .type = ty, .assembly = assembly, .constraints = constraints },
9341 };
9342 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
9343 if (!gop.found_existing) {
9344 gop.key_ptr.* = {};
9345 gop.value_ptr.* = {};
9346 self.constant_items.appendAssumeCapacity(.{
9347 .tag = data.tag,
9348 .data = self.addConstantExtraAssumeCapacity(data.extra),
9349 });
9350 if (self.useLibLlvm()) {
9351 const assembly_slice = assembly.slice(self).?;
9352 const constraints_slice = constraints.slice(self).?;
9353 self.llvm.constants.appendAssumeCapacity(llvm.getInlineAsm(
9354 ty.toLlvm(self),
9355 assembly_slice.ptr,
9356 assembly_slice.len,
9357 constraints_slice.ptr,
9358 constraints_slice.len,
9359 llvm.Bool.fromBool(info.sideeffect),
9360 llvm.Bool.fromBool(info.alignstack),
9361 if (info.inteldialect) .Intel else .ATT,
9362 llvm.Bool.fromBool(info.unwind),
9363 ));
9364 }
9365 }
9366 return @enumFromInt(gop.index);
9367}
9368
9124fn ensureUnusedConstantCapacity(9369fn ensureUnusedConstantCapacity(
9125 self: *Builder,9370 self: *Builder,
9126 count: usize,9371 count: usize,
...@@ -9211,7 +9456,7 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item....@@ -9211,7 +9456,7 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.
9211 const value = @field(extra, field.name);9456 const value = @field(extra, field.name);
9212 self.constant_extra.appendAssumeCapacity(switch (field.type) {9457 self.constant_extra.appendAssumeCapacity(switch (field.type) {
9213 u32 => value,9458 u32 => value,
9214 Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),9459 String, Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
9215 Constant.GetElementPtr.Info => @bitCast(value),9460 Constant.GetElementPtr.Info => @bitCast(value),
9216 else => @compileError("bad field type: " ++ @typeName(field.type)),9461 else => @compileError("bad field type: " ++ @typeName(field.type)),
9217 });9462 });
...@@ -9250,7 +9495,7 @@ fn constantExtraDataTrail(...@@ -9250,7 +9495,7 @@ fn constantExtraDataTrail(
9250 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|9495 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|
9251 @field(result, field.name) = switch (field.type) {9496 @field(result, field.name) = switch (field.type) {
9252 u32 => value,9497 u32 => value,
9253 Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),9498 String, Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
9254 Constant.GetElementPtr.Info => @bitCast(value),9499 Constant.GetElementPtr.Info => @bitCast(value),
9255 else => @compileError("bad field type: " ++ @typeName(field.type)),9500 else => @compileError("bad field type: " ++ @typeName(field.type)),
9256 };9501 };