mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 21:38:33 +00:00
llvm: convert inline assembly
Also, implement TODOs from a previous commit.
This commit is contained in:
parent
c610cde1eb
commit
533111e849
@ -6780,7 +6780,7 @@ pub const FuncGen = struct {
|
||||
|
||||
const max_param_count = inputs.len + outputs.len;
|
||||
const llvm_param_types = try arena.alloc(Builder.Type, max_param_count);
|
||||
const llvm_param_values = try arena.alloc(*llvm.Value, max_param_count);
|
||||
const llvm_param_values = try arena.alloc(Builder.Value, max_param_count);
|
||||
// This stores whether we need to add an elementtype attribute and
|
||||
// if so, the element type itself.
|
||||
const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);
|
||||
@ -6820,7 +6820,7 @@ pub const FuncGen = struct {
|
||||
// Pass the result by reference as an indirect output (e.g. "=*m")
|
||||
llvm_constraints.appendAssumeCapacity('*');
|
||||
|
||||
llvm_param_values[llvm_param_i] = output_inst.toLlvm(&self.wip);
|
||||
llvm_param_values[llvm_param_i] = output_inst;
|
||||
llvm_param_types[llvm_param_i] = output_inst.typeOfWip(&self.wip);
|
||||
llvm_param_attrs[llvm_param_i] = elem_llvm_ty;
|
||||
llvm_param_i += 1;
|
||||
@ -6870,25 +6870,25 @@ pub const FuncGen = struct {
|
||||
if (isByRef(arg_ty, mod)) {
|
||||
llvm_elem_ty = try o.lowerPtrElemTy(arg_ty);
|
||||
if (constraintAllowsMemory(constraint)) {
|
||||
llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
|
||||
llvm_param_values[llvm_param_i] = arg_llvm_value;
|
||||
llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
|
||||
} else {
|
||||
const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
|
||||
const arg_llvm_ty = try o.lowerType(arg_ty);
|
||||
const load_inst =
|
||||
try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
|
||||
llvm_param_values[llvm_param_i] = load_inst.toLlvm(&self.wip);
|
||||
llvm_param_values[llvm_param_i] = load_inst;
|
||||
llvm_param_types[llvm_param_i] = arg_llvm_ty;
|
||||
}
|
||||
} else {
|
||||
if (constraintAllowsRegister(constraint)) {
|
||||
llvm_param_values[llvm_param_i] = arg_llvm_value.toLlvm(&self.wip);
|
||||
llvm_param_values[llvm_param_i] = arg_llvm_value;
|
||||
llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
|
||||
} else {
|
||||
const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
|
||||
const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
|
||||
_ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
|
||||
llvm_param_values[llvm_param_i] = arg_ptr.toLlvm(&self.wip);
|
||||
llvm_param_values[llvm_param_i] = arg_ptr;
|
||||
llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip);
|
||||
}
|
||||
}
|
||||
@ -7037,40 +7037,24 @@ pub const FuncGen = struct {
|
||||
|
||||
var attributes: Builder.FunctionAttributes.Wip = .{};
|
||||
defer attributes.deinit(&o.builder);
|
||||
for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| if (llvm_elem_ty != .none)
|
||||
try attributes.addParamAttr(i, .{ .elementtype = llvm_elem_ty }, &o.builder);
|
||||
|
||||
const ret_llvm_ty = switch (return_count) {
|
||||
0 => .void,
|
||||
1 => llvm_ret_types[0],
|
||||
else => try o.builder.structType(.normal, llvm_ret_types),
|
||||
};
|
||||
|
||||
const llvm_fn_ty = try o.builder.fnType(ret_llvm_ty, llvm_param_types[0..param_count], .normal);
|
||||
const asm_fn = llvm.getInlineAsm(
|
||||
llvm_fn_ty.toLlvm(&o.builder),
|
||||
rendered_template.items.ptr,
|
||||
rendered_template.items.len,
|
||||
llvm_constraints.items.ptr,
|
||||
llvm_constraints.items.len,
|
||||
llvm.Bool.fromBool(is_volatile),
|
||||
.False,
|
||||
.ATT,
|
||||
.False,
|
||||
);
|
||||
const call = (try self.wip.unimplemented(ret_llvm_ty, "")).finish(self.builder.buildCallOld(
|
||||
llvm_fn_ty.toLlvm(&o.builder),
|
||||
asm_fn,
|
||||
llvm_param_values.ptr,
|
||||
@intCast(param_count),
|
||||
.C,
|
||||
.Auto,
|
||||
const call = try self.wip.callAsm(
|
||||
try attributes.finish(&o.builder),
|
||||
llvm_fn_ty,
|
||||
.{ .sideeffect = is_volatile },
|
||||
try o.builder.string(rendered_template.items),
|
||||
try o.builder.string(llvm_constraints.items),
|
||||
llvm_param_values[0..param_count],
|
||||
"",
|
||||
), &self.wip);
|
||||
for (llvm_param_attrs[0..param_count], 0..) |llvm_elem_ty, i| {
|
||||
if (llvm_elem_ty != .none) {
|
||||
try attributes.addParamAttr(i, .{ .elementtype = llvm_elem_ty }, &o.builder);
|
||||
llvm.setCallElemTypeAttr(call.toLlvm(&self.wip), i, llvm_elem_ty.toLlvm(&o.builder));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
var ret_val = call;
|
||||
llvm_ret_i = 0;
|
||||
|
||||
@ -1072,7 +1072,7 @@ pub const Attribute = union(Kind) {
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (comptime std.mem.indexOfNone(u8, fmt_str, "\"")) |_|
|
||||
if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_|
|
||||
@compileError("invalid format string: '" ++ fmt_str ++ "'");
|
||||
const attribute = data.attribute_index.toAttribute(data.builder);
|
||||
switch (attribute) {
|
||||
@ -1154,17 +1154,72 @@ pub const Attribute = union(Kind) {
|
||||
.sret,
|
||||
.elementtype,
|
||||
=> |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
|
||||
.@"align" => @panic("todo"),
|
||||
.@"align" => |alignment| try writer.print("{}", .{alignment}),
|
||||
.dereferenceable,
|
||||
.dereferenceable_or_null,
|
||||
=> @panic("todo"),
|
||||
.nofpclass => @panic("todo"),
|
||||
.alignstack => @panic("todo"),
|
||||
.allockind => @panic("todo"),
|
||||
.allocsize => @panic("todo"),
|
||||
.memory => @panic("todo"),
|
||||
.uwtable => @panic("todo"),
|
||||
.vscale_range => @panic("todo"),
|
||||
=> |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }),
|
||||
.nofpclass => |fpclass| {
|
||||
const Int = @typeInfo(FpClass).Struct.backing_integer.?;
|
||||
try writer.print("{s}(", .{@tagName(attribute)});
|
||||
var any = false;
|
||||
var remaining: Int = @bitCast(fpclass);
|
||||
inline for (@typeInfo(FpClass).Struct.decls) |decl| {
|
||||
if (!decl.is_pub) continue;
|
||||
const pattern: Int = @bitCast(@field(FpClass, decl.name));
|
||||
if (remaining & pattern == pattern) {
|
||||
if (!any) {
|
||||
try writer.writeByte(' ');
|
||||
any = true;
|
||||
}
|
||||
try writer.writeAll(decl.name);
|
||||
remaining &= ~pattern;
|
||||
}
|
||||
}
|
||||
try writer.writeByte(')');
|
||||
},
|
||||
.alignstack => |alignment| try writer.print(
|
||||
if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null)
|
||||
"{s}={d}"
|
||||
else
|
||||
"{s}({d})",
|
||||
.{ @tagName(attribute), alignment.toByteUnits() orelse return },
|
||||
),
|
||||
.allockind => |allockind| {
|
||||
try writer.print("{s}(\"", .{@tagName(attribute)});
|
||||
var any = false;
|
||||
inline for (@typeInfo(AllocKind).Struct.fields) |field| {
|
||||
if (comptime std.mem.eql(u8, field.name, "_")) continue;
|
||||
if (@field(allockind, field.name)) {
|
||||
if (!any) {
|
||||
try writer.writeByte(',');
|
||||
any = true;
|
||||
}
|
||||
try writer.writeAll(field.name);
|
||||
}
|
||||
}
|
||||
try writer.writeAll("\")");
|
||||
},
|
||||
.allocsize => |allocsize| {
|
||||
try writer.print("{s}({d}", .{ @tagName(attribute), allocsize.elem_size });
|
||||
if (allocsize.num_elems != AllocSize.none)
|
||||
try writer.print(",{d}", .{allocsize.num_elems});
|
||||
try writer.writeByte(')');
|
||||
},
|
||||
.memory => |memory| try writer.print("{s}({s}, argmem: {s}, inaccessiblemem: {s})", .{
|
||||
@tagName(attribute),
|
||||
@tagName(memory.other),
|
||||
@tagName(memory.argmem),
|
||||
@tagName(memory.inaccessiblemem),
|
||||
}),
|
||||
.uwtable => |uwtable| if (uwtable != .none) {
|
||||
try writer.writeAll(@tagName(attribute));
|
||||
if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)});
|
||||
},
|
||||
.vscale_range => |vscale_range| try writer.print("{s}({d},{d})", .{
|
||||
@tagName(attribute),
|
||||
vscale_range.min.toByteUnits().?,
|
||||
vscale_range.max.toByteUnits() orelse 0,
|
||||
}),
|
||||
.string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {
|
||||
try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});
|
||||
if (string_attr.value != .empty)
|
||||
@ -1314,11 +1369,6 @@ pub const Attribute = union(Kind) {
|
||||
positive_infinity: bool = false,
|
||||
_: u22 = 0,
|
||||
|
||||
pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
|
||||
pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
|
||||
pub const norm = FpClass{ .positive_normal = true, .negative_normal = true };
|
||||
pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true };
|
||||
pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
|
||||
pub const all = FpClass{
|
||||
.signaling_nan = true,
|
||||
.quiet_nan = true,
|
||||
@ -1331,16 +1381,26 @@ pub const Attribute = union(Kind) {
|
||||
.positive_normal = true,
|
||||
.positive_infinity = true,
|
||||
};
|
||||
|
||||
pub const nan = FpClass{ .signaling_nan = true, .quiet_nan = true };
|
||||
pub const snan = FpClass{ .signaling_nan = true };
|
||||
pub const qnan = FpClass{ .quiet_nan = true };
|
||||
|
||||
pub const inf = FpClass{ .negative_infinity = true, .positive_infinity = true };
|
||||
pub const ninf = FpClass{ .negative_infinity = true };
|
||||
pub const nnorm = FpClass{ .negative_normal = true };
|
||||
pub const nsub = FpClass{ .negative_subnormal = true };
|
||||
pub const pinf = FpClass{ .positive_infinity = true };
|
||||
|
||||
pub const zero = FpClass{ .positive_zero = true, .negative_zero = true };
|
||||
pub const nzero = FpClass{ .negative_zero = true };
|
||||
pub const pzero = FpClass{ .positive_zero = true };
|
||||
|
||||
pub const sub = FpClass{ .positive_subnormal = true, .negative_subnormal = true };
|
||||
pub const nsub = FpClass{ .negative_subnormal = true };
|
||||
pub const psub = FpClass{ .positive_subnormal = true };
|
||||
|
||||
pub const norm = FpClass{ .positive_normal = true, .negative_normal = true };
|
||||
pub const nnorm = FpClass{ .negative_normal = true };
|
||||
pub const pnorm = FpClass{ .positive_normal = true };
|
||||
pub const pinf = FpClass{ .positive_infinity = true };
|
||||
};
|
||||
|
||||
pub const AllocKind = packed struct(u32) {
|
||||
@ -1924,7 +1984,7 @@ pub const CallConv = enum(u10) {
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
switch (self) {
|
||||
.ccc => {},
|
||||
default => {},
|
||||
.fastcc,
|
||||
.coldcc,
|
||||
.ghccc,
|
||||
@ -2445,6 +2505,7 @@ pub const Function = struct {
|
||||
.br_cond,
|
||||
.ret,
|
||||
.@"ret void",
|
||||
.@"switch",
|
||||
.@"unreachable",
|
||||
=> true,
|
||||
else => false,
|
||||
@ -2462,6 +2523,7 @@ pub const Function = struct {
|
||||
.@"store atomic",
|
||||
.@"store atomic volatile",
|
||||
.@"store volatile",
|
||||
.@"switch",
|
||||
.@"unreachable",
|
||||
=> false,
|
||||
.call,
|
||||
@ -2472,6 +2534,7 @@ pub const Function = struct {
|
||||
.@"notail call fast",
|
||||
.@"tail call",
|
||||
.@"tail call fast",
|
||||
.unimplemented,
|
||||
=> self.typeOfWip(wip) != .void,
|
||||
else => true,
|
||||
};
|
||||
@ -4165,7 +4228,7 @@ pub const WipFunction = struct {
|
||||
callee: Value,
|
||||
args: []const Value,
|
||||
name: []const u8,
|
||||
) if (build_options.have_llvm) Allocator.Error!Value else Value {
|
||||
) Allocator.Error!Value {
|
||||
const ret_ty = ty.functionReturn(self.builder);
|
||||
assert(ty.isFunction(self.builder));
|
||||
assert(callee.typeOfWip(self).isPointer(self.builder));
|
||||
@ -4238,6 +4301,20 @@ pub const WipFunction = struct {
|
||||
return instruction.toValue();
|
||||
}
|
||||
|
||||
pub fn callAsm(
|
||||
self: *WipFunction,
|
||||
function_attributes: FunctionAttributes,
|
||||
ty: Type,
|
||||
kind: Constant.Asm.Info,
|
||||
assembly: String,
|
||||
constraints: String,
|
||||
args: []const Value,
|
||||
name: []const u8,
|
||||
) Allocator.Error!Value {
|
||||
const callee = try self.builder.asmValue(ty, kind, assembly, constraints);
|
||||
return self.call(.normal, CallConv.default, function_attributes, ty, callee, args, name);
|
||||
}
|
||||
|
||||
pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
|
||||
try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
|
||||
const instruction = try self.addInst(name, .{
|
||||
@ -5216,7 +5293,7 @@ pub const Constant = enum(u32) {
|
||||
|
||||
const first_global: Constant = @enumFromInt(1 << 30);
|
||||
|
||||
pub const Tag = enum(u6) {
|
||||
pub const Tag = enum(u7) {
|
||||
positive_integer,
|
||||
negative_integer,
|
||||
half,
|
||||
@ -5276,6 +5353,22 @@ pub const Constant = enum(u32) {
|
||||
@"and",
|
||||
@"or",
|
||||
xor,
|
||||
@"asm",
|
||||
@"asm sideeffect",
|
||||
@"asm alignstack",
|
||||
@"asm sideeffect alignstack",
|
||||
@"asm inteldialect",
|
||||
@"asm sideeffect inteldialect",
|
||||
@"asm alignstack inteldialect",
|
||||
@"asm sideeffect alignstack inteldialect",
|
||||
@"asm unwind",
|
||||
@"asm sideeffect unwind",
|
||||
@"asm alignstack unwind",
|
||||
@"asm sideeffect alignstack unwind",
|
||||
@"asm inteldialect unwind",
|
||||
@"asm sideeffect inteldialect unwind",
|
||||
@"asm alignstack inteldialect unwind",
|
||||
@"asm sideeffect alignstack inteldialect unwind",
|
||||
};
|
||||
|
||||
pub const Item = struct {
|
||||
@ -5371,6 +5464,19 @@ pub const Constant = enum(u32) {
|
||||
rhs: Constant,
|
||||
};
|
||||
|
||||
pub const Asm = extern struct {
|
||||
type: Type,
|
||||
assembly: String,
|
||||
constraints: String,
|
||||
|
||||
pub const Info = packed struct {
|
||||
sideeffect: bool = false,
|
||||
alignstack: bool = false,
|
||||
inteldialect: bool = false,
|
||||
unwind: bool = false,
|
||||
};
|
||||
};
|
||||
|
||||
pub fn unwrap(self: Constant) union(enum) {
|
||||
constant: u30,
|
||||
global: Global.Index,
|
||||
@ -5489,6 +5595,23 @@ pub const Constant = enum(u32) {
|
||||
.@"or",
|
||||
.xor,
|
||||
=> builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
|
||||
.@"asm",
|
||||
.@"asm sideeffect",
|
||||
.@"asm alignstack",
|
||||
.@"asm sideeffect alignstack",
|
||||
.@"asm inteldialect",
|
||||
.@"asm sideeffect inteldialect",
|
||||
.@"asm alignstack inteldialect",
|
||||
.@"asm sideeffect alignstack inteldialect",
|
||||
.@"asm unwind",
|
||||
.@"asm sideeffect unwind",
|
||||
.@"asm alignstack unwind",
|
||||
.@"asm sideeffect alignstack unwind",
|
||||
.@"asm inteldialect unwind",
|
||||
.@"asm sideeffect inteldialect unwind",
|
||||
.@"asm alignstack inteldialect unwind",
|
||||
.@"asm sideeffect alignstack inteldialect unwind",
|
||||
=> .ptr,
|
||||
};
|
||||
},
|
||||
.global => |global| return builder.ptrTypeAssumeCapacity(
|
||||
@ -5836,6 +5959,30 @@ pub const Constant = enum(u32) {
|
||||
extra.rhs.fmt(data.builder),
|
||||
});
|
||||
},
|
||||
.@"asm",
|
||||
.@"asm sideeffect",
|
||||
.@"asm alignstack",
|
||||
.@"asm sideeffect alignstack",
|
||||
.@"asm inteldialect",
|
||||
.@"asm sideeffect inteldialect",
|
||||
.@"asm alignstack inteldialect",
|
||||
.@"asm sideeffect alignstack inteldialect",
|
||||
.@"asm unwind",
|
||||
.@"asm sideeffect unwind",
|
||||
.@"asm alignstack unwind",
|
||||
.@"asm sideeffect alignstack unwind",
|
||||
.@"asm inteldialect unwind",
|
||||
.@"asm sideeffect inteldialect unwind",
|
||||
.@"asm alignstack inteldialect unwind",
|
||||
.@"asm sideeffect alignstack inteldialect unwind",
|
||||
=> |tag| {
|
||||
const extra = data.builder.constantExtraData(Asm, item.data);
|
||||
try writer.print("{s} {\"}, {\"}", .{
|
||||
@tagName(tag),
|
||||
extra.assembly.fmt(data.builder),
|
||||
extra.constraints.fmt(data.builder),
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
.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)
|
||||
return (try self.binConst(tag, lhs, rhs)).toValue();
|
||||
}
|
||||
|
||||
pub fn asmConst(
|
||||
self: *Builder,
|
||||
ty: Type,
|
||||
info: Constant.Asm.Info,
|
||||
assembly: String,
|
||||
constraints: String,
|
||||
) Allocator.Error!Constant {
|
||||
try self.ensureUnusedConstantCapacity(1, Constant.Asm, 0);
|
||||
return self.asmConstAssumeCapacity(ty, info, assembly, constraints);
|
||||
}
|
||||
|
||||
pub fn asmValue(
|
||||
self: *Builder,
|
||||
ty: Type,
|
||||
info: Constant.Asm.Info,
|
||||
assembly: String,
|
||||
constraints: String,
|
||||
) Allocator.Error!Value {
|
||||
return (try self.asmConst(ty, info, assembly, constraints)).toValue();
|
||||
}
|
||||
|
||||
pub fn dump(self: *Builder) void {
|
||||
if (self.useLibLlvm())
|
||||
self.llvm.module.?.dump()
|
||||
@ -7303,7 +7471,15 @@ pub fn printUnbuffered(
|
||||
arg.fmt(function_index, self),
|
||||
});
|
||||
}
|
||||
try writer.print("){}\n", .{extra.data.attributes.func(self).fmt(self)});
|
||||
try writer.writeByte(')');
|
||||
const call_function_attributes = extra.data.attributes.func(self);
|
||||
if (call_function_attributes != .none) try writer.print(" #{d}", .{
|
||||
(try attribute_groups.getOrPutValue(
|
||||
self.gpa,
|
||||
call_function_attributes,
|
||||
{},
|
||||
)).index,
|
||||
});
|
||||
},
|
||||
.extractelement => |tag| {
|
||||
const extra =
|
||||
@ -7401,13 +7577,19 @@ pub fn printUnbuffered(
|
||||
=> |tag| {
|
||||
const extra = function.extraData(Function.Instruction.Binary, instruction.data);
|
||||
const ty = instruction_index.typeOf(function_index, self);
|
||||
try writer.print(" %{} = call {%} @{s}{m}({%}, {%})\n", .{
|
||||
try writer.print(" %{} = call {%} @{s}{m}({%}, {%}{s})\n", .{
|
||||
instruction_index.name(&function).fmt(self),
|
||||
ty.fmt(self),
|
||||
@tagName(tag),
|
||||
ty.fmt(self),
|
||||
extra.lhs.fmt(function_index, self),
|
||||
extra.rhs.fmt(function_index, self),
|
||||
switch (tag) {
|
||||
.@"llvm.smul.fix.sat.",
|
||||
.@"llvm.umul.fix.sat.",
|
||||
=> ", i32 0",
|
||||
else => "",
|
||||
},
|
||||
});
|
||||
},
|
||||
.load,
|
||||
@ -7494,7 +7676,7 @@ pub fn printUnbuffered(
|
||||
const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
|
||||
const blocks =
|
||||
extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
|
||||
try writer.print(" {s} {%}, {%} [", .{
|
||||
try writer.print(" {s} {%}, {%} [\n", .{
|
||||
@tagName(tag),
|
||||
extra.data.val.fmt(function_index, self),
|
||||
extra.data.default.toInst(&function).fmt(function_index, self),
|
||||
@ -7507,14 +7689,22 @@ pub fn printUnbuffered(
|
||||
},
|
||||
.unimplemented => |tag| {
|
||||
const ty: Type = @enumFromInt(instruction.data);
|
||||
try writer.writeAll(" ");
|
||||
switch (ty) {
|
||||
if (true) {
|
||||
try writer.writeAll(" ");
|
||||
switch (ty) {
|
||||
.none, .void => {},
|
||||
else => try writer.print("%{} = ", .{
|
||||
instruction_index.name(&function).fmt(self),
|
||||
}),
|
||||
}
|
||||
try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
|
||||
} else switch (ty) {
|
||||
.none, .void => {},
|
||||
else => try writer.print("%{} = ", .{
|
||||
else => try writer.print(" %{} = load {%}, ptr undef\n", .{
|
||||
instruction_index.name(&function).fmt(self),
|
||||
ty.fmt(self),
|
||||
}),
|
||||
}
|
||||
try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
|
||||
},
|
||||
.va_arg => |tag| {
|
||||
const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
|
||||
@ -7534,7 +7724,7 @@ pub fn printUnbuffered(
|
||||
|
||||
for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|
|
||||
try writer.print(
|
||||
\\attribute #{d} = {{{"} }}
|
||||
\\attributes #{d} = {{{#"} }}
|
||||
\\
|
||||
, .{ attribute_group_index, attribute_group.fmt(self) });
|
||||
}
|
||||
@ -9080,30 +9270,30 @@ fn binConstAssumeCapacity(
|
||||
=> {},
|
||||
else => unreachable,
|
||||
}
|
||||
const Key = struct { tag: Constant.Tag, bin: Constant.Binary };
|
||||
const Key = struct { tag: Constant.Tag, extra: Constant.Binary };
|
||||
const Adapter = struct {
|
||||
builder: *const Builder,
|
||||
pub fn hash(_: @This(), key: Key) u32 {
|
||||
return @truncate(std.hash.Wyhash.hash(
|
||||
std.hash.uint32(@intFromEnum(key.tag)),
|
||||
std.mem.asBytes(&key.bin),
|
||||
std.mem.asBytes(&key.extra),
|
||||
));
|
||||
}
|
||||
pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
|
||||
if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
|
||||
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
|
||||
const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);
|
||||
return std.meta.eql(lhs_key.bin, rhs_extra);
|
||||
return std.meta.eql(lhs_key.extra, rhs_extra);
|
||||
}
|
||||
};
|
||||
const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } };
|
||||
const data = Key{ .tag = tag, .extra = .{ .lhs = lhs, .rhs = rhs } };
|
||||
const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
|
||||
if (!gop.found_existing) {
|
||||
gop.key_ptr.* = {};
|
||||
gop.value_ptr.* = {};
|
||||
self.constant_items.appendAssumeCapacity(.{
|
||||
.tag = tag,
|
||||
.data = self.addConstantExtraAssumeCapacity(data.bin),
|
||||
.data = self.addConstantExtraAssumeCapacity(data.extra),
|
||||
});
|
||||
if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(switch (tag) {
|
||||
.add => &llvm.Value.constAdd,
|
||||
@ -9121,6 +9311,61 @@ fn binConstAssumeCapacity(
|
||||
return @enumFromInt(gop.index);
|
||||
}
|
||||
|
||||
fn asmConstAssumeCapacity(
|
||||
self: *Builder,
|
||||
ty: Type,
|
||||
info: Constant.Asm.Info,
|
||||
assembly: String,
|
||||
constraints: String,
|
||||
) Constant {
|
||||
const Key = struct { tag: Constant.Tag, extra: Constant.Asm };
|
||||
const Adapter = struct {
|
||||
builder: *const Builder,
|
||||
pub fn hash(_: @This(), key: Key) u32 {
|
||||
return @truncate(std.hash.Wyhash.hash(
|
||||
std.hash.uint32(@intFromEnum(key.tag)),
|
||||
std.mem.asBytes(&key.extra),
|
||||
));
|
||||
}
|
||||
pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
|
||||
if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
|
||||
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
|
||||
const rhs_extra = ctx.builder.constantExtraData(Constant.Asm, rhs_data);
|
||||
return std.meta.eql(lhs_key.extra, rhs_extra);
|
||||
}
|
||||
};
|
||||
|
||||
const data = Key{
|
||||
.tag = @enumFromInt(@intFromEnum(Constant.Tag.@"asm") + @as(u4, @bitCast(info))),
|
||||
.extra = .{ .type = ty, .assembly = assembly, .constraints = constraints },
|
||||
};
|
||||
const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
|
||||
if (!gop.found_existing) {
|
||||
gop.key_ptr.* = {};
|
||||
gop.value_ptr.* = {};
|
||||
self.constant_items.appendAssumeCapacity(.{
|
||||
.tag = data.tag,
|
||||
.data = self.addConstantExtraAssumeCapacity(data.extra),
|
||||
});
|
||||
if (self.useLibLlvm()) {
|
||||
const assembly_slice = assembly.slice(self).?;
|
||||
const constraints_slice = constraints.slice(self).?;
|
||||
self.llvm.constants.appendAssumeCapacity(llvm.getInlineAsm(
|
||||
ty.toLlvm(self),
|
||||
assembly_slice.ptr,
|
||||
assembly_slice.len,
|
||||
constraints_slice.ptr,
|
||||
constraints_slice.len,
|
||||
llvm.Bool.fromBool(info.sideeffect),
|
||||
llvm.Bool.fromBool(info.alignstack),
|
||||
if (info.inteldialect) .Intel else .ATT,
|
||||
llvm.Bool.fromBool(info.unwind),
|
||||
));
|
||||
}
|
||||
}
|
||||
return @enumFromInt(gop.index);
|
||||
}
|
||||
|
||||
fn ensureUnusedConstantCapacity(
|
||||
self: *Builder,
|
||||
count: usize,
|
||||
@ -9211,7 +9456,7 @@ fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.
|
||||
const value = @field(extra, field.name);
|
||||
self.constant_extra.appendAssumeCapacity(switch (field.type) {
|
||||
u32 => value,
|
||||
Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
|
||||
String, Type, Constant, Function.Index, Function.Block.Index => @intFromEnum(value),
|
||||
Constant.GetElementPtr.Info => @bitCast(value),
|
||||
else => @compileError("bad field type: " ++ @typeName(field.type)),
|
||||
});
|
||||
@ -9250,7 +9495,7 @@ fn constantExtraDataTrail(
|
||||
inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, value|
|
||||
@field(result, field.name) = switch (field.type) {
|
||||
u32 => value,
|
||||
Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
|
||||
String, Type, Constant, Function.Index, Function.Block.Index => @enumFromInt(value),
|
||||
Constant.GetElementPtr.Info => @bitCast(value),
|
||||
else => @compileError("bad field type: " ++ @typeName(field.type)),
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user