Commit 533111e849
Changed files (2)
src
codegen
src/codegen/llvm/Builder.zig
@@ -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)),
};
src/codegen/llvm.zig
@@ -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;