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 {
67806780
67816781 const max_param_count = inputs.len + outputs.len;
67826782 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);
67846784 // This stores whether we need to add an elementtype attribute and
67856785 // if so, the element type itself.
67866786 const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);
......@@ -6820,7 +6820,7 @@ pub const FuncGen = struct {
68206820 // Pass the result by reference as an indirect output (e.g. "=*m")
68216821 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;
68246824 llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
68256825 llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
68266826 llvm_param_i += 1;
......@@ -6870,25 +6870,25 @@ pub const FuncGen = struct {
68706870 if (isByRef(arg_ty, mod)) {
68716871 llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
68726872 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;
68746874 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
68756875 } else {
68766876 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
68776877 const arg_llvm_ty = try o.lowerType(arg_ty);
68786878 const load_inst =
68796879 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;
68816881 llvm_param_types[llvm_param_i] = arg_llvm_ty;
68826882 }
68836883 } else {
68846884 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;
68866886 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
68876887 } else {
68886888 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
68896889 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
68906890 _ = 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;
68926892 llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
68936893 }
68946894 }
......@@ -7037,40 +7037,24 @@ pub const FuncGen = struct {
70377037
70387038 var attributes: Builder.FunctionAttributes.Wip = .{};
70397039 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
70417043 const ret_llvm_ty = switch (return_count) {
70427044 0 => .void,
70437045 1 => llvm_ret_types[0],
70447046 else => try o.builder.structType(.normal, llvm_ret_types),
70457047 };
7046
70477048 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 llvm_fn_ty.toLlvm(&o.builder),
7050 rendered_template.items.ptr,
7051 rendered_template.items.len,
7052 llvm_constraints.items.ptr,
7053 llvm_constraints.items.len,
7054 llvm.Bool.fromBool(is_volatile),
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,
7049 const call = try self.wip.callAsm(
7050 try attributes.finish(&o.builder),
7051 llvm_fn_ty,
7052 .{ .sideeffect = is_volatile },
7053 try o.builder.string(rendered_template.items),
7054 try o.builder.string(llvm_constraints.items),
7055 llvm_param_values[0..param_count],
70667056 "",
7067 ), &self.wip);
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 }
7057 );
70747058
70757059 var ret_val = call;
70767060 llvm_ret_i = 0;
src/codegen/llvm/Builder.zig+281-36
......@@ -1072,7 +1072,7 @@ pub const Attribute = union(Kind) {
10721072 _: std.fmt.FormatOptions,
10731073 writer: anytype,
10741074 ) @TypeOf(writer).Error!void {
1075 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"")) |_|
1075 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_|
10761076 @compileError("invalid format string: '" ++ fmt_str ++ "'");
10771077 const attribute = data.attribute_index.toAttribute(data.builder);
10781078 switch (attribute) {
......@@ -1154,17 +1154,72 @@ pub const Attribute = union(Kind) {
11541154 .sret,
11551155 .elementtype,
11561156 => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
1157 .@"align" => @panic("todo"),
1157 .@"align" => |alignment| try writer.print("{}", .{alignment}),
11581158 .dereferenceable,
11591159 .dereferenceable_or_null,
1160 => @panic("todo"),
1161 .nofpclass => @panic("todo"),
1162 .alignstack => @panic("todo"),
1163 .allockind => @panic("todo"),
1164 .allocsize => @panic("todo"),
1165 .memory => @panic("todo"),
1166 .uwtable => @panic("todo"),
1167 .vscale_range => @panic("todo"),
1160 => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }),
1161 .nofpclass => |fpclass| {
1162 const Int = @typeInfo(FpClass).Struct.backing_integer.?;
1163 try writer.print("{s}(", .{@tagName(attribute)});
1164 var any = false;
1165 var remaining: Int = @bitCast(fpclass);
1166 inline for (@typeInfo(FpClass).Struct.decls) |decl| {
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 }),
11681223 .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {
11691224 try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});
11701225 if (string_attr.value != .empty)
......@@ -1314,11 +1369,6 @@ pub const Attribute = union(Kind) {
13141369 positive_infinity: bool = false,
13151370 _: 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 };
13221372 pub const all = FpClass{
13231373 .signaling_nan = true,
13241374 .quiet_nan = true,
......@@ -1331,16 +1381,26 @@ pub const Attribute = union(Kind) {
13311381 .positive_normal = true,
13321382 .positive_infinity = true,
13331383 };
1384
1385 pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
13341386 pub const snan = FpClass{ .signaling_nan = true };
13351387 pub const qnan = FpClass{ .quiet_nan = true };
1388
1389 pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
13361390 pub const ninf = FpClass{ .negative_infinity = true };
1337 pub const nnorm = FpClass{ .negative_normal = true };
1338 pub const nsub = FpClass{ .negative_subnormal = true };
1391 pub const pinf = FpClass{ .positive_infinity = true };
1392
1393 pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
13391394 pub const nzero = FpClass{ .negative_zero = true };
13401395 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 };
13411399 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 };
13421403 pub const pnorm = FpClass{ .positive_normal = true };
1343 pub const pinf = FpClass{ .positive_infinity = true };
13441404 };
13451405
13461406 pub const AllocKind = packed struct(u32) {
......@@ -1924,7 +1984,7 @@ pub const CallConv = enum(u10) {
19241984 writer: anytype,
19251985 ) @TypeOf(writer).Error!void {
19261986 switch (self) {
1927 .ccc => {},
1987 default => {},
19281988 .fastcc,
19291989 .coldcc,
19301990 .ghccc,
......@@ -2445,6 +2505,7 @@ pub const Function = struct {
24452505 .br_cond,
24462506 .ret,
24472507 .@"ret void",
2508 .@"switch",
24482509 .@"unreachable",
24492510 => true,
24502511 else => false,
......@@ -2462,6 +2523,7 @@ pub const Function = struct {
24622523 .@"store atomic",
24632524 .@"store atomic volatile",
24642525 .@"store volatile",
2526 .@"switch",
24652527 .@"unreachable",
24662528 => false,
24672529 .call,
......@@ -2472,6 +2534,7 @@ pub const Function = struct {
24722534 .@"notail call fast",
24732535 .@"tail call",
24742536 .@"tail call fast",
2537 .unimplemented,
24752538 => self.typeOfWip(wip) != .void,
24762539 else => true,
24772540 };
......@@ -4165,7 +4228,7 @@ pub const WipFunction = struct {
41654228 callee: Value,
41664229 args: []const Value,
41674230 name: []const u8,
4168 ) if (build_options.have_llvm) Allocator.Error!Value else Value {
4231 ) Allocator.Error!Value {
41694232 const ret_ty = ty.functionReturn(self.builder);
41704233 assert(ty.isFunction(self.builder));
41714234 assert(callee.typeOfWip(self).isPointer(self.builder));
......@@ -4238,6 +4301,20 @@ pub const WipFunction = struct {
42384301 return instruction.toValue();
42394302 }
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
42414318 pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
42424319 try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
42434320 const instruction = try self.addInst(name, .{
......@@ -5216,7 +5293,7 @@ pub const Constant = enum(u32) {
52165293
52175294 const first_global: Constant = @enumFromInt(1 << 30);
52185295
5219 pub const Tag = enum(u6) {
5296 pub const Tag = enum(u7) {
52205297 positive_integer,
52215298 negative_integer,
52225299 half,
......@@ -5276,6 +5353,22 @@ pub const Constant = enum(u32) {
52765353 @"and",
52775354 @"or",
52785355 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",
52795372 };
52805373
52815374 pub const Item = struct {
......@@ -5371,6 +5464,19 @@ pub const Constant = enum(u32) {
53715464 rhs: Constant,
53725465 };
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
53745480 pub fn unwrap(self: Constant) union(enum) {
53755481 constant: u30,
53765482 global: Global.Index,
......@@ -5489,6 +5595,23 @@ pub const Constant = enum(u32) {
54895595 .@"or",
54905596 .xor,
54915597 => 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,
54925615 };
54935616 },
54945617 .global => |global| return builder.ptrTypeAssumeCapacity(
......@@ -5836,6 +5959,30 @@ pub const Constant = enum(u32) {
58365959 extra.rhs.fmt(data.builder),
58375960 });
58385961 },
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 },
58395986 }
58405987 },
58415988 .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)
69727119 return (try self.binConst(tag, lhs, rhs)).toValue();
69737120}
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
69757143pub fn dump(self: *Builder) void {
69767144 if (self.useLibLlvm())
69777145 self.llvm.module.?.dump()
......@@ -7303,7 +7471,15 @@ pub fn printUnbuffered(
73037471 arg.fmt(function_index, self),
73047472 });
73057473 }
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 });
73077483 },
73087484 .extractelement => |tag| {
73097485 const extra =
......@@ -7401,13 +7577,19 @@ pub fn printUnbuffered(
74017577 => |tag| {
74027578 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
74037579 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", .{
74057581 instruction_index.name(&function).fmt(self),
74067582 ty.fmt(self),
74077583 @tagName(tag),
74087584 ty.fmt(self),
74097585 extra.lhs.fmt(function_index, self),
74107586 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 },
74117593 });
74127594 },
74137595 .load,
......@@ -7494,7 +7676,7 @@ pub fn printUnbuffered(
74947676 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
74957677 const blocks =
74967678 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
7497 try writer.print(" {s} {%}, {%} [", .{
7679 try writer.print(" {s} {%}, {%} [\n", .{
74987680 @tagName(tag),
74997681 extra.data.val.fmt(function_index, self),
75007682 extra.data.default.toInst(&function).fmt(function_index, self),
......@@ -7507,14 +7689,22 @@ pub fn printUnbuffered(
75077689 },
75087690 .unimplemented => |tag| {
75097691 const ty: Type = @enumFromInt(instruction.data);
7510 try writer.writeAll(" ");
7511 switch (ty) {
7692 if (true) {
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) {
75127702 .none, .void => {},
7513 else => try writer.print("%{} = ", .{
7703 else => try writer.print(" %{} = load {%}, ptr undef\n", .{
75147704 instruction_index.name(&function).fmt(self),
7705 ty.fmt(self),
75157706 }),
75167707 }
7517 try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
75187708 },
75197709 .va_arg => |tag| {
75207710 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
......@@ -7534,7 +7724,7 @@ pub fn printUnbuffered(
75347724
75357725 for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|
75367726 try writer.print(
7537 \\attribute #{d} = {{{"} }}
7727 \\attributes #{d} = {{{#"} }}
75387728 \\
75397729 , .{ attribute_group_index, attribute_group.fmt(self) });
75407730}
......@@ -9080,30 +9270,30 @@ fn binConstAssumeCapacity(
90809270 => {},
90819271 else => unreachable,
90829272 }
9083 const Key = struct { tag: Constant.Tag, bin: Constant.Binary };
9273 const Key = struct { tag: Constant.Tag, extra: Constant.Binary };
90849274 const Adapter = struct {
90859275 builder: *const Builder,
90869276 pub fn hash(_: @This(), key: Key) u32 {
90879277 return @truncate(std.hash.Wyhash.hash(
90889278 std.hash.uint32(@intFromEnum(key.tag)),
9089 std.mem.asBytes(&key.bin),
9279 std.mem.asBytes(&key.extra),
90909280 ));
90919281 }
90929282 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
90939283 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
90949284 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
90959285 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);
90979287 }
90989288 };
9099 const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } };
9289 const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } };
91009290 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
91019291 if (!gop.found_existing) {
91029292 gop.key_ptr.* = {};
91039293 gop.value_ptr.* = {};
91049294 self.constant_items.appendAssumeCapacity(.{
91059295 .tag = tag,
9106 .data = self.addConstantExtraAssumeCapacity(data.bin),
9296 .data = self.addConstantExtraAssumeCapacity(data.extra),
91079297 });
91089298 if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) {
91099299 .add => &llvm.Value.constAdd,
......@@ -9121,6 +9311,61 @@ fn binConstAssumeCapacity(
91219311 return @enumFromInt(gop.index);
91229312}
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
91249369fn ensureUnusedConstantCapacity(
91259370 self: *Builder,
91269371 count: usize,
......@@ -9211,7 +9456,7 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.
92119456 const value = @field(extra, field.name);
92129457 self.constant_extra.appendAssumeCapacity(switch (field.type) {
92139458 u32 => value,
9214 Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
9459 String, Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
92159460 Constant.GetElementPtr.Info => @bitCast(value),
92169461 else => @compileError("bad field type: " ++ @typeName(field.type)),
92179462 });
......@@ -9250,7 +9495,7 @@ fn constantExtraDataTrail(
92509495 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|
92519496 @field(result, field.name) = switch (field.type) {
92529497 u32 => value,
9253 Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
9498 String, Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
92549499 Constant.GetElementPtr.Info => @bitCast(value),
92559500 else => @compileError("bad field type: " ++ @typeName(field.type)),
92569501 };