diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 43a4b9886662..87ed52c31b77 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1034,15 +1034,11 @@ pub const Object = struct { fn genModuleLevelAssembly(object: *Object) !void { const mod = object.module; - if (mod.global_assembly.count() == 0) return; - var buffer = std.ArrayList(u8).init(mod.gpa); - defer buffer.deinit(); - var it = mod.global_assembly.iterator(); - while (it.next()) |kv| { - try buffer.appendSlice(kv.value_ptr.*); - try buffer.append('\n'); - } - object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1); + + const writer = object.builder.setModuleAsm(); + var it = mod.global_assembly.valueIterator(); + while (it.next()) |assembly| try writer.print("{s}\n", .{assembly.*}); + try object.builder.finishModuleAsm(); } fn resolveExportExternCollisions(object: *Object) !void { diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig index 08ada8a81bb1..1b25e285ff06 100644 --- a/src/codegen/llvm/Builder.zig +++ b/src/codegen/llvm/Builder.zig @@ -18,6 +18,7 @@ llvm: if (build_options.have_llvm) struct { source_filename: String, data_layout: String, target_triple: String, +module_asm: std.ArrayListUnmanaged(u8), string_map: std.AutoArrayHashMapUnmanaged(void, void), string_indices: std.ArrayListUnmanaged(u32), @@ -95,18 +96,12 @@ pub const String = enum(u32) { assert(data.string != .none); const sentinel_slice = data.string.slice(data.builder) orelse return writer.print("{d}", .{@intFromEnum(data.string)}); - const full_slice = sentinel_slice[0 .. sentinel_slice.len + comptime @intFromBool( + try printEscapedString(sentinel_slice[0 .. sentinel_slice.len + comptime @intFromBool( std.mem.indexOfScalar(u8, fmt_str, '@') != null, - )]; - const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or - !isValidIdentifier(full_slice); - if (need_quotes) try writer.writeByte('"'); - for (full_slice) |character| switch (character) { - '\\' => try writer.writeAll("\\\\"), - ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(character), - else => try writer.print("\\{X:0>2}", .{character}), - }; - if (need_quotes) try writer.writeByte('"'); + )], if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_| + .always_quote + else + .quote_unless_valid_identifier, writer); } pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) { return .{ .data = .{ .string = self, .builder = builder } }; @@ -3812,7 +3807,7 @@ pub const WipFunction = struct { @intFromEnum(addr_space), instruction.llvmName(self), ); - if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a)); + if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes)); self.llvm.instructions.appendAssumeCapacity(llvm_instruction); } return instruction.toValue(); @@ -3868,7 +3863,7 @@ pub const WipFunction = struct { instruction.llvmName(self), ); if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering))); - if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a)); + if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes)); self.llvm.instructions.appendAssumeCapacity(llvm_instruction); } return instruction.toValue(); @@ -3922,7 +3917,7 @@ pub const WipFunction = struct { .@"volatile" => llvm_instruction.setVolatile(.True), } if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering))); - if (alignment.toByteUnits()) |a| llvm_instruction.setAlignment(@intCast(a)); + if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes)); self.llvm.instructions.appendAssumeCapacity(llvm_instruction); } return instruction; @@ -6090,6 +6085,7 @@ pub fn init(options: Options) InitError!Builder { .source_filename = .none, .data_layout = .none, .target_triple = .none, + .module_asm = .{}, .string_map = .{}, .string_indices = .{}, @@ -6207,6 +6203,8 @@ pub fn init(options: Options) InitError!Builder { } pub fn deinit(self: *Builder) void { + self.module_asm.deinit(self.gpa); + self.string_map.deinit(self.gpa); self.string_indices.deinit(self.gpa); self.string_bytes.deinit(self.gpa); @@ -6440,6 +6438,22 @@ pub fn initializeLLVMTarget(self: *const Builder, arch: std.Target.Cpu.Arch) voi } } +pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { + self.module_asm.clearRetainingCapacity(); + return self.appendModuleAsm(); +} + +pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { + return self.module_asm.writer(self.gpa); +} + +pub fn finishModuleAsm(self: *Builder) Allocator.Error!void { + if (self.module_asm.getLastOrNull()) |last| if (last != '\n') + try self.module_asm.append(self.gpa, '\n'); + if (self.useLibLlvm()) + self.llvm.module.?.setModuleInlineAsm(self.module_asm.items.ptr, self.module_asm.items.len); +} + pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String { try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len + 1); try self.string_indices.ensureUnusedCapacity(self.gpa, 1); @@ -7185,548 +7199,605 @@ pub fn printUnbuffered( self: *Builder, writer: anytype, ) (@TypeOf(writer).Error || Allocator.Error)!void { - if (self.source_filename != .none) try writer.print( - \\; ModuleID = '{s}' - \\source_filename = {"} - \\ - , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) }); - if (self.data_layout != .none) try writer.print( - \\target datalayout = {"} - \\ - , .{self.data_layout.fmt(self)}); - if (self.target_triple != .none) try writer.print( - \\target triple = {"} - \\ - , .{self.target_triple.fmt(self)}); - try writer.writeByte('\n'); - - for (self.types.keys(), self.types.values()) |id, ty| try writer.print( - \\%{} = type {} - \\ - , .{ id.fmt(self), ty.fmt(self) }); - try writer.writeByte('\n'); - - for (self.variables.items) |variable| { - if (variable.global.getReplacement(self) != .none) continue; - const global = variable.global.ptrConst(self); - try writer.print( - \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,} + var need_newline = false; + + if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) { + if (need_newline) try writer.writeByte('\n'); + if (self.source_filename != .none) try writer.print( + \\; ModuleID = '{s}' + \\source_filename = {"} \\ - , .{ - variable.global.fmt(self), - global.linkage, - global.preemption, - global.visibility, - global.dll_storage_class, - variable.thread_local, - global.unnamed_addr, - global.addr_space, - global.externally_initialized, - @tagName(variable.mutability), - global.type.fmt(self), - variable.init.fmt(self), - variable.alignment, - }); + , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) }); + if (self.data_layout != .none) try writer.print( + \\target datalayout = {"} + \\ + , .{self.data_layout.fmt(self)}); + if (self.target_triple != .none) try writer.print( + \\target triple = {"} + \\ + , .{self.target_triple.fmt(self)}); + need_newline = true; } - try writer.writeByte('\n'); - var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .{}; - defer attribute_groups.deinit(self.gpa); - for (0.., self.functions.items) |function_i, function| { - const function_index: Function.Index = @enumFromInt(function_i); - if (function.global.getReplacement(self) != .none) continue; - const global = function.global.ptrConst(self); - const params_len = global.type.functionParameters(self).len; - const function_attributes = function.attributes.func(self); - if (function_attributes != .none) try writer.print( - \\; Function Attrs:{} + if (self.module_asm.items.len > 0) { + if (need_newline) try writer.writeByte('\n'); + var line_it = std.mem.tokenizeScalar(u8, self.module_asm.items, '\n'); + while (line_it.next()) |line| { + try writer.writeAll("module asm "); + try printEscapedString(line, .always_quote, writer); + try writer.writeByte('\n'); + } + need_newline = true; + } + + if (self.types.count() > 0) { + if (need_newline) try writer.writeByte('\n'); + for (self.types.keys(), self.types.values()) |id, ty| try writer.print( + \\%{} = type {} \\ - , .{function_attributes.fmt(self)}); - try writer.print( - \\{s}{}{}{}{}{}{"} {} {}( - , .{ - if (function.instructions.len > 0) "define" else "declare", - global.linkage, - global.preemption, - global.visibility, - global.dll_storage_class, - function.call_conv, - function.attributes.ret(self).fmt(self), - global.type.functionReturn(self).fmt(self), - function.global.fmt(self), - }); - for (0..params_len) |arg| { - if (arg > 0) try writer.writeAll(", "); + , .{ id.fmt(self), ty.fmt(self) }); + need_newline = true; + } + + if (self.variables.items.len > 0) { + if (need_newline) try writer.writeByte('\n'); + for (self.variables.items) |variable| { + if (variable.global.getReplacement(self) != .none) continue; + const global = variable.global.ptrConst(self); try writer.print( - \\{%}{"} + \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,} + \\ , .{ - global.type.functionParameters(self)[arg].fmt(self), - function.attributes.param(arg, self).fmt(self), + variable.global.fmt(self), + global.linkage, + global.preemption, + global.visibility, + global.dll_storage_class, + variable.thread_local, + global.unnamed_addr, + global.addr_space, + global.externally_initialized, + @tagName(variable.mutability), + global.type.fmt(self), + variable.init.fmt(self), + variable.alignment, }); - if (function.instructions.len > 0) - try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)}); - } - switch (global.type.functionKind(self)) { - .normal => {}, - .vararg => { - if (params_len > 0) try writer.writeAll(", "); - try writer.writeAll("..."); - }, } - try writer.print("){}{}", .{ global.unnamed_addr, global.addr_space }); - if (function_attributes != .none) try writer.print(" #{d}", .{ - (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index, - }); - try writer.print("{}", .{function.alignment}); - if (function.instructions.len > 0) { - var block_incoming_len: u32 = undefined; - try writer.writeAll(" {\n"); - for (params_len..function.instructions.len) |instruction_i| { - const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i); - const instruction = function.instructions.get(@intFromEnum(instruction_index)); - switch (instruction.tag) { - .add, - .@"add nsw", - .@"add nuw", - .@"add nuw nsw", - .@"and", - .ashr, - .@"ashr exact", - .fadd, - .@"fadd fast", - .@"fcmp false", - .@"fcmp fast false", - .@"fcmp fast oeq", - .@"fcmp fast oge", - .@"fcmp fast ogt", - .@"fcmp fast ole", - .@"fcmp fast olt", - .@"fcmp fast one", - .@"fcmp fast ord", - .@"fcmp fast true", - .@"fcmp fast ueq", - .@"fcmp fast uge", - .@"fcmp fast ugt", - .@"fcmp fast ule", - .@"fcmp fast ult", - .@"fcmp fast une", - .@"fcmp fast uno", - .@"fcmp oeq", - .@"fcmp oge", - .@"fcmp ogt", - .@"fcmp ole", - .@"fcmp olt", - .@"fcmp one", - .@"fcmp ord", - .@"fcmp true", - .@"fcmp ueq", - .@"fcmp uge", - .@"fcmp ugt", - .@"fcmp ule", - .@"fcmp ult", - .@"fcmp une", - .@"fcmp uno", - .fdiv, - .@"fdiv fast", - .fmul, - .@"fmul fast", - .frem, - .@"frem fast", - .fsub, - .@"fsub fast", - .@"icmp eq", - .@"icmp ne", - .@"icmp sge", - .@"icmp sgt", - .@"icmp sle", - .@"icmp slt", - .@"icmp uge", - .@"icmp ugt", - .@"icmp ule", - .@"icmp ult", - .lshr, - .@"lshr exact", - .mul, - .@"mul nsw", - .@"mul nuw", - .@"mul nuw nsw", - .@"or", - .sdiv, - .@"sdiv exact", - .srem, - .shl, - .@"shl nsw", - .@"shl nuw", - .@"shl nuw nsw", - .sub, - .@"sub nsw", - .@"sub nuw", - .@"sub nuw nsw", - .udiv, - .@"udiv exact", - .urem, - .xor, - => |tag| { - const extra = function.extraData(Function.Instruction.Binary, instruction.data); - try writer.print(" %{} = {s} {%}, {}\n", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.lhs.fmt(function_index, self), - extra.rhs.fmt(function_index, self), - }); - }, - .addrspacecast, - .bitcast, - .fpext, - .fptosi, - .fptoui, - .fptrunc, - .inttoptr, - .ptrtoint, - .sext, - .sitofp, - .trunc, - .uitofp, - .zext, - => |tag| { - const extra = function.extraData(Function.Instruction.Cast, instruction.data); - try writer.print(" %{} = {s} {%} to {%}\n", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.val.fmt(function_index, self), - extra.type.fmt(self), - }); - }, - .alloca, - .@"alloca inalloca", - => |tag| { - const extra = function.extraData(Function.Instruction.Alloca, instruction.data); - try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.type.fmt(self), - extra.len.fmt(function_index, self), - extra.info.alignment, - extra.info.addr_space, - }); - }, - .arg => unreachable, - .block => { - block_incoming_len = instruction.data; - const name = instruction_index.name(&function); - if (@intFromEnum(instruction_index) > params_len) try writer.writeByte('\n'); - try writer.print("{}:\n", .{name.fmt(self)}); - }, - .br => |tag| { - const target: Function.Block.Index = @enumFromInt(instruction.data); - try writer.print(" {s} {%}\n", .{ - @tagName(tag), target.toInst(&function).fmt(function_index, self), - }); - }, - .br_cond => { - const extra = function.extraData(Function.Instruction.BrCond, instruction.data); - try writer.print(" br {%}, {%}, {%}\n", .{ - extra.cond.fmt(function_index, self), - extra.then.toInst(&function).fmt(function_index, self), - extra.@"else".toInst(&function).fmt(function_index, self), - }); - }, - .call, - .@"call fast", - .@"musttail call", - .@"musttail call fast", - .@"notail call", - .@"notail call fast", - .@"tail call", - .@"tail call fast", - => |tag| { - var extra = - function.extraDataTrail(Function.Instruction.Call, instruction.data); - const args = extra.trail.next(extra.data.args_len, Value, &function); - try writer.writeAll(" "); - const ret_ty = extra.data.ty.functionReturn(self); - switch (ret_ty) { - .void => {}, - else => try writer.print("%{} = ", .{ + need_newline = true; + } + + var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .{}; + defer attribute_groups.deinit(self.gpa); + + if (self.functions.items.len > 0) { + if (need_newline) try writer.writeByte('\n'); + for (0.., self.functions.items) |function_i, function| { + if (function_i > 0) try writer.writeByte('\n'); + const function_index: Function.Index = @enumFromInt(function_i); + if (function.global.getReplacement(self) != .none) continue; + const global = function.global.ptrConst(self); + const params_len = global.type.functionParameters(self).len; + const function_attributes = function.attributes.func(self); + if (function_attributes != .none) try writer.print( + \\; Function Attrs:{} + \\ + , .{function_attributes.fmt(self)}); + try writer.print( + \\{s}{}{}{}{}{}{"} {} {}( + , .{ + if (function.instructions.len > 0) "define" else "declare", + global.linkage, + global.preemption, + global.visibility, + global.dll_storage_class, + function.call_conv, + function.attributes.ret(self).fmt(self), + global.type.functionReturn(self).fmt(self), + function.global.fmt(self), + }); + for (0..params_len) |arg| { + if (arg > 0) try writer.writeAll(", "); + try writer.print( + \\{%}{"} + , .{ + global.type.functionParameters(self)[arg].fmt(self), + function.attributes.param(arg, self).fmt(self), + }); + if (function.instructions.len > 0) + try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)}); + } + switch (global.type.functionKind(self)) { + .normal => {}, + .vararg => { + if (params_len > 0) try writer.writeAll(", "); + try writer.writeAll("..."); + }, + } + try writer.print("){}{}", .{ global.unnamed_addr, global.addr_space }); + if (function_attributes != .none) try writer.print(" #{d}", .{ + (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index, + }); + try writer.print("{}", .{function.alignment}); + if (function.instructions.len > 0) { + var block_incoming_len: u32 = undefined; + try writer.writeAll(" {\n"); + for (params_len..function.instructions.len) |instruction_i| { + const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i); + const instruction = function.instructions.get(@intFromEnum(instruction_index)); + switch (instruction.tag) { + .add, + .@"add nsw", + .@"add nuw", + .@"add nuw nsw", + .@"and", + .ashr, + .@"ashr exact", + .fadd, + .@"fadd fast", + .@"fcmp false", + .@"fcmp fast false", + .@"fcmp fast oeq", + .@"fcmp fast oge", + .@"fcmp fast ogt", + .@"fcmp fast ole", + .@"fcmp fast olt", + .@"fcmp fast one", + .@"fcmp fast ord", + .@"fcmp fast true", + .@"fcmp fast ueq", + .@"fcmp fast uge", + .@"fcmp fast ugt", + .@"fcmp fast ule", + .@"fcmp fast ult", + .@"fcmp fast une", + .@"fcmp fast uno", + .@"fcmp oeq", + .@"fcmp oge", + .@"fcmp ogt", + .@"fcmp ole", + .@"fcmp olt", + .@"fcmp one", + .@"fcmp ord", + .@"fcmp true", + .@"fcmp ueq", + .@"fcmp uge", + .@"fcmp ugt", + .@"fcmp ule", + .@"fcmp ult", + .@"fcmp une", + .@"fcmp uno", + .fdiv, + .@"fdiv fast", + .fmul, + .@"fmul fast", + .frem, + .@"frem fast", + .fsub, + .@"fsub fast", + .@"icmp eq", + .@"icmp ne", + .@"icmp sge", + .@"icmp sgt", + .@"icmp sle", + .@"icmp slt", + .@"icmp uge", + .@"icmp ugt", + .@"icmp ule", + .@"icmp ult", + .lshr, + .@"lshr exact", + .mul, + .@"mul nsw", + .@"mul nuw", + .@"mul nuw nsw", + .@"or", + .sdiv, + .@"sdiv exact", + .srem, + .shl, + .@"shl nsw", + .@"shl nuw", + .@"shl nuw nsw", + .sub, + .@"sub nsw", + .@"sub nuw", + .@"sub nuw nsw", + .udiv, + .@"udiv exact", + .urem, + .xor, + => |tag| { + const extra = + function.extraData(Function.Instruction.Binary, instruction.data); + try writer.print(" %{} = {s} {%}, {}\n", .{ instruction_index.name(&function).fmt(self), - }), - .none => unreachable, - } - try writer.print("{s}{}{}{} {%} {}(", .{ - @tagName(tag), - extra.data.info.call_conv, - extra.data.attributes.ret(self).fmt(self), - extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self), - switch (extra.data.ty.functionKind(self)) { - .normal => ret_ty, - .vararg => extra.data.ty, - }.fmt(self), - extra.data.callee.fmt(function_index, self), - }); - for (0.., args) |arg_index, arg| { - if (arg_index > 0) try writer.writeAll(", "); - try writer.print("{%}{} {}", .{ - arg.typeOf(function_index, self).fmt(self), - extra.data.attributes.param(arg_index, self).fmt(self), - arg.fmt(function_index, self), + @tagName(tag), + extra.lhs.fmt(function_index, self), + extra.rhs.fmt(function_index, 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 = - function.extraData(Function.Instruction.ExtractElement, instruction.data); - try writer.print(" %{} = {s} {%}, {%}\n", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.val.fmt(function_index, self), - extra.index.fmt(function_index, self), - }); - }, - .extractvalue => |tag| { - var extra = - function.extraDataTrail(Function.Instruction.ExtractValue, instruction.data); - const indices = extra.trail.next(extra.data.indices_len, u32, &function); - try writer.print(" %{} = {s} {%}", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.data.val.fmt(function_index, self), - }); - for (indices) |index| try writer.print(", {d}", .{index}); - try writer.writeByte('\n'); - }, - .fence => |tag| { - const info: MemoryAccessInfo = @bitCast(instruction.data); - try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering }); - }, - .fneg, - .@"fneg fast", - .ret, - => |tag| { - const val: Value = @enumFromInt(instruction.data); - try writer.print(" {s} {%}\n", .{ - @tagName(tag), - val.fmt(function_index, self), - }); - }, - .getelementptr, - .@"getelementptr inbounds", - => |tag| { - var extra = function.extraDataTrail( - Function.Instruction.GetElementPtr, - instruction.data, - ); - const indices = extra.trail.next(extra.data.indices_len, Value, &function); - try writer.print(" %{} = {s} {%}, {%}", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.data.type.fmt(self), - extra.data.base.fmt(function_index, self), - }); - for (indices) |index| try writer.print(", {%}", .{ - index.fmt(function_index, self), - }); - try writer.writeByte('\n'); - }, - .insertelement => |tag| { - const extra = - function.extraData(Function.Instruction.InsertElement, instruction.data); - try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.val.fmt(function_index, self), - extra.elem.fmt(function_index, self), - extra.index.fmt(function_index, self), - }); - }, - .insertvalue => |tag| { - var extra = - function.extraDataTrail(Function.Instruction.InsertValue, instruction.data); - const indices = extra.trail.next(extra.data.indices_len, u32, &function); - try writer.print(" %{} = {s} {%}, {%}", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.data.val.fmt(function_index, self), - extra.data.elem.fmt(function_index, self), - }); - for (indices) |index| try writer.print(", {d}", .{index}); - try writer.writeByte('\n'); - }, - .@"llvm.maxnum.", - .@"llvm.minnum.", - .@"llvm.sadd.sat.", - .@"llvm.smax.", - .@"llvm.smin.", - .@"llvm.smul.fix.sat.", - .@"llvm.sshl.sat.", - .@"llvm.ssub.sat.", - .@"llvm.uadd.sat.", - .@"llvm.umax.", - .@"llvm.umin.", - .@"llvm.umul.fix.sat.", - .@"llvm.ushl.sat.", - .@"llvm.usub.sat.", - => |tag| { - const extra = function.extraData(Function.Instruction.Binary, instruction.data); - const ty = instruction_index.typeOf(function_index, self); - 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, - .@"load atomic", - .@"load atomic volatile", - .@"load volatile", - => |tag| { - const extra = function.extraData(Function.Instruction.Load, instruction.data); - try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.type.fmt(self), - extra.ptr.fmt(function_index, self), - extra.info.scope, - extra.info.ordering, - extra.info.alignment, - }); - }, - .phi, - .@"phi fast", - => |tag| { - var extra = function.extraDataTrail(Function.Instruction.Phi, instruction.data); - const vals = extra.trail.next(block_incoming_len, Value, &function); - const blocks = - extra.trail.next(block_incoming_len, Function.Block.Index, &function); - try writer.print(" %{} = {s} {%} ", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - vals[0].typeOf(function_index, self).fmt(self), - }); - for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| { - if (incoming_index > 0) try writer.writeAll(", "); - try writer.print("[ {}, {} ]", .{ - incoming_val.fmt(function_index, self), - incoming_block.toInst(&function).fmt(function_index, self), + }, + .addrspacecast, + .bitcast, + .fpext, + .fptosi, + .fptoui, + .fptrunc, + .inttoptr, + .ptrtoint, + .sext, + .sitofp, + .trunc, + .uitofp, + .zext, + => |tag| { + const extra = + function.extraData(Function.Instruction.Cast, instruction.data); + try writer.print(" %{} = {s} {%} to {%}\n", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.val.fmt(function_index, self), + extra.type.fmt(self), }); - } - try writer.writeByte('\n'); - }, - .@"ret void", - .@"unreachable", - => |tag| try writer.print(" {s}\n", .{@tagName(tag)}), - .select, - .@"select fast", - => |tag| { - const extra = function.extraData(Function.Instruction.Select, instruction.data); - try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.cond.fmt(function_index, self), - extra.lhs.fmt(function_index, self), - extra.rhs.fmt(function_index, self), - }); - }, - .shufflevector => |tag| { - const extra = - function.extraData(Function.Instruction.ShuffleVector, instruction.data); - try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.lhs.fmt(function_index, self), - extra.rhs.fmt(function_index, self), - extra.mask.fmt(function_index, self), - }); - }, - .store, - .@"store atomic", - .@"store atomic volatile", - .@"store volatile", - => |tag| { - const extra = function.extraData(Function.Instruction.Store, instruction.data); - try writer.print(" {s} {%}, {%}{}{}{,}\n", .{ - @tagName(tag), - extra.val.fmt(function_index, self), - extra.ptr.fmt(function_index, self), - extra.info.scope, - extra.info.ordering, - extra.info.alignment, - }); - }, - .@"switch" => |tag| { - var extra = - function.extraDataTrail(Function.Instruction.Switch, instruction.data); - 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} {%}, {%} [\n", .{ - @tagName(tag), - extra.data.val.fmt(function_index, self), - extra.data.default.toInst(&function).fmt(function_index, self), - }); - for (vals, blocks) |case_val, case_block| try writer.print(" {%}, {%}\n", .{ - case_val.fmt(self), - case_block.toInst(&function).fmt(function_index, self), - }); - try writer.writeAll(" ]\n"); - }, - .unimplemented => |tag| { - const ty: Type = @enumFromInt(instruction.data); - if (true) { + }, + .alloca, + .@"alloca inalloca", + => |tag| { + const extra = + function.extraData(Function.Instruction.Alloca, instruction.data); + try writer.print(" %{} = {s} {%}{,%}{,}{,}\n", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.type.fmt(self), + extra.len.fmt(function_index, self), + extra.info.alignment, + extra.info.addr_space, + }); + }, + .arg => unreachable, + .block => { + block_incoming_len = instruction.data; + const name = instruction_index.name(&function); + if (@intFromEnum(instruction_index) > params_len) + try writer.writeByte('\n'); + try writer.print("{}:\n", .{name.fmt(self)}); + }, + .br => |tag| { + const target: Function.Block.Index = @enumFromInt(instruction.data); + try writer.print(" {s} {%}\n", .{ + @tagName(tag), target.toInst(&function).fmt(function_index, self), + }); + }, + .br_cond => { + const extra = + function.extraData(Function.Instruction.BrCond, instruction.data); + try writer.print(" br {%}, {%}, {%}\n", .{ + extra.cond.fmt(function_index, self), + extra.then.toInst(&function).fmt(function_index, self), + extra.@"else".toInst(&function).fmt(function_index, self), + }); + }, + .call, + .@"call fast", + .@"musttail call", + .@"musttail call fast", + .@"notail call", + .@"notail call fast", + .@"tail call", + .@"tail call fast", + => |tag| { + var extra = + function.extraDataTrail(Function.Instruction.Call, instruction.data); + const args = extra.trail.next(extra.data.args_len, Value, &function); try writer.writeAll(" "); - switch (ty) { - .none, .void => {}, + const ret_ty = extra.data.ty.functionReturn(self); + switch (ret_ty) { + .void => {}, else => try writer.print("%{} = ", .{ instruction_index.name(&function).fmt(self), }), + .none => unreachable, + } + try writer.print("{s}{}{}{} {%} {}(", .{ + @tagName(tag), + extra.data.info.call_conv, + extra.data.attributes.ret(self).fmt(self), + extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self), + switch (extra.data.ty.functionKind(self)) { + .normal => ret_ty, + .vararg => extra.data.ty, + }.fmt(self), + extra.data.callee.fmt(function_index, self), + }); + for (0.., args) |arg_index, arg| { + if (arg_index > 0) try writer.writeAll(", "); + try writer.print("{%}{} {}", .{ + arg.typeOf(function_index, self).fmt(self), + extra.data.attributes.param(arg_index, self).fmt(self), + arg.fmt(function_index, self), + }); } - try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) }); - } else switch (ty) { - .none, .void => {}, - else => try writer.print(" %{} = load {%}, ptr undef\n", .{ + 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, + }); + try writer.writeByte('\n'); + }, + .extractelement => |tag| { + const extra = function.extraData( + Function.Instruction.ExtractElement, + instruction.data, + ); + try writer.print(" %{} = {s} {%}, {%}\n", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.val.fmt(function_index, self), + extra.index.fmt(function_index, self), + }); + }, + .extractvalue => |tag| { + var extra = function.extraDataTrail( + Function.Instruction.ExtractValue, + instruction.data, + ); + const indices = extra.trail.next(extra.data.indices_len, u32, &function); + try writer.print(" %{} = {s} {%}", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.data.val.fmt(function_index, self), + }); + for (indices) |index| try writer.print(", {d}", .{index}); + try writer.writeByte('\n'); + }, + .fence => |tag| { + const info: MemoryAccessInfo = @bitCast(instruction.data); + try writer.print(" {s}{}{}", .{ @tagName(tag), info.scope, info.ordering }); + }, + .fneg, + .@"fneg fast", + .ret, + => |tag| { + const val: Value = @enumFromInt(instruction.data); + try writer.print(" {s} {%}\n", .{ + @tagName(tag), + val.fmt(function_index, self), + }); + }, + .getelementptr, + .@"getelementptr inbounds", + => |tag| { + var extra = function.extraDataTrail( + Function.Instruction.GetElementPtr, + instruction.data, + ); + const indices = extra.trail.next(extra.data.indices_len, Value, &function); + try writer.print(" %{} = {s} {%}, {%}", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.data.type.fmt(self), + extra.data.base.fmt(function_index, self), + }); + for (indices) |index| try writer.print(", {%}", .{ + index.fmt(function_index, self), + }); + try writer.writeByte('\n'); + }, + .insertelement => |tag| { + const extra = function.extraData( + Function.Instruction.InsertElement, + instruction.data, + ); + try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.val.fmt(function_index, self), + extra.elem.fmt(function_index, self), + extra.index.fmt(function_index, self), + }); + }, + .insertvalue => |tag| { + var extra = function.extraDataTrail( + Function.Instruction.InsertValue, + instruction.data, + ); + const indices = extra.trail.next(extra.data.indices_len, u32, &function); + try writer.print(" %{} = {s} {%}, {%}", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.data.val.fmt(function_index, self), + extra.data.elem.fmt(function_index, self), + }); + for (indices) |index| try writer.print(", {d}", .{index}); + try writer.writeByte('\n'); + }, + .@"llvm.maxnum.", + .@"llvm.minnum.", + .@"llvm.sadd.sat.", + .@"llvm.smax.", + .@"llvm.smin.", + .@"llvm.smul.fix.sat.", + .@"llvm.sshl.sat.", + .@"llvm.ssub.sat.", + .@"llvm.uadd.sat.", + .@"llvm.umax.", + .@"llvm.umin.", + .@"llvm.umul.fix.sat.", + .@"llvm.ushl.sat.", + .@"llvm.usub.sat.", + => |tag| { + const extra = + function.extraData(Function.Instruction.Binary, instruction.data); + const ty = instruction_index.typeOf(function_index, self); + try writer.print(" %{} = call {%} @{s}{m}({%}, {%}{s})\n", .{ instruction_index.name(&function).fmt(self), ty.fmt(self), - }), - } - }, - .va_arg => |tag| { - const extra = function.extraData(Function.Instruction.VaArg, instruction.data); - try writer.print(" %{} = {s} {%}, {%}\n", .{ - instruction_index.name(&function).fmt(self), - @tagName(tag), - extra.list.fmt(function_index, self), - extra.type.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, + .@"load atomic", + .@"load atomic volatile", + .@"load volatile", + => |tag| { + const extra = + function.extraData(Function.Instruction.Load, instruction.data); + try writer.print(" %{} = {s} {%}, {%}{}{}{,}\n", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.type.fmt(self), + extra.ptr.fmt(function_index, self), + extra.info.scope, + extra.info.ordering, + extra.info.alignment, + }); + }, + .phi, + .@"phi fast", + => |tag| { + var extra = + function.extraDataTrail(Function.Instruction.Phi, instruction.data); + const vals = extra.trail.next(block_incoming_len, Value, &function); + const blocks = + extra.trail.next(block_incoming_len, Function.Block.Index, &function); + try writer.print(" %{} = {s} {%} ", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + vals[0].typeOf(function_index, self).fmt(self), + }); + for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| { + if (incoming_index > 0) try writer.writeAll(", "); + try writer.print("[ {}, {} ]", .{ + incoming_val.fmt(function_index, self), + incoming_block.toInst(&function).fmt(function_index, self), + }); + } + try writer.writeByte('\n'); + }, + .@"ret void", + .@"unreachable", + => |tag| try writer.print(" {s}\n", .{@tagName(tag)}), + .select, + .@"select fast", + => |tag| { + const extra = + function.extraData(Function.Instruction.Select, instruction.data); + try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.cond.fmt(function_index, self), + extra.lhs.fmt(function_index, self), + extra.rhs.fmt(function_index, self), + }); + }, + .shufflevector => |tag| { + const extra = function.extraData( + Function.Instruction.ShuffleVector, + instruction.data, + ); + try writer.print(" %{} = {s} {%}, {%}, {%}\n", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.lhs.fmt(function_index, self), + extra.rhs.fmt(function_index, self), + extra.mask.fmt(function_index, self), + }); + }, + .store, + .@"store atomic", + .@"store atomic volatile", + .@"store volatile", + => |tag| { + const extra = + function.extraData(Function.Instruction.Store, instruction.data); + try writer.print(" {s} {%}, {%}{}{}{,}\n", .{ + @tagName(tag), + extra.val.fmt(function_index, self), + extra.ptr.fmt(function_index, self), + extra.info.scope, + extra.info.ordering, + extra.info.alignment, + }); + }, + .@"switch" => |tag| { + var extra = + function.extraDataTrail(Function.Instruction.Switch, instruction.data); + 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} {%}, {%} [\n", .{ + @tagName(tag), + extra.data.val.fmt(function_index, self), + extra.data.default.toInst(&function).fmt(function_index, self), + }); + for (vals, blocks) |case_val, case_block| try writer.print( + " {%}, {%}\n", + .{ + case_val.fmt(self), + case_block.toInst(&function).fmt(function_index, self), + }, + ); + try writer.writeAll(" ]\n"); + }, + .unimplemented => |tag| { + const ty: Type = @enumFromInt(instruction.data); + 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(" %{} = load {%}, ptr undef\n", .{ + instruction_index.name(&function).fmt(self), + ty.fmt(self), + }), + } + }, + .va_arg => |tag| { + const extra = + function.extraData(Function.Instruction.VaArg, instruction.data); + try writer.print(" %{} = {s} {%}, {%}\n", .{ + instruction_index.name(&function).fmt(self), + @tagName(tag), + extra.list.fmt(function_index, self), + extra.type.fmt(self), + }); + }, + } } + try writer.writeByte('}'); } - try writer.writeByte('}'); + try writer.writeByte('\n'); } - try writer.writeAll("\n\n"); + need_newline = true; } - for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group| - try writer.print( - \\attributes #{d} = {{{#"} }} - \\ - , .{ attribute_group_index, attribute_group.fmt(self) }); + if (attribute_groups.count() > 0) { + if (need_newline) try writer.writeByte('\n') else need_newline = true; + for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group| + try writer.print( + \\attributes #{d} = {{{#"} }} + \\ + , .{ attribute_group_index, attribute_group.fmt(self) }); + need_newline = true; + } } pub inline fn useLibLlvm(self: *const Builder) bool { @@ -7736,7 +7807,7 @@ pub inline fn useLibLlvm(self: *const Builder) bool { const NoExtra = struct {}; fn isValidIdentifier(id: []const u8) bool { - for (id, 0..) |character, index| switch (character) { + for (id, 0..) |byte, index| switch (byte) { '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {}, '0'...'9' => if (index == 0) return false, else => return false, @@ -7744,6 +7815,25 @@ fn isValidIdentifier(id: []const u8) bool { return true; } +const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier }; +fn printEscapedString( + slice: []const u8, + quotes: QuoteBehavior, + writer: anytype, +) @TypeOf(writer).Error!void { + const need_quotes = switch (quotes) { + .always_quote => true, + .quote_unless_valid_identifier => !isValidIdentifier(slice), + }; + if (need_quotes) try writer.writeByte('"'); + for (slice) |byte| switch (byte) { + '\\' => try writer.writeAll("\\\\"), + ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(byte), + else => try writer.print("\\{X:0>2}", .{byte}), + }; + if (need_quotes) try writer.writeByte('"'); +} + fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void { if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1); try self.string_map.ensureUnusedCapacity(self.gpa, 1); @@ -9318,6 +9408,8 @@ fn asmConstAssumeCapacity( assembly: String, constraints: String, ) Constant { + assert(ty.functionKind(self) == .normal); + const Key = struct { tag: Constant.Tag, extra: Constant.Asm }; const Adapter = struct { builder: *const Builder, diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 7f0afee2af82..aee9cea384c3 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -540,7 +540,7 @@ pub const Module = opaque { pub const createDIBuilder = ZigLLVMCreateDIBuilder; extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) *DIBuilder; - pub const setModuleInlineAsm2 = LLVMSetModuleInlineAsm2; + pub const setModuleInlineAsm = LLVMSetModuleInlineAsm2; extern fn LLVMSetModuleInlineAsm2(M: *Module, Asm: [*]const u8, Len: usize) void; pub const printModuleToFile = LLVMPrintModuleToFile;