mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
llvm: convert all calls to constInt
This commit is contained in:
parent
65fd401c06
commit
2cb52235b9
3 changed files with 834 additions and 454 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -6,6 +6,7 @@ llvm_module: *llvm.Module,
|
||||||
di_builder: ?*llvm.DIBuilder = null,
|
di_builder: ?*llvm.DIBuilder = null,
|
||||||
llvm_types: std.ArrayListUnmanaged(*llvm.Type) = .{},
|
llvm_types: std.ArrayListUnmanaged(*llvm.Type) = .{},
|
||||||
llvm_globals: std.ArrayListUnmanaged(*llvm.Value) = .{},
|
llvm_globals: std.ArrayListUnmanaged(*llvm.Value) = .{},
|
||||||
|
llvm_constants: std.ArrayListUnmanaged(*llvm.Value) = .{},
|
||||||
|
|
||||||
source_filename: String = .none,
|
source_filename: String = .none,
|
||||||
data_layout: String = .none,
|
data_layout: String = .none,
|
||||||
|
|
@ -29,6 +30,11 @@ aliases: std.ArrayListUnmanaged(Alias) = .{},
|
||||||
objects: std.ArrayListUnmanaged(Object) = .{},
|
objects: std.ArrayListUnmanaged(Object) = .{},
|
||||||
functions: std.ArrayListUnmanaged(Function) = .{},
|
functions: std.ArrayListUnmanaged(Function) = .{},
|
||||||
|
|
||||||
|
constant_map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
|
||||||
|
constant_items: std.MultiArrayList(Constant.Item) = .{},
|
||||||
|
constant_extra: std.ArrayListUnmanaged(u32) = .{},
|
||||||
|
constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb) = .{},
|
||||||
|
|
||||||
pub const String = enum(u32) {
|
pub const String = enum(u32) {
|
||||||
none = std.math.maxInt(u31),
|
none = std.math.maxInt(u31),
|
||||||
empty,
|
empty,
|
||||||
|
|
@ -612,10 +618,6 @@ pub const Global = struct {
|
||||||
builder.llvm_globals.items[index].setValueName2(slice.ptr, slice.len);
|
builder.llvm_globals.items[index].setValueName2(slice.ptr, slice.len);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn deinit(self: *Global, _: Allocator) void {
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Alias = struct {
|
pub const Alias = struct {
|
||||||
|
|
@ -642,7 +644,7 @@ pub const Object = struct {
|
||||||
global: Global.Index,
|
global: Global.Index,
|
||||||
thread_local: ThreadLocal = .default,
|
thread_local: ThreadLocal = .default,
|
||||||
mutability: enum { global, constant } = .global,
|
mutability: enum { global, constant } = .global,
|
||||||
init: void = {},
|
init: Constant = .no_init,
|
||||||
|
|
||||||
pub const Index = enum(u32) {
|
pub const Index = enum(u32) {
|
||||||
_,
|
_,
|
||||||
|
|
@ -664,10 +666,8 @@ pub const Object = struct {
|
||||||
pub const Function = struct {
|
pub const Function = struct {
|
||||||
global: Global.Index,
|
global: Global.Index,
|
||||||
body: ?void = null,
|
body: ?void = null,
|
||||||
|
instructions: std.ArrayListUnmanaged(Instruction) = .{},
|
||||||
fn deinit(self: *Function, _: Allocator) void {
|
blocks: std.ArrayListUnmanaged(Block) = .{},
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const Index = enum(u32) {
|
pub const Index = enum(u32) {
|
||||||
_,
|
_,
|
||||||
|
|
@ -684,6 +684,130 @@ pub const Function = struct {
|
||||||
return self.ptrConst(builder).global.toLlvm(builder);
|
return self.ptrConst(builder).global.toLlvm(builder);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Instruction = struct {
|
||||||
|
tag: Tag,
|
||||||
|
|
||||||
|
pub const Tag = enum {
|
||||||
|
arg,
|
||||||
|
block,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Index = enum(u31) { _ };
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Block = struct {
|
||||||
|
body: std.ArrayListUnmanaged(Instruction.Index) = .{},
|
||||||
|
|
||||||
|
pub const Index = enum(u31) { _ };
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn deinit(self: *Function, gpa: Allocator) void {
|
||||||
|
self.instructions.deinit(gpa);
|
||||||
|
self.blocks.deinit(gpa);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Constant = enum(u32) {
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
none,
|
||||||
|
no_init = 1 << 31,
|
||||||
|
_,
|
||||||
|
|
||||||
|
const first_global: Constant = @enumFromInt(1 << 30);
|
||||||
|
|
||||||
|
pub const Tag = enum(u6) {
|
||||||
|
integer_positive,
|
||||||
|
integer_negative,
|
||||||
|
null,
|
||||||
|
none,
|
||||||
|
structure,
|
||||||
|
array,
|
||||||
|
vector,
|
||||||
|
zeroinitializer,
|
||||||
|
global,
|
||||||
|
undef,
|
||||||
|
poison,
|
||||||
|
blockaddress,
|
||||||
|
dso_local_equivalent,
|
||||||
|
no_cfi,
|
||||||
|
trunc,
|
||||||
|
zext,
|
||||||
|
sext,
|
||||||
|
fptrunc,
|
||||||
|
fpext,
|
||||||
|
fptoui,
|
||||||
|
fptosi,
|
||||||
|
uitofp,
|
||||||
|
sitofp,
|
||||||
|
ptrtoint,
|
||||||
|
inttoptr,
|
||||||
|
bitcast,
|
||||||
|
addrspacecast,
|
||||||
|
getelementptr,
|
||||||
|
icmp,
|
||||||
|
fcmp,
|
||||||
|
extractelement,
|
||||||
|
insertelement,
|
||||||
|
shufflevector,
|
||||||
|
add,
|
||||||
|
sub,
|
||||||
|
mul,
|
||||||
|
shl,
|
||||||
|
lshr,
|
||||||
|
ashr,
|
||||||
|
@"and",
|
||||||
|
@"or",
|
||||||
|
xor,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Item = struct {
|
||||||
|
tag: Tag,
|
||||||
|
data: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Integer = packed struct(u64) {
|
||||||
|
type: Type,
|
||||||
|
limbs_len: u32,
|
||||||
|
|
||||||
|
pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb));
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn unwrap(self: Constant) union(enum) {
|
||||||
|
constant: u30,
|
||||||
|
global: Global.Index,
|
||||||
|
} {
|
||||||
|
return if (@intFromEnum(self) < @intFromEnum(first_global))
|
||||||
|
.{ .constant = @intCast(@intFromEnum(self)) }
|
||||||
|
else
|
||||||
|
.{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toLlvm(self: Constant, builder: *const Builder) *llvm.Value {
|
||||||
|
assert(builder.useLibLlvm());
|
||||||
|
return switch (self.unwrap()) {
|
||||||
|
.constant => |constant| builder.llvm_constants.items[constant],
|
||||||
|
.global => |global| global.toLlvm(builder),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Value = enum(u32) {
|
||||||
|
_,
|
||||||
|
|
||||||
|
const first_constant: Value = @enumFromInt(1 << 31);
|
||||||
|
|
||||||
|
pub fn unwrap(self: Value) union(enum) {
|
||||||
|
instruction: Function.Instruction.Index,
|
||||||
|
constant: Constant,
|
||||||
|
} {
|
||||||
|
return if (@intFromEnum(self) < @intFromEnum(first_constant))
|
||||||
|
.{ .instruction = @intFromEnum(self) }
|
||||||
|
else
|
||||||
|
.{ .constant = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_constant)) };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(self: *Builder) Allocator.Error!void {
|
pub fn init(self: *Builder) Allocator.Error!void {
|
||||||
|
|
@ -711,11 +835,15 @@ pub fn init(self: *Builder) Allocator.Error!void {
|
||||||
inline for (.{0}) |addr_space|
|
inline for (.{0}) |addr_space|
|
||||||
assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
|
assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(try self.intConst(.i1, 0) == .false);
|
||||||
|
assert(try self.intConst(.i1, 1) == .true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Builder) void {
|
pub fn deinit(self: *Builder) void {
|
||||||
self.llvm_types.deinit(self.gpa);
|
self.llvm_types.deinit(self.gpa);
|
||||||
self.llvm_globals.deinit(self.gpa);
|
self.llvm_globals.deinit(self.gpa);
|
||||||
|
self.llvm_constants.deinit(self.gpa);
|
||||||
|
|
||||||
self.string_map.deinit(self.gpa);
|
self.string_map.deinit(self.gpa);
|
||||||
self.string_bytes.deinit(self.gpa);
|
self.string_bytes.deinit(self.gpa);
|
||||||
|
|
@ -731,11 +859,210 @@ pub fn deinit(self: *Builder) void {
|
||||||
self.next_unique_global_id.deinit(self.gpa);
|
self.next_unique_global_id.deinit(self.gpa);
|
||||||
self.aliases.deinit(self.gpa);
|
self.aliases.deinit(self.gpa);
|
||||||
self.objects.deinit(self.gpa);
|
self.objects.deinit(self.gpa);
|
||||||
|
for (self.functions.items) |*function| function.deinit(self.gpa);
|
||||||
self.functions.deinit(self.gpa);
|
self.functions.deinit(self.gpa);
|
||||||
|
|
||||||
|
self.constant_map.deinit(self.gpa);
|
||||||
|
self.constant_items.deinit(self.gpa);
|
||||||
|
self.constant_extra.deinit(self.gpa);
|
||||||
|
self.constant_limbs.deinit(self.gpa);
|
||||||
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn initializeLLVMTarget(self: *const Builder, arch: std.Target.Cpu.Arch) void {
|
||||||
|
if (!self.useLibLlvm()) return;
|
||||||
|
switch (arch) {
|
||||||
|
.aarch64, .aarch64_be, .aarch64_32 => {
|
||||||
|
llvm.LLVMInitializeAArch64Target();
|
||||||
|
llvm.LLVMInitializeAArch64TargetInfo();
|
||||||
|
llvm.LLVMInitializeAArch64TargetMC();
|
||||||
|
llvm.LLVMInitializeAArch64AsmPrinter();
|
||||||
|
llvm.LLVMInitializeAArch64AsmParser();
|
||||||
|
},
|
||||||
|
.amdgcn => {
|
||||||
|
llvm.LLVMInitializeAMDGPUTarget();
|
||||||
|
llvm.LLVMInitializeAMDGPUTargetInfo();
|
||||||
|
llvm.LLVMInitializeAMDGPUTargetMC();
|
||||||
|
llvm.LLVMInitializeAMDGPUAsmPrinter();
|
||||||
|
llvm.LLVMInitializeAMDGPUAsmParser();
|
||||||
|
},
|
||||||
|
.thumb, .thumbeb, .arm, .armeb => {
|
||||||
|
llvm.LLVMInitializeARMTarget();
|
||||||
|
llvm.LLVMInitializeARMTargetInfo();
|
||||||
|
llvm.LLVMInitializeARMTargetMC();
|
||||||
|
llvm.LLVMInitializeARMAsmPrinter();
|
||||||
|
llvm.LLVMInitializeARMAsmParser();
|
||||||
|
},
|
||||||
|
.avr => {
|
||||||
|
llvm.LLVMInitializeAVRTarget();
|
||||||
|
llvm.LLVMInitializeAVRTargetInfo();
|
||||||
|
llvm.LLVMInitializeAVRTargetMC();
|
||||||
|
llvm.LLVMInitializeAVRAsmPrinter();
|
||||||
|
llvm.LLVMInitializeAVRAsmParser();
|
||||||
|
},
|
||||||
|
.bpfel, .bpfeb => {
|
||||||
|
llvm.LLVMInitializeBPFTarget();
|
||||||
|
llvm.LLVMInitializeBPFTargetInfo();
|
||||||
|
llvm.LLVMInitializeBPFTargetMC();
|
||||||
|
llvm.LLVMInitializeBPFAsmPrinter();
|
||||||
|
llvm.LLVMInitializeBPFAsmParser();
|
||||||
|
},
|
||||||
|
.hexagon => {
|
||||||
|
llvm.LLVMInitializeHexagonTarget();
|
||||||
|
llvm.LLVMInitializeHexagonTargetInfo();
|
||||||
|
llvm.LLVMInitializeHexagonTargetMC();
|
||||||
|
llvm.LLVMInitializeHexagonAsmPrinter();
|
||||||
|
llvm.LLVMInitializeHexagonAsmParser();
|
||||||
|
},
|
||||||
|
.lanai => {
|
||||||
|
llvm.LLVMInitializeLanaiTarget();
|
||||||
|
llvm.LLVMInitializeLanaiTargetInfo();
|
||||||
|
llvm.LLVMInitializeLanaiTargetMC();
|
||||||
|
llvm.LLVMInitializeLanaiAsmPrinter();
|
||||||
|
llvm.LLVMInitializeLanaiAsmParser();
|
||||||
|
},
|
||||||
|
.mips, .mipsel, .mips64, .mips64el => {
|
||||||
|
llvm.LLVMInitializeMipsTarget();
|
||||||
|
llvm.LLVMInitializeMipsTargetInfo();
|
||||||
|
llvm.LLVMInitializeMipsTargetMC();
|
||||||
|
llvm.LLVMInitializeMipsAsmPrinter();
|
||||||
|
llvm.LLVMInitializeMipsAsmParser();
|
||||||
|
},
|
||||||
|
.msp430 => {
|
||||||
|
llvm.LLVMInitializeMSP430Target();
|
||||||
|
llvm.LLVMInitializeMSP430TargetInfo();
|
||||||
|
llvm.LLVMInitializeMSP430TargetMC();
|
||||||
|
llvm.LLVMInitializeMSP430AsmPrinter();
|
||||||
|
llvm.LLVMInitializeMSP430AsmParser();
|
||||||
|
},
|
||||||
|
.nvptx, .nvptx64 => {
|
||||||
|
llvm.LLVMInitializeNVPTXTarget();
|
||||||
|
llvm.LLVMInitializeNVPTXTargetInfo();
|
||||||
|
llvm.LLVMInitializeNVPTXTargetMC();
|
||||||
|
llvm.LLVMInitializeNVPTXAsmPrinter();
|
||||||
|
// There is no LLVMInitializeNVPTXAsmParser function available.
|
||||||
|
},
|
||||||
|
.powerpc, .powerpcle, .powerpc64, .powerpc64le => {
|
||||||
|
llvm.LLVMInitializePowerPCTarget();
|
||||||
|
llvm.LLVMInitializePowerPCTargetInfo();
|
||||||
|
llvm.LLVMInitializePowerPCTargetMC();
|
||||||
|
llvm.LLVMInitializePowerPCAsmPrinter();
|
||||||
|
llvm.LLVMInitializePowerPCAsmParser();
|
||||||
|
},
|
||||||
|
.riscv32, .riscv64 => {
|
||||||
|
llvm.LLVMInitializeRISCVTarget();
|
||||||
|
llvm.LLVMInitializeRISCVTargetInfo();
|
||||||
|
llvm.LLVMInitializeRISCVTargetMC();
|
||||||
|
llvm.LLVMInitializeRISCVAsmPrinter();
|
||||||
|
llvm.LLVMInitializeRISCVAsmParser();
|
||||||
|
},
|
||||||
|
.sparc, .sparc64, .sparcel => {
|
||||||
|
llvm.LLVMInitializeSparcTarget();
|
||||||
|
llvm.LLVMInitializeSparcTargetInfo();
|
||||||
|
llvm.LLVMInitializeSparcTargetMC();
|
||||||
|
llvm.LLVMInitializeSparcAsmPrinter();
|
||||||
|
llvm.LLVMInitializeSparcAsmParser();
|
||||||
|
},
|
||||||
|
.s390x => {
|
||||||
|
llvm.LLVMInitializeSystemZTarget();
|
||||||
|
llvm.LLVMInitializeSystemZTargetInfo();
|
||||||
|
llvm.LLVMInitializeSystemZTargetMC();
|
||||||
|
llvm.LLVMInitializeSystemZAsmPrinter();
|
||||||
|
llvm.LLVMInitializeSystemZAsmParser();
|
||||||
|
},
|
||||||
|
.wasm32, .wasm64 => {
|
||||||
|
llvm.LLVMInitializeWebAssemblyTarget();
|
||||||
|
llvm.LLVMInitializeWebAssemblyTargetInfo();
|
||||||
|
llvm.LLVMInitializeWebAssemblyTargetMC();
|
||||||
|
llvm.LLVMInitializeWebAssemblyAsmPrinter();
|
||||||
|
llvm.LLVMInitializeWebAssemblyAsmParser();
|
||||||
|
},
|
||||||
|
.x86, .x86_64 => {
|
||||||
|
llvm.LLVMInitializeX86Target();
|
||||||
|
llvm.LLVMInitializeX86TargetInfo();
|
||||||
|
llvm.LLVMInitializeX86TargetMC();
|
||||||
|
llvm.LLVMInitializeX86AsmPrinter();
|
||||||
|
llvm.LLVMInitializeX86AsmParser();
|
||||||
|
},
|
||||||
|
.xtensa => {
|
||||||
|
if (build_options.llvm_has_xtensa) {
|
||||||
|
llvm.LLVMInitializeXtensaTarget();
|
||||||
|
llvm.LLVMInitializeXtensaTargetInfo();
|
||||||
|
llvm.LLVMInitializeXtensaTargetMC();
|
||||||
|
llvm.LLVMInitializeXtensaAsmPrinter();
|
||||||
|
llvm.LLVMInitializeXtensaAsmParser();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.xcore => {
|
||||||
|
llvm.LLVMInitializeXCoreTarget();
|
||||||
|
llvm.LLVMInitializeXCoreTargetInfo();
|
||||||
|
llvm.LLVMInitializeXCoreTargetMC();
|
||||||
|
llvm.LLVMInitializeXCoreAsmPrinter();
|
||||||
|
// There is no LLVMInitializeXCoreAsmParser function.
|
||||||
|
},
|
||||||
|
.m68k => {
|
||||||
|
if (build_options.llvm_has_m68k) {
|
||||||
|
llvm.LLVMInitializeM68kTarget();
|
||||||
|
llvm.LLVMInitializeM68kTargetInfo();
|
||||||
|
llvm.LLVMInitializeM68kTargetMC();
|
||||||
|
llvm.LLVMInitializeM68kAsmPrinter();
|
||||||
|
llvm.LLVMInitializeM68kAsmParser();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.csky => {
|
||||||
|
if (build_options.llvm_has_csky) {
|
||||||
|
llvm.LLVMInitializeCSKYTarget();
|
||||||
|
llvm.LLVMInitializeCSKYTargetInfo();
|
||||||
|
llvm.LLVMInitializeCSKYTargetMC();
|
||||||
|
// There is no LLVMInitializeCSKYAsmPrinter function.
|
||||||
|
llvm.LLVMInitializeCSKYAsmParser();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.ve => {
|
||||||
|
llvm.LLVMInitializeVETarget();
|
||||||
|
llvm.LLVMInitializeVETargetInfo();
|
||||||
|
llvm.LLVMInitializeVETargetMC();
|
||||||
|
llvm.LLVMInitializeVEAsmPrinter();
|
||||||
|
llvm.LLVMInitializeVEAsmParser();
|
||||||
|
},
|
||||||
|
.arc => {
|
||||||
|
if (build_options.llvm_has_arc) {
|
||||||
|
llvm.LLVMInitializeARCTarget();
|
||||||
|
llvm.LLVMInitializeARCTargetInfo();
|
||||||
|
llvm.LLVMInitializeARCTargetMC();
|
||||||
|
llvm.LLVMInitializeARCAsmPrinter();
|
||||||
|
// There is no LLVMInitializeARCAsmParser function.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// LLVM backends that have no initialization functions.
|
||||||
|
.tce,
|
||||||
|
.tcele,
|
||||||
|
.r600,
|
||||||
|
.le32,
|
||||||
|
.le64,
|
||||||
|
.amdil,
|
||||||
|
.amdil64,
|
||||||
|
.hsail,
|
||||||
|
.hsail64,
|
||||||
|
.shave,
|
||||||
|
.spir,
|
||||||
|
.spir64,
|
||||||
|
.kalimba,
|
||||||
|
.renderscript32,
|
||||||
|
.renderscript64,
|
||||||
|
.dxil,
|
||||||
|
.loongarch32,
|
||||||
|
.loongarch64,
|
||||||
|
=> {},
|
||||||
|
|
||||||
|
.spu_2 => unreachable, // LLVM does not support this backend
|
||||||
|
.spirv32 => unreachable, // LLVM does not support this backend
|
||||||
|
.spirv64 => unreachable, // LLVM does not support this backend
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String {
|
pub fn string(self: *Builder, bytes: []const u8) Allocator.Error!String {
|
||||||
try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len + 1);
|
try self.string_bytes.ensureUnusedCapacity(self.gpa, bytes.len + 1);
|
||||||
try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
|
try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
|
||||||
|
|
@ -899,6 +1226,112 @@ pub fn getGlobal(self: *const Builder, name: String) ?Global.Index {
|
||||||
return @enumFromInt(self.globals.getIndex(name) orelse return null);
|
return @enumFromInt(self.globals.getIndex(name) orelse return null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn intConst(self: *Builder, ty: Type, value: anytype) Allocator.Error!Constant {
|
||||||
|
var limbs: [
|
||||||
|
switch (@typeInfo(@TypeOf(value))) {
|
||||||
|
.Int => |info| std.math.big.int.calcTwosCompLimbCount(info.bits),
|
||||||
|
.ComptimeInt => std.math.big.int.calcLimbLen(value),
|
||||||
|
else => @compileError("intConst expected an integral value, got " ++
|
||||||
|
@typeName(@TypeOf(value))),
|
||||||
|
}
|
||||||
|
]std.math.big.Limb = undefined;
|
||||||
|
return self.bigIntConst(ty, std.math.big.int.Mutable.init(&limbs, value).toConst());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allocator.Error!Constant {
|
||||||
|
try self.constant_map.ensureUnusedCapacity(self.gpa, 1);
|
||||||
|
try self.constant_items.ensureUnusedCapacity(self.gpa, 1);
|
||||||
|
try self.constant_limbs.ensureUnusedCapacity(self.gpa, Constant.Integer.limbs + value.limbs.len);
|
||||||
|
if (self.useLibLlvm()) try self.llvm_constants.ensureUnusedCapacity(self.gpa, 1);
|
||||||
|
return self.bigIntConstAssumeCapacity(ty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
|
||||||
|
if (self.source_filename != .none) try writer.print(
|
||||||
|
\\; ModuleID = '{s}'
|
||||||
|
\\source_filename = {"}
|
||||||
|
\\
|
||||||
|
, .{ self.source_filename.toSlice(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.objects.items) |object| {
|
||||||
|
const global = self.globals.entries.get(@intFromEnum(object.global));
|
||||||
|
try writer.print(
|
||||||
|
\\@{} ={}{}{}{}{}{}{}{} {s} {%}{,}
|
||||||
|
\\
|
||||||
|
, .{
|
||||||
|
global.key.fmt(self),
|
||||||
|
global.value.linkage,
|
||||||
|
global.value.preemption,
|
||||||
|
global.value.visibility,
|
||||||
|
global.value.dll_storage_class,
|
||||||
|
object.thread_local,
|
||||||
|
global.value.unnamed_addr,
|
||||||
|
global.value.addr_space,
|
||||||
|
global.value.externally_initialized,
|
||||||
|
@tagName(object.mutability),
|
||||||
|
global.value.type.fmt(self),
|
||||||
|
global.value.alignment,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try writer.writeByte('\n');
|
||||||
|
for (self.functions.items) |function| {
|
||||||
|
const global = self.globals.entries.get(@intFromEnum(function.global));
|
||||||
|
const item = self.type_items.items[@intFromEnum(global.value.type)];
|
||||||
|
const extra = self.typeExtraDataTrail(Type.Function, item.data);
|
||||||
|
const params: []const Type =
|
||||||
|
@ptrCast(self.type_extra.items[extra.end..][0..extra.data.params_len]);
|
||||||
|
try writer.print(
|
||||||
|
\\{s} {}{}{}{}{} @{}(
|
||||||
|
, .{
|
||||||
|
if (function.body) |_| "define" else "declare",
|
||||||
|
global.value.linkage,
|
||||||
|
global.value.preemption,
|
||||||
|
global.value.visibility,
|
||||||
|
global.value.dll_storage_class,
|
||||||
|
extra.data.ret.fmt(self),
|
||||||
|
global.key.fmt(self),
|
||||||
|
});
|
||||||
|
for (params, 0..) |param, index| {
|
||||||
|
if (index > 0) try writer.writeAll(", ");
|
||||||
|
try writer.print("{%} %{d}", .{ param.fmt(self), index });
|
||||||
|
}
|
||||||
|
switch (item.tag) {
|
||||||
|
.function => {},
|
||||||
|
.vararg_function => {
|
||||||
|
if (params.len > 0) try writer.writeAll(", ");
|
||||||
|
try writer.writeAll("...");
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
try writer.print(") {}{}", .{
|
||||||
|
global.value.unnamed_addr,
|
||||||
|
global.value.alignment,
|
||||||
|
});
|
||||||
|
if (function.body) |_| try writer.print(
|
||||||
|
\\{{
|
||||||
|
\\ ret {%}
|
||||||
|
\\}}
|
||||||
|
\\
|
||||||
|
, .{
|
||||||
|
extra.data.ret.fmt(self),
|
||||||
|
});
|
||||||
|
try writer.writeByte('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ensureUnusedCapacityGlobal(self: *Builder, name: String) Allocator.Error!void {
|
fn ensureUnusedCapacityGlobal(self: *Builder, name: String) Allocator.Error!void {
|
||||||
if (self.useLibLlvm()) try self.llvm_globals.ensureUnusedCapacity(self.gpa, 1);
|
if (self.useLibLlvm()) try self.llvm_globals.ensureUnusedCapacity(self.gpa, 1);
|
||||||
try self.string_map.ensureUnusedCapacity(self.gpa, 1);
|
try self.string_map.ensureUnusedCapacity(self.gpa, 1);
|
||||||
|
|
@ -1002,6 +1435,7 @@ fn fnTypeAssumeCapacity(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
|
fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
|
||||||
|
assert(bits > 0);
|
||||||
const result = self.typeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
|
const result = self.typeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
|
||||||
if (self.useLibLlvm() and result.new)
|
if (self.useLibLlvm() and result.new)
|
||||||
self.llvm_types.appendAssumeCapacity(self.llvm_context.intType(bits));
|
self.llvm_types.appendAssumeCapacity(self.llvm_context.intType(bits));
|
||||||
|
|
@ -1162,10 +1596,16 @@ fn structTypeAssumeCapacity(
|
||||||
});
|
});
|
||||||
self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields));
|
self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields));
|
||||||
if (self.useLibLlvm()) {
|
if (self.useLibLlvm()) {
|
||||||
const llvm_fields = try self.gpa.alloc(*llvm.Type, fields.len);
|
const ExpectedContents = [32]*llvm.Type;
|
||||||
defer self.gpa.free(llvm_fields);
|
var stack align(@alignOf(ExpectedContents)) =
|
||||||
|
std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
|
||||||
|
const allocator = stack.get();
|
||||||
|
|
||||||
|
const llvm_fields = try allocator.alloc(*llvm.Type, fields.len);
|
||||||
|
defer allocator.free(llvm_fields);
|
||||||
for (llvm_fields, fields) |*llvm_field, field|
|
for (llvm_fields, fields) |*llvm_field, field|
|
||||||
llvm_field.* = self.llvm_types.items[@intFromEnum(field)];
|
llvm_field.* = self.llvm_types.items[@intFromEnum(field)];
|
||||||
|
|
||||||
self.llvm_types.appendAssumeCapacity(self.llvm_context.structType(
|
self.llvm_types.appendAssumeCapacity(self.llvm_context.structType(
|
||||||
llvm_fields.ptr,
|
llvm_fields.ptr,
|
||||||
@intCast(llvm_fields.len),
|
@intCast(llvm_fields.len),
|
||||||
|
|
@ -1277,90 +1717,114 @@ fn isValidIdentifier(id: []const u8) bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
|
fn bigIntConstAssumeCapacity(
|
||||||
if (self.source_filename != .none) try writer.print(
|
self: *Builder,
|
||||||
\\; ModuleID = '{s}'
|
ty: Type,
|
||||||
\\source_filename = {"}
|
value: std.math.big.int.Const,
|
||||||
\\
|
) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
|
||||||
, .{ self.source_filename.toSlice(self).?, self.source_filename.fmt(self) });
|
const type_item = self.type_items.items[@intFromEnum(ty)];
|
||||||
if (self.data_layout != .none) try writer.print(
|
assert(type_item.tag == .integer);
|
||||||
\\target datalayout = {"}
|
const bits = type_item.data;
|
||||||
\\
|
|
||||||
, .{self.data_layout.fmt(self)});
|
const ExpectedContents = extern struct {
|
||||||
if (self.target_triple != .none) try writer.print(
|
limbs: [64 / @sizeOf(std.math.big.Limb)]std.math.big.Limb,
|
||||||
\\target triple = {"}
|
llvm_limbs: if (build_options.have_llvm) [64 / @sizeOf(u64)]u64 else void,
|
||||||
\\
|
};
|
||||||
, .{self.target_triple.fmt(self)});
|
var stack align(@alignOf(ExpectedContents)) =
|
||||||
try writer.writeByte('\n');
|
std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
|
||||||
for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
|
const allocator = stack.get();
|
||||||
\\%{} = type {}
|
|
||||||
\\
|
var limbs: []std.math.big.Limb = &.{};
|
||||||
, .{ id.fmt(self), ty.fmt(self) });
|
defer allocator.free(limbs);
|
||||||
try writer.writeByte('\n');
|
const canonical_value = if (value.fitsInTwosComp(.signed, bits)) value else canon: {
|
||||||
for (self.objects.items) |object| {
|
assert(value.fitsInTwosComp(.unsigned, bits));
|
||||||
const global = self.globals.entries.get(@intFromEnum(object.global));
|
limbs = try allocator.alloc(std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(bits));
|
||||||
try writer.print(
|
var temp_value = std.math.big.int.Mutable.init(limbs, 0);
|
||||||
\\@{} ={}{}{}{}{}{}{}{} {s} {%}{,}
|
temp_value.truncate(value, .signed, bits);
|
||||||
\\
|
break :canon temp_value.toConst();
|
||||||
, .{
|
};
|
||||||
global.key.fmt(self),
|
assert(canonical_value.fitsInTwosComp(.signed, bits));
|
||||||
global.value.linkage,
|
|
||||||
global.value.preemption,
|
const ExtraPtr = *align(@alignOf(std.math.big.Limb)) Constant.Integer;
|
||||||
global.value.visibility,
|
const Key = struct { tag: Constant.Tag, type: Type, limbs: []const std.math.big.Limb };
|
||||||
global.value.dll_storage_class,
|
const tag: Constant.Tag = switch (canonical_value.positive) {
|
||||||
object.thread_local,
|
true => .integer_positive,
|
||||||
global.value.unnamed_addr,
|
false => .integer_negative,
|
||||||
global.value.addr_space,
|
};
|
||||||
global.value.externally_initialized,
|
const Adapter = struct {
|
||||||
@tagName(object.mutability),
|
builder: *const Builder,
|
||||||
global.value.type.fmt(self),
|
pub fn hash(_: @This(), key: Key) u32 {
|
||||||
global.value.alignment,
|
var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
|
||||||
});
|
hasher.update(std.mem.asBytes(&key.type));
|
||||||
|
hasher.update(std.mem.sliceAsBytes(key.limbs));
|
||||||
|
return @truncate(hasher.final());
|
||||||
}
|
}
|
||||||
try writer.writeByte('\n');
|
pub fn eql(ctx: @This(), lhs: Key, _: void, rhs_index: usize) bool {
|
||||||
for (self.functions.items) |function| {
|
if (lhs.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
|
||||||
const global = self.globals.entries.get(@intFromEnum(function.global));
|
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
|
||||||
const item = self.type_items.items[@intFromEnum(global.value.type)];
|
const rhs_extra: ExtraPtr = @ptrCast(
|
||||||
const extra = self.typeExtraDataTrail(Type.Function, item.data);
|
ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs],
|
||||||
const params: []const Type =
|
);
|
||||||
@ptrCast(self.type_extra.items[extra.end..][0..extra.data.params_len]);
|
const rhs_limbs = ctx.builder.constant_limbs
|
||||||
try writer.print(
|
.items[rhs_data + Constant.Integer.limbs ..][0..rhs_extra.limbs_len];
|
||||||
\\{s} {}{}{}{}{} @{}(
|
return lhs.type == rhs_extra.type and std.mem.eql(std.math.big.Limb, lhs.limbs, rhs_limbs);
|
||||||
, .{
|
|
||||||
if (function.body) |_| "define" else "declare",
|
|
||||||
global.value.linkage,
|
|
||||||
global.value.preemption,
|
|
||||||
global.value.visibility,
|
|
||||||
global.value.dll_storage_class,
|
|
||||||
extra.data.ret.fmt(self),
|
|
||||||
global.key.fmt(self),
|
|
||||||
});
|
|
||||||
for (params, 0..) |param, index| {
|
|
||||||
if (index > 0) try writer.writeAll(", ");
|
|
||||||
try writer.print("{%} %{d}", .{ param.fmt(self), index });
|
|
||||||
}
|
}
|
||||||
switch (item.tag) {
|
};
|
||||||
.function => {},
|
|
||||||
.vararg_function => {
|
const data = Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs };
|
||||||
if (params.len > 0) try writer.writeAll(", ");
|
const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
|
||||||
try writer.writeAll("...");
|
if (!gop.found_existing) {
|
||||||
},
|
gop.key_ptr.* = {};
|
||||||
else => unreachable,
|
gop.value_ptr.* = {};
|
||||||
}
|
self.constant_items.appendAssumeCapacity(.{
|
||||||
try writer.print(") {}{}", .{
|
.tag = tag,
|
||||||
global.value.unnamed_addr,
|
.data = @intCast(self.constant_limbs.items.len),
|
||||||
global.value.alignment,
|
|
||||||
});
|
});
|
||||||
if (function.body) |_| try writer.print(
|
const extra: ExtraPtr = @ptrCast(
|
||||||
\\{{
|
self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs),
|
||||||
\\ ret {%}
|
);
|
||||||
\\}}
|
extra.* = .{ .type = ty, .limbs_len = @intCast(canonical_value.limbs.len) };
|
||||||
\\
|
self.constant_limbs.appendSliceAssumeCapacity(canonical_value.limbs);
|
||||||
, .{
|
if (self.useLibLlvm()) {
|
||||||
extra.data.ret.fmt(self),
|
const llvm_type = ty.toLlvm(self);
|
||||||
});
|
if (canonical_value.to(c_longlong)) |small| {
|
||||||
try writer.writeByte('\n');
|
self.llvm_constants.appendAssumeCapacity(llvm_type.constInt(@bitCast(small), .True));
|
||||||
|
} else |_| if (canonical_value.to(c_ulonglong)) |small| {
|
||||||
|
self.llvm_constants.appendAssumeCapacity(llvm_type.constInt(small, .False));
|
||||||
|
} else |_| {
|
||||||
|
const llvm_limbs = try allocator.alloc(u64, std.math.divCeil(
|
||||||
|
usize,
|
||||||
|
canonical_value.bitCountTwosComp(),
|
||||||
|
@bitSizeOf(u64),
|
||||||
|
) catch unreachable);
|
||||||
|
defer allocator.free(llvm_limbs);
|
||||||
|
var limb_index: usize = 0;
|
||||||
|
var borrow: std.math.big.Limb = 0;
|
||||||
|
for (llvm_limbs) |*result_limb| {
|
||||||
|
var llvm_limb: u64 = 0;
|
||||||
|
inline for (0..Constant.Integer.limbs) |shift| {
|
||||||
|
const limb = if (limb_index < canonical_value.limbs.len)
|
||||||
|
canonical_value.limbs[limb_index]
|
||||||
|
else
|
||||||
|
0;
|
||||||
|
limb_index += 1;
|
||||||
|
llvm_limb |= @as(u64, limb) << shift * @bitSizeOf(std.math.big.Limb);
|
||||||
}
|
}
|
||||||
|
if (!canonical_value.positive) {
|
||||||
|
const overflow = @subWithOverflow(borrow, llvm_limb);
|
||||||
|
llvm_limb = overflow[0];
|
||||||
|
borrow -%= overflow[1];
|
||||||
|
assert(borrow == 0 or borrow == std.math.maxInt(u64));
|
||||||
|
}
|
||||||
|
result_limb.* = llvm_limb;
|
||||||
|
}
|
||||||
|
self.llvm_constants.appendAssumeCapacity(
|
||||||
|
llvm_type.constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), llvm_limbs.ptr),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return @enumFromInt(gop.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn useLibLlvm(self: *const Builder) bool {
|
inline fn useLibLlvm(self: *const Builder) bool {
|
||||||
|
|
|
||||||
|
|
@ -280,6 +280,9 @@ pub const Value = opaque {
|
||||||
|
|
||||||
pub const attachMetaData = ZigLLVMAttachMetaData;
|
pub const attachMetaData = ZigLLVMAttachMetaData;
|
||||||
extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;
|
extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;
|
||||||
|
|
||||||
|
pub const dump = LLVMDumpValue;
|
||||||
|
extern fn LLVMDumpValue(Val: *Value) void;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Type = opaque {
|
pub const Type = opaque {
|
||||||
|
|
@ -353,6 +356,9 @@ pub const Type = opaque {
|
||||||
ConstantIndices: [*]const *Value,
|
ConstantIndices: [*]const *Value,
|
||||||
NumIndices: c_uint,
|
NumIndices: c_uint,
|
||||||
) *Value;
|
) *Value;
|
||||||
|
|
||||||
|
pub const dump = LLVMDumpType;
|
||||||
|
extern fn LLVMDumpType(Ty: *Type) void;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Module = opaque {
|
pub const Module = opaque {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue