mirror of
https://github.com/ziglang/zig.git
synced 2026-02-17 06:49:23 +00:00
llvm: finish converting lowerType
This commit is contained in:
parent
3314fd83af
commit
d167bd4b56
1580
src/codegen/llvm.zig
1580
src/codegen/llvm.zig
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@ types: std.AutoArrayHashMapUnmanaged(String, Type) = .{},
|
||||
next_unnamed_type: String = @enumFromInt(0),
|
||||
next_unique_type_id: std.AutoHashMapUnmanaged(String, u32) = .{},
|
||||
type_map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
|
||||
type_data: std.ArrayListUnmanaged(Type.Data) = .{},
|
||||
type_items: std.ArrayListUnmanaged(Type.Item) = .{},
|
||||
type_extra: std.ArrayListUnmanaged(u32) = .{},
|
||||
|
||||
globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{},
|
||||
@ -62,10 +62,10 @@ pub const String = enum(u32) {
|
||||
else
|
||||
@compileError("invalid format string: '" ++ fmt_str ++ "'");
|
||||
if (need_quotes) try writer.writeByte('\"');
|
||||
for (slice) |c| switch (c) {
|
||||
for (slice) |character| switch (character) {
|
||||
'\\' => try writer.writeAll("\\\\"),
|
||||
' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(c),
|
||||
else => try writer.print("\\{X:0>2}", .{c}),
|
||||
' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(character),
|
||||
else => try writer.print("\\{X:0>2}", .{character}),
|
||||
};
|
||||
if (need_quotes) try writer.writeByte('\"');
|
||||
}
|
||||
@ -120,21 +120,25 @@ pub const Type = enum(u32) {
|
||||
none = std.math.maxInt(u32),
|
||||
_,
|
||||
|
||||
const Tag = enum(u4) {
|
||||
pub const err_int = Type.i16;
|
||||
|
||||
pub const Tag = enum(u4) {
|
||||
simple,
|
||||
function,
|
||||
vararg_function,
|
||||
integer,
|
||||
pointer,
|
||||
target,
|
||||
vector,
|
||||
vscale_vector,
|
||||
scalable_vector,
|
||||
small_array,
|
||||
array,
|
||||
structure,
|
||||
packed_structure,
|
||||
named_structure,
|
||||
};
|
||||
|
||||
const Simple = enum {
|
||||
pub const Simple = enum {
|
||||
void,
|
||||
half,
|
||||
bfloat,
|
||||
@ -150,19 +154,55 @@ pub const Type = enum(u32) {
|
||||
metadata,
|
||||
};
|
||||
|
||||
const NamedStructure = struct {
|
||||
id: String,
|
||||
child: Type,
|
||||
pub const Function = struct {
|
||||
ret: Type,
|
||||
params_len: u32,
|
||||
|
||||
pub const Kind = enum { normal, vararg };
|
||||
};
|
||||
|
||||
const Data = packed struct(u32) {
|
||||
pub const Target = extern struct {
|
||||
name: String,
|
||||
types_len: u32,
|
||||
ints_len: u32,
|
||||
};
|
||||
|
||||
pub const Vector = extern struct {
|
||||
len: u32,
|
||||
child: Type,
|
||||
|
||||
pub const Kind = enum { normal, scalable };
|
||||
};
|
||||
|
||||
pub const Array = extern struct {
|
||||
len_lo: u32,
|
||||
len_hi: u32,
|
||||
child: Type,
|
||||
|
||||
fn len(self: Array) u64 {
|
||||
return @as(u64, self.len_hi) << 32 | self.len_lo;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Structure = struct {
|
||||
fields_len: u32,
|
||||
|
||||
pub const Kind = enum { normal, @"packed" };
|
||||
};
|
||||
|
||||
pub const NamedStructure = struct {
|
||||
id: String,
|
||||
body: Type,
|
||||
};
|
||||
|
||||
pub const Item = packed struct(u32) {
|
||||
tag: Tag,
|
||||
data: ExtraIndex,
|
||||
};
|
||||
|
||||
const ExtraIndex = u28;
|
||||
pub const ExtraIndex = u28;
|
||||
|
||||
const FormatData = struct {
|
||||
pub const FormatData = struct {
|
||||
type: Type,
|
||||
builder: *const Builder,
|
||||
};
|
||||
@ -174,27 +214,106 @@ pub const Type = enum(u32) {
|
||||
) @TypeOf(writer).Error!void {
|
||||
assert(data.type != .none);
|
||||
if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
|
||||
const type_data = data.builder.type_data.items[@intFromEnum(data.type)];
|
||||
switch (type_data.tag) {
|
||||
.integer => try writer.print("i{d}", .{type_data.data}),
|
||||
const type_item = data.builder.type_items.items[@intFromEnum(data.type)];
|
||||
switch (type_item.tag) {
|
||||
.simple => unreachable,
|
||||
.function, .vararg_function => {
|
||||
const extra = data.builder.typeExtraDataTrail(Type.Function, type_item.data);
|
||||
const params: []const Type =
|
||||
@ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.params_len]);
|
||||
if (!comptime std.mem.eql(u8, fmt_str, ">"))
|
||||
try writer.print("{%} ", .{extra.data.ret.fmt(data.builder)});
|
||||
if (!comptime std.mem.eql(u8, fmt_str, "<")) {
|
||||
try writer.writeByte('(');
|
||||
for (params, 0..) |param, index| {
|
||||
if (index > 0) try writer.writeAll(", ");
|
||||
try writer.print("{%}", .{param.fmt(data.builder)});
|
||||
}
|
||||
switch (type_item.tag) {
|
||||
.function => {},
|
||||
.vararg_function => {
|
||||
if (params.len > 0) try writer.writeAll(", ");
|
||||
try writer.writeAll("...");
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
try writer.writeByte(')');
|
||||
}
|
||||
},
|
||||
.integer => try writer.print("i{d}", .{type_item.data}),
|
||||
.pointer => try writer.print("ptr{}", .{@as(AddrSpace, @enumFromInt(type_item.data))}),
|
||||
.target => {
|
||||
const extra = data.builder.typeExtraDataTrail(Type.Target, type_item.data);
|
||||
const types: []const Type =
|
||||
@ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.types_len]);
|
||||
const ints: []const u32 = @ptrCast(data.builder.type_extra.items[extra.end +
|
||||
extra.data.types_len ..][0..extra.data.ints_len]);
|
||||
try writer.print(
|
||||
\\target({"}
|
||||
, .{extra.data.name.fmt(data.builder)});
|
||||
for (types) |ty| try writer.print(", {%}", .{ty.fmt(data.builder)});
|
||||
for (ints) |int| try writer.print(", {d}", .{int});
|
||||
try writer.writeByte(')');
|
||||
},
|
||||
.vector => {
|
||||
const extra = data.builder.typeExtraData(Type.Vector, type_item.data);
|
||||
try writer.print("<{d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });
|
||||
},
|
||||
.scalable_vector => {
|
||||
const extra = data.builder.typeExtraData(Type.Vector, type_item.data);
|
||||
try writer.print("<vscale x {d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });
|
||||
},
|
||||
.small_array => {
|
||||
const extra = data.builder.typeExtraData(Type.Vector, type_item.data);
|
||||
try writer.print("[{d} x {%}]", .{ extra.len, extra.child.fmt(data.builder) });
|
||||
},
|
||||
.array => {
|
||||
const extra = data.builder.typeExtraData(Type.Array, type_item.data);
|
||||
try writer.print("[{d} x {%}]", .{ extra.len(), extra.child.fmt(data.builder) });
|
||||
},
|
||||
.structure, .packed_structure => {
|
||||
const extra = data.builder.typeExtraDataTrail(Type.Structure, type_item.data);
|
||||
const fields: []const Type =
|
||||
@ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.fields_len]);
|
||||
switch (type_item.tag) {
|
||||
.structure => {},
|
||||
.packed_structure => try writer.writeByte('<'),
|
||||
else => unreachable,
|
||||
}
|
||||
try writer.writeAll("{ ");
|
||||
for (fields, 0..) |field, index| {
|
||||
if (index > 0) try writer.writeAll(", ");
|
||||
try writer.print("{%}", .{field.fmt(data.builder)});
|
||||
}
|
||||
try writer.writeAll(" }");
|
||||
switch (type_item.tag) {
|
||||
.structure => {},
|
||||
.packed_structure => try writer.writeByte('>'),
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.named_structure => {
|
||||
const extra = data.builder.typeExtraData(NamedStructure, type_data.data);
|
||||
if (comptime std.mem.eql(u8, fmt_str, "")) switch (extra.child) {
|
||||
const extra = data.builder.typeExtraData(Type.NamedStructure, type_item.data);
|
||||
if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{
|
||||
extra.id.fmt(data.builder),
|
||||
}) else switch (extra.body) {
|
||||
.none => try writer.writeAll("opaque"),
|
||||
else => try format(.{
|
||||
.type = extra.child,
|
||||
.type = extra.body,
|
||||
.builder = data.builder,
|
||||
}, fmt_str, fmt_opts, writer),
|
||||
} else if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{
|
||||
extra.id.fmt(data.builder),
|
||||
}) else @compileError("invalid format string: '" ++ fmt_str ++ "'");
|
||||
}
|
||||
},
|
||||
else => try writer.print("<type 0x{X}>", .{@intFromEnum(data.type)}),
|
||||
}
|
||||
}
|
||||
pub fn fmt(self: Type, builder: *const Builder) std.fmt.Formatter(format) {
|
||||
return .{ .data = .{ .type = self, .builder = builder } };
|
||||
}
|
||||
|
||||
pub fn toLlvm(self: Type, builder: *const Builder) *llvm.Type {
|
||||
assert(builder.useLibLlvm());
|
||||
return builder.llvm_types.items[@intFromEnum(self)];
|
||||
}
|
||||
};
|
||||
|
||||
pub const Linkage = enum {
|
||||
@ -217,9 +336,7 @@ pub const Linkage = enum {
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (self == .default) return;
|
||||
try writer.writeAll(@tagName(self));
|
||||
try writer.writeByte(' ');
|
||||
if (self != .default) try writer.print(" {s}", .{@tagName(self)});
|
||||
}
|
||||
};
|
||||
|
||||
@ -234,9 +351,7 @@ pub const Preemption = enum {
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (self == .default) return;
|
||||
try writer.writeAll(@tagName(self));
|
||||
try writer.writeByte(' ');
|
||||
if (self != .default) try writer.print(" {s}", .{@tagName(self)});
|
||||
}
|
||||
};
|
||||
|
||||
@ -251,9 +366,7 @@ pub const Visibility = enum {
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (self == .default) return;
|
||||
try writer.writeAll(@tagName(self));
|
||||
try writer.writeByte(' ');
|
||||
if (self != .default) try writer.print(" {s}", .{@tagName(self)});
|
||||
}
|
||||
};
|
||||
|
||||
@ -268,9 +381,7 @@ pub const DllStorageClass = enum {
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (self == .default) return;
|
||||
try writer.writeAll(@tagName(self));
|
||||
try writer.writeByte(' ');
|
||||
if (self != .default) try writer.print(" {s}", .{@tagName(self)});
|
||||
}
|
||||
};
|
||||
|
||||
@ -288,13 +399,12 @@ pub const ThreadLocal = enum {
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (self == .default) return;
|
||||
try writer.writeAll("thread_local");
|
||||
try writer.writeAll(" thread_local");
|
||||
if (self != .generaldynamic) {
|
||||
try writer.writeByte('(');
|
||||
try writer.writeAll(@tagName(self));
|
||||
try writer.writeByte(')');
|
||||
}
|
||||
try writer.writeByte(' ');
|
||||
}
|
||||
};
|
||||
|
||||
@ -309,9 +419,7 @@ pub const UnnamedAddr = enum {
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (self == .default) return;
|
||||
try writer.writeAll(@tagName(self));
|
||||
try writer.writeByte(' ');
|
||||
if (self != .default) try writer.print(" {s}", .{@tagName(self)});
|
||||
}
|
||||
};
|
||||
|
||||
@ -319,14 +427,82 @@ pub const AddrSpace = enum(u24) {
|
||||
default,
|
||||
_,
|
||||
|
||||
// See llvm/lib/Target/X86/X86.h
|
||||
pub const x86 = struct {
|
||||
pub const gs: AddrSpace = @enumFromInt(256);
|
||||
pub const fs: AddrSpace = @enumFromInt(257);
|
||||
pub const ss: AddrSpace = @enumFromInt(258);
|
||||
|
||||
pub const ptr32_sptr: AddrSpace = @enumFromInt(270);
|
||||
pub const ptr32_uptr: AddrSpace = @enumFromInt(271);
|
||||
pub const ptr64: AddrSpace = @enumFromInt(272);
|
||||
};
|
||||
pub const x86_64 = x86;
|
||||
|
||||
// See llvm/lib/Target/AVR/AVR.h
|
||||
pub const avr = struct {
|
||||
pub const flash: AddrSpace = @enumFromInt(1);
|
||||
pub const flash1: AddrSpace = @enumFromInt(2);
|
||||
pub const flash2: AddrSpace = @enumFromInt(3);
|
||||
pub const flash3: AddrSpace = @enumFromInt(4);
|
||||
pub const flash4: AddrSpace = @enumFromInt(5);
|
||||
pub const flash5: AddrSpace = @enumFromInt(6);
|
||||
};
|
||||
|
||||
// See llvm/lib/Target/NVPTX/NVPTX.h
|
||||
pub const nvptx = struct {
|
||||
pub const generic: AddrSpace = @enumFromInt(0);
|
||||
pub const global: AddrSpace = @enumFromInt(1);
|
||||
pub const constant: AddrSpace = @enumFromInt(2);
|
||||
pub const shared: AddrSpace = @enumFromInt(3);
|
||||
pub const param: AddrSpace = @enumFromInt(4);
|
||||
pub const local: AddrSpace = @enumFromInt(5);
|
||||
};
|
||||
|
||||
// See llvm/lib/Target/AMDGPU/AMDGPU.h
|
||||
pub const amdgpu = struct {
|
||||
pub const flat: AddrSpace = @enumFromInt(0);
|
||||
pub const global: AddrSpace = @enumFromInt(1);
|
||||
pub const region: AddrSpace = @enumFromInt(2);
|
||||
pub const local: AddrSpace = @enumFromInt(3);
|
||||
pub const constant: AddrSpace = @enumFromInt(4);
|
||||
pub const private: AddrSpace = @enumFromInt(5);
|
||||
pub const constant_32bit: AddrSpace = @enumFromInt(6);
|
||||
pub const buffer_fat_pointer: AddrSpace = @enumFromInt(7);
|
||||
pub const param_d: AddrSpace = @enumFromInt(6);
|
||||
pub const param_i: AddrSpace = @enumFromInt(7);
|
||||
pub const constant_buffer_0: AddrSpace = @enumFromInt(8);
|
||||
pub const constant_buffer_1: AddrSpace = @enumFromInt(9);
|
||||
pub const constant_buffer_2: AddrSpace = @enumFromInt(10);
|
||||
pub const constant_buffer_3: AddrSpace = @enumFromInt(11);
|
||||
pub const constant_buffer_4: AddrSpace = @enumFromInt(12);
|
||||
pub const constant_buffer_5: AddrSpace = @enumFromInt(13);
|
||||
pub const constant_buffer_6: AddrSpace = @enumFromInt(14);
|
||||
pub const constant_buffer_7: AddrSpace = @enumFromInt(15);
|
||||
pub const constant_buffer_8: AddrSpace = @enumFromInt(16);
|
||||
pub const constant_buffer_9: AddrSpace = @enumFromInt(17);
|
||||
pub const constant_buffer_10: AddrSpace = @enumFromInt(18);
|
||||
pub const constant_buffer_11: AddrSpace = @enumFromInt(19);
|
||||
pub const constant_buffer_12: AddrSpace = @enumFromInt(20);
|
||||
pub const constant_buffer_13: AddrSpace = @enumFromInt(21);
|
||||
pub const constant_buffer_14: AddrSpace = @enumFromInt(22);
|
||||
pub const constant_buffer_15: AddrSpace = @enumFromInt(23);
|
||||
};
|
||||
|
||||
// See llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
|
||||
pub const wasm = struct {
|
||||
pub const variable: AddrSpace = @enumFromInt(1);
|
||||
pub const externref: AddrSpace = @enumFromInt(10);
|
||||
pub const funcref: AddrSpace = @enumFromInt(20);
|
||||
};
|
||||
|
||||
pub fn format(
|
||||
self: AddrSpace,
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (self == .default) return;
|
||||
try writer.print("addrspace({d}) ", .{@intFromEnum(self)});
|
||||
if (self != .default) try writer.print(" addrspace({d})", .{@intFromEnum(self)});
|
||||
}
|
||||
};
|
||||
|
||||
@ -341,8 +517,8 @@ pub const ExternallyInitialized = enum {
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (self == .default) return;
|
||||
try writer.writeAll(@tagName(self));
|
||||
try writer.writeByte(' ');
|
||||
try writer.writeAll(@tagName(self));
|
||||
}
|
||||
};
|
||||
|
||||
@ -399,6 +575,7 @@ pub const Global = struct {
|
||||
}
|
||||
|
||||
pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
|
||||
assert(builder.useLibLlvm());
|
||||
return builder.llvm_globals.items[@intFromEnum(self)];
|
||||
}
|
||||
|
||||
@ -517,7 +694,7 @@ pub fn init(self: *Builder) Allocator.Error!void {
|
||||
{
|
||||
const static_len = @typeInfo(Type).Enum.fields.len - 1;
|
||||
try self.type_map.ensureTotalCapacity(self.gpa, static_len);
|
||||
try self.type_data.ensureTotalCapacity(self.gpa, static_len);
|
||||
try self.type_items.ensureTotalCapacity(self.gpa, static_len);
|
||||
if (self.useLibLlvm()) try self.llvm_types.ensureTotalCapacity(self.gpa, static_len);
|
||||
inline for (@typeInfo(Type.Simple).Enum.fields) |simple_field| {
|
||||
const result = self.typeNoExtraAssumeCapacity(.{
|
||||
@ -532,7 +709,7 @@ pub fn init(self: *Builder) Allocator.Error!void {
|
||||
inline for (.{ 1, 8, 16, 29, 32, 64, 80, 128 }) |bits| assert(self.intTypeAssumeCapacity(bits) ==
|
||||
@field(Type, std.fmt.comptimePrint("i{d}", .{bits})));
|
||||
inline for (.{0}) |addr_space|
|
||||
assert(self.pointerTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
|
||||
assert(self.ptrTypeAssumeCapacity(@enumFromInt(addr_space)) == .ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -547,7 +724,7 @@ pub fn deinit(self: *Builder) void {
|
||||
self.types.deinit(self.gpa);
|
||||
self.next_unique_type_id.deinit(self.gpa);
|
||||
self.type_map.deinit(self.gpa);
|
||||
self.type_data.deinit(self.gpa);
|
||||
self.type_items.deinit(self.gpa);
|
||||
self.type_extra.deinit(self.gpa);
|
||||
|
||||
self.globals.deinit(self.gpa);
|
||||
@ -600,25 +777,95 @@ pub fn fmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args:
|
||||
return String.fromIndex(gop.index);
|
||||
}
|
||||
|
||||
pub fn fnType(
|
||||
self: *Builder,
|
||||
ret: Type,
|
||||
params: []const Type,
|
||||
kind: Type.Function.Kind,
|
||||
) Allocator.Error!Type {
|
||||
try self.ensureUnusedCapacityTypes(1, Type.Function, params.len);
|
||||
return switch (kind) {
|
||||
inline else => |comptime_kind| self.fnTypeAssumeCapacity(ret, params, comptime_kind),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
|
||||
try self.ensureUnusedCapacityTypes(1, null, 0);
|
||||
return self.intTypeAssumeCapacity(bits);
|
||||
}
|
||||
|
||||
pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {
|
||||
try self.ensureUnusedCapacityTypes(1, null, 0);
|
||||
return self.ptrTypeAssumeCapacity(addr_space);
|
||||
}
|
||||
|
||||
pub fn vectorType(
|
||||
self: *Builder,
|
||||
kind: Type.Vector.Kind,
|
||||
len: u32,
|
||||
child: Type,
|
||||
) Allocator.Error!Type {
|
||||
try self.ensureUnusedCapacityTypes(1, Type.Vector, 0);
|
||||
return switch (kind) {
|
||||
inline else => |comptime_kind| self.vectorTypeAssumeCapacity(comptime_kind, len, child),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn arrayType(self: *Builder, len: u64, child: Type) Allocator.Error!Type {
|
||||
comptime assert(@sizeOf(Type.Array) >= @sizeOf(Type.Vector));
|
||||
try self.ensureUnusedCapacityTypes(1, Type.Array, 0);
|
||||
return self.arrayTypeAssumeCapacity(len, child);
|
||||
}
|
||||
|
||||
pub fn structType(
|
||||
self: *Builder,
|
||||
kind: Type.Structure.Kind,
|
||||
fields: []const Type,
|
||||
) Allocator.Error!Type {
|
||||
try self.ensureUnusedCapacityTypes(1, Type.Structure, fields.len);
|
||||
return switch (kind) {
|
||||
inline else => |comptime_kind| self.structTypeAssumeCapacity(comptime_kind, fields),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
|
||||
try self.string_map.ensureUnusedCapacity(self.gpa, 1);
|
||||
try self.string_bytes.ensureUnusedCapacity(self.gpa, name.toSlice(self).?.len +
|
||||
if (name.toSlice(self)) |id| try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len +
|
||||
comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)}));
|
||||
try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
|
||||
try self.types.ensureUnusedCapacity(self.gpa, 1);
|
||||
try self.next_unique_type_id.ensureUnusedCapacity(self.gpa, 1);
|
||||
try self.ensureUnusedCapacityTypes(1, Type.NamedStructure);
|
||||
try self.ensureUnusedCapacityTypes(1, Type.NamedStructure, 0);
|
||||
return self.opaqueTypeAssumeCapacity(name);
|
||||
}
|
||||
|
||||
pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
|
||||
try self.ensureUnusedCapacityTypes(1, null);
|
||||
return self.intTypeAssumeCapacity(bits);
|
||||
}
|
||||
|
||||
pub fn pointerType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {
|
||||
try self.ensureUnusedCapacityTypes(1, null);
|
||||
return self.pointerTypeAssumeCapacity(addr_space);
|
||||
pub fn namedTypeSetBody(
|
||||
self: *Builder,
|
||||
named_type: Type,
|
||||
body_type: Type,
|
||||
) if (build_options.have_llvm) Allocator.Error!void else void {
|
||||
const named_item = self.type_items.items[@intFromEnum(named_type)];
|
||||
self.type_extra.items[named_item.data + std.meta.fieldIndex(Type.NamedStructure, "body").?] =
|
||||
@intFromEnum(body_type);
|
||||
if (self.useLibLlvm()) {
|
||||
const body_item = self.type_items.items[@intFromEnum(body_type)];
|
||||
const body_extra = self.typeExtraDataTrail(Type.Structure, body_item.data);
|
||||
const body_fields: []const Type =
|
||||
@ptrCast(self.type_extra.items[body_extra.end..][0..body_extra.data.fields_len]);
|
||||
const llvm_fields = try self.gpa.alloc(*llvm.Type, body_fields.len);
|
||||
defer self.gpa.free(llvm_fields);
|
||||
for (llvm_fields, body_fields) |*llvm_field, body_field|
|
||||
llvm_field.* = self.llvm_types.items[@intFromEnum(body_field)];
|
||||
self.llvm_types.items[@intFromEnum(named_type)].structSetBody(
|
||||
llvm_fields.ptr,
|
||||
@intCast(llvm_fields.len),
|
||||
switch (body_item.tag) {
|
||||
.structure => .False,
|
||||
.packed_structure => .True,
|
||||
else => unreachable,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
|
||||
@ -667,6 +914,7 @@ fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.ExtraIndex {
|
||||
inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
|
||||
const value = @field(extra, field.name);
|
||||
self.type_extra.appendAssumeCapacity(switch (field.type) {
|
||||
u32 => value,
|
||||
String, Type => @intFromEnum(value),
|
||||
else => @compileError("bad field type: " ++ @typeName(field.type)),
|
||||
});
|
||||
@ -683,6 +931,7 @@ fn typeExtraDataTrail(
|
||||
const fields = @typeInfo(T).Struct.fields;
|
||||
inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, data|
|
||||
@field(result, field.name) = switch (field.type) {
|
||||
u32 => data,
|
||||
String, Type => @enumFromInt(data),
|
||||
else => @compileError("bad field type: " ++ @typeName(field.type)),
|
||||
};
|
||||
@ -693,14 +942,254 @@ fn typeExtraData(self: *const Builder, comptime T: type, index: Type.ExtraIndex)
|
||||
return self.typeExtraDataTrail(T, index).data;
|
||||
}
|
||||
|
||||
fn fnTypeAssumeCapacity(
|
||||
self: *Builder,
|
||||
ret: Type,
|
||||
params: []const Type,
|
||||
comptime kind: Type.Function.Kind,
|
||||
) if (build_options.have_llvm) Allocator.Error!Type else Type {
|
||||
const tag: Type.Tag = switch (kind) {
|
||||
.normal => .function,
|
||||
.vararg => .vararg_function,
|
||||
};
|
||||
const Key = struct { ret: Type, params: []const Type };
|
||||
const Adapter = struct {
|
||||
builder: *const Builder,
|
||||
pub fn hash(_: @This(), key: Key) u32 {
|
||||
var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
|
||||
hasher.update(std.mem.asBytes(&key.ret));
|
||||
hasher.update(std.mem.sliceAsBytes(key.params));
|
||||
return @truncate(hasher.final());
|
||||
}
|
||||
pub fn eql(ctx: @This(), lhs: Key, _: void, rhs_index: usize) bool {
|
||||
const rhs_data = ctx.builder.type_items.items[rhs_index];
|
||||
const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Function, rhs_data.data);
|
||||
const rhs_params: []const Type =
|
||||
@ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.params_len]);
|
||||
return rhs_data.tag == tag and lhs.ret == rhs_extra.data.ret and
|
||||
std.mem.eql(Type, lhs.params, rhs_params);
|
||||
}
|
||||
};
|
||||
const data = Key{ .ret = ret, .params = params };
|
||||
const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
|
||||
if (!gop.found_existing) {
|
||||
gop.key_ptr.* = {};
|
||||
gop.value_ptr.* = {};
|
||||
self.type_items.appendAssumeCapacity(.{
|
||||
.tag = .function,
|
||||
.data = self.addTypeExtraAssumeCapacity(Type.Function{
|
||||
.ret = ret,
|
||||
.params_len = @intCast(params.len),
|
||||
}),
|
||||
});
|
||||
self.type_extra.appendSliceAssumeCapacity(@ptrCast(params));
|
||||
if (self.useLibLlvm()) {
|
||||
const llvm_params = try self.gpa.alloc(*llvm.Type, params.len);
|
||||
defer self.gpa.free(llvm_params);
|
||||
for (llvm_params, params) |*llvm_param, param| llvm_param.* = param.toLlvm(self);
|
||||
self.llvm_types.appendAssumeCapacity(llvm.functionType(
|
||||
ret.toLlvm(self),
|
||||
llvm_params.ptr,
|
||||
@intCast(llvm_params.len),
|
||||
switch (kind) {
|
||||
.normal => .False,
|
||||
.vararg => .True,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
return @enumFromInt(gop.index);
|
||||
}
|
||||
|
||||
fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
|
||||
const result = self.typeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
|
||||
if (self.useLibLlvm() and result.new)
|
||||
self.llvm_types.appendAssumeCapacity(self.llvm_context.intType(bits));
|
||||
return result.type;
|
||||
}
|
||||
|
||||
fn ptrTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type {
|
||||
const result = self.typeNoExtraAssumeCapacity(.{
|
||||
.tag = .pointer,
|
||||
.data = @intFromEnum(addr_space),
|
||||
});
|
||||
if (self.useLibLlvm() and result.new)
|
||||
self.llvm_types.appendAssumeCapacity(self.llvm_context.pointerType(@intFromEnum(addr_space)));
|
||||
return result.type;
|
||||
}
|
||||
|
||||
fn vectorTypeAssumeCapacity(
|
||||
self: *Builder,
|
||||
comptime kind: Type.Vector.Kind,
|
||||
len: u32,
|
||||
child: Type,
|
||||
) Type {
|
||||
const tag: Type.Tag = switch (kind) {
|
||||
.normal => .vector,
|
||||
.scalable => .scalable_vector,
|
||||
};
|
||||
const Adapter = struct {
|
||||
builder: *const Builder,
|
||||
pub fn hash(_: @This(), key: Type.Vector) u32 {
|
||||
return @truncate(std.hash.Wyhash.hash(
|
||||
comptime std.hash.uint32(@intFromEnum(tag)),
|
||||
std.mem.asBytes(&key),
|
||||
));
|
||||
}
|
||||
pub fn eql(ctx: @This(), lhs: Type.Vector, _: void, rhs_index: usize) bool {
|
||||
const rhs_data = ctx.builder.type_items.items[rhs_index];
|
||||
return rhs_data.tag == tag and
|
||||
std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
|
||||
}
|
||||
};
|
||||
const data = Type.Vector{ .len = len, .child = child };
|
||||
const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
|
||||
if (!gop.found_existing) {
|
||||
gop.key_ptr.* = {};
|
||||
gop.value_ptr.* = {};
|
||||
self.type_items.appendAssumeCapacity(.{
|
||||
.tag = tag,
|
||||
.data = self.addTypeExtraAssumeCapacity(data),
|
||||
});
|
||||
if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity(switch (kind) {
|
||||
.normal => &llvm.Type.vectorType,
|
||||
.scalable => &llvm.Type.scalableVectorType,
|
||||
}(child.toLlvm(self), @intCast(len)));
|
||||
}
|
||||
return @enumFromInt(gop.index);
|
||||
}
|
||||
|
||||
fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {
|
||||
if (std.math.cast(u32, len)) |small_len| {
|
||||
const Adapter = struct {
|
||||
builder: *const Builder,
|
||||
pub fn hash(_: @This(), key: Type.Vector) u32 {
|
||||
return @truncate(std.hash.Wyhash.hash(
|
||||
comptime std.hash.uint32(@intFromEnum(Type.Tag.small_array)),
|
||||
std.mem.asBytes(&key),
|
||||
));
|
||||
}
|
||||
pub fn eql(ctx: @This(), lhs: Type.Vector, _: void, rhs_index: usize) bool {
|
||||
const rhs_data = ctx.builder.type_items.items[rhs_index];
|
||||
return rhs_data.tag == .small_array and
|
||||
std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
|
||||
}
|
||||
};
|
||||
const data = Type.Vector{ .len = small_len, .child = child };
|
||||
const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
|
||||
if (!gop.found_existing) {
|
||||
gop.key_ptr.* = {};
|
||||
gop.value_ptr.* = {};
|
||||
self.type_items.appendAssumeCapacity(.{
|
||||
.tag = .small_array,
|
||||
.data = self.addTypeExtraAssumeCapacity(data),
|
||||
});
|
||||
if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity(
|
||||
child.toLlvm(self).arrayType(@intCast(len)),
|
||||
);
|
||||
}
|
||||
return @enumFromInt(gop.index);
|
||||
} else {
|
||||
const Adapter = struct {
|
||||
builder: *const Builder,
|
||||
pub fn hash(_: @This(), key: Type.Array) u32 {
|
||||
return @truncate(std.hash.Wyhash.hash(
|
||||
comptime std.hash.uint32(@intFromEnum(Type.Tag.array)),
|
||||
std.mem.asBytes(&key),
|
||||
));
|
||||
}
|
||||
pub fn eql(ctx: @This(), lhs: Type.Array, _: void, rhs_index: usize) bool {
|
||||
const rhs_data = ctx.builder.type_items.items[rhs_index];
|
||||
return rhs_data.tag == .array and
|
||||
std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Array, rhs_data.data));
|
||||
}
|
||||
};
|
||||
const data = Type.Array{
|
||||
.len_lo = @truncate(len),
|
||||
.len_hi = @intCast(len >> 32),
|
||||
.child = child,
|
||||
};
|
||||
const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
|
||||
if (!gop.found_existing) {
|
||||
gop.key_ptr.* = {};
|
||||
gop.value_ptr.* = {};
|
||||
self.type_items.appendAssumeCapacity(.{
|
||||
.tag = .array,
|
||||
.data = self.addTypeExtraAssumeCapacity(data),
|
||||
});
|
||||
if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity(
|
||||
child.toLlvm(self).arrayType(@intCast(len)),
|
||||
);
|
||||
}
|
||||
return @enumFromInt(gop.index);
|
||||
}
|
||||
}
|
||||
|
||||
fn structTypeAssumeCapacity(
|
||||
self: *Builder,
|
||||
comptime kind: Type.Structure.Kind,
|
||||
fields: []const Type,
|
||||
) if (build_options.have_llvm) Allocator.Error!Type else Type {
|
||||
const tag: Type.Tag = switch (kind) {
|
||||
.normal => .structure,
|
||||
.@"packed" => .packed_structure,
|
||||
};
|
||||
const Adapter = struct {
|
||||
builder: *const Builder,
|
||||
pub fn hash(_: @This(), key: []const Type) u32 {
|
||||
return @truncate(std.hash.Wyhash.hash(
|
||||
comptime std.hash.uint32(@intFromEnum(tag)),
|
||||
std.mem.sliceAsBytes(key),
|
||||
));
|
||||
}
|
||||
pub fn eql(ctx: @This(), lhs: []const Type, _: void, rhs_index: usize) bool {
|
||||
const rhs_data = ctx.builder.type_items.items[rhs_index];
|
||||
const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Structure, rhs_data.data);
|
||||
const rhs_fields: []const Type =
|
||||
@ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.fields_len]);
|
||||
return rhs_data.tag == tag and std.mem.eql(Type, lhs, rhs_fields);
|
||||
}
|
||||
};
|
||||
const gop = self.type_map.getOrPutAssumeCapacityAdapted(fields, Adapter{ .builder = self });
|
||||
if (!gop.found_existing) {
|
||||
gop.key_ptr.* = {};
|
||||
gop.value_ptr.* = {};
|
||||
self.type_items.appendAssumeCapacity(.{
|
||||
.tag = tag,
|
||||
.data = self.addTypeExtraAssumeCapacity(Type.Structure{
|
||||
.fields_len = @intCast(fields.len),
|
||||
}),
|
||||
});
|
||||
self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields));
|
||||
if (self.useLibLlvm()) {
|
||||
const llvm_fields = try self.gpa.alloc(*llvm.Type, fields.len);
|
||||
defer self.gpa.free(llvm_fields);
|
||||
for (llvm_fields, fields) |*llvm_field, field|
|
||||
llvm_field.* = self.llvm_types.items[@intFromEnum(field)];
|
||||
self.llvm_types.appendAssumeCapacity(self.llvm_context.structType(
|
||||
llvm_fields.ptr,
|
||||
@intCast(llvm_fields.len),
|
||||
switch (kind) {
|
||||
.normal => .False,
|
||||
.@"packed" => .True,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
return @enumFromInt(gop.index);
|
||||
}
|
||||
|
||||
fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
|
||||
const Adapter = struct {
|
||||
builder: *const Builder,
|
||||
pub fn hash(_: @This(), key: String) u32 {
|
||||
return std.hash.uint32(@intFromEnum(key));
|
||||
return @truncate(std.hash.Wyhash.hash(
|
||||
comptime std.hash.uint32(@intFromEnum(Type.Tag.named_structure)),
|
||||
std.mem.asBytes(&key),
|
||||
));
|
||||
}
|
||||
pub fn eql(ctx: @This(), lhs: String, _: void, rhs_index: usize) bool {
|
||||
const rhs_data = ctx.builder.type_data.items[rhs_index];
|
||||
const rhs_data = ctx.builder.type_items.items[rhs_index];
|
||||
return rhs_data.tag == .named_structure and
|
||||
lhs == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id;
|
||||
}
|
||||
@ -718,11 +1207,11 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
|
||||
assert(!gop.found_existing);
|
||||
gop.key_ptr.* = {};
|
||||
gop.value_ptr.* = {};
|
||||
self.type_data.appendAssumeCapacity(.{
|
||||
self.type_items.appendAssumeCapacity(.{
|
||||
.tag = .named_structure,
|
||||
.data = self.addTypeExtraAssumeCapacity(Type.NamedStructure{
|
||||
.id = id,
|
||||
.child = .none,
|
||||
.body = .none,
|
||||
}),
|
||||
});
|
||||
const result: Type = @enumFromInt(gop.index);
|
||||
@ -740,53 +1229,49 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
|
||||
}
|
||||
}
|
||||
|
||||
fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
|
||||
const result = self.typeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
|
||||
if (self.useLibLlvm() and result.new)
|
||||
self.llvm_types.appendAssumeCapacity(self.llvm_context.intType(bits));
|
||||
return result.type;
|
||||
}
|
||||
|
||||
fn pointerTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type {
|
||||
const result = self.typeNoExtraAssumeCapacity(.{ .tag = .pointer, .data = @intFromEnum(addr_space) });
|
||||
if (self.useLibLlvm() and result.new)
|
||||
self.llvm_types.appendAssumeCapacity(self.llvm_context.pointerType(@intFromEnum(addr_space)));
|
||||
return result.type;
|
||||
}
|
||||
|
||||
fn ensureUnusedCapacityTypes(self: *Builder, count: usize, comptime Extra: ?type) Allocator.Error!void {
|
||||
fn ensureUnusedCapacityTypes(
|
||||
self: *Builder,
|
||||
count: usize,
|
||||
comptime Extra: ?type,
|
||||
trail_len: usize,
|
||||
) Allocator.Error!void {
|
||||
try self.type_map.ensureUnusedCapacity(self.gpa, count);
|
||||
try self.type_data.ensureUnusedCapacity(self.gpa, count);
|
||||
if (Extra) |E|
|
||||
try self.type_extra.ensureUnusedCapacity(self.gpa, count * @typeInfo(E).Struct.fields.len);
|
||||
try self.type_items.ensureUnusedCapacity(self.gpa, count);
|
||||
if (Extra) |E| try self.type_extra.ensureUnusedCapacity(
|
||||
self.gpa,
|
||||
count * (@typeInfo(E).Struct.fields.len + trail_len),
|
||||
);
|
||||
if (self.useLibLlvm()) try self.llvm_types.ensureUnusedCapacity(self.gpa, count);
|
||||
}
|
||||
|
||||
fn typeNoExtraAssumeCapacity(self: *Builder, data: Type.Data) struct { new: bool, type: Type } {
|
||||
fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } {
|
||||
const Adapter = struct {
|
||||
builder: *const Builder,
|
||||
pub fn hash(_: @This(), key: Type.Data) u32 {
|
||||
return std.hash.uint32(@bitCast(key));
|
||||
pub fn hash(_: @This(), key: Type.Item) u32 {
|
||||
return @truncate(std.hash.Wyhash.hash(
|
||||
comptime std.hash.uint32(@intFromEnum(Type.Tag.simple)),
|
||||
std.mem.asBytes(&key),
|
||||
));
|
||||
}
|
||||
pub fn eql(ctx: @This(), lhs: Type.Data, _: void, rhs_index: usize) bool {
|
||||
pub fn eql(ctx: @This(), lhs: Type.Item, _: void, rhs_index: usize) bool {
|
||||
const lhs_bits: u32 = @bitCast(lhs);
|
||||
const rhs_bits: u32 = @bitCast(ctx.builder.type_data.items[rhs_index]);
|
||||
const rhs_bits: u32 = @bitCast(ctx.builder.type_items.items[rhs_index]);
|
||||
return lhs_bits == rhs_bits;
|
||||
}
|
||||
};
|
||||
const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
|
||||
const gop = self.type_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self });
|
||||
if (!gop.found_existing) {
|
||||
gop.key_ptr.* = {};
|
||||
gop.value_ptr.* = {};
|
||||
self.type_data.appendAssumeCapacity(data);
|
||||
self.type_items.appendAssumeCapacity(item);
|
||||
}
|
||||
return .{ .new = !gop.found_existing, .type = @enumFromInt(gop.index) };
|
||||
}
|
||||
|
||||
fn isValidIdentifier(id: []const u8) bool {
|
||||
for (id, 0..) |c, i| switch (c) {
|
||||
for (id, 0..) |character, index| switch (character) {
|
||||
'$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
|
||||
'0'...'9' => if (i == 0) return false,
|
||||
'0'...'9' => if (index == 0) return false,
|
||||
else => return false,
|
||||
};
|
||||
return true;
|
||||
@ -815,7 +1300,7 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
|
||||
for (self.objects.items) |object| {
|
||||
const global = self.globals.entries.get(@intFromEnum(object.global));
|
||||
try writer.print(
|
||||
\\@{} = {}{}{}{}{}{}{}{}{s} {}{,}
|
||||
\\@{} ={}{}{}{}{}{}{}{} {s} {%}{,}
|
||||
\\
|
||||
, .{
|
||||
global.key.fmt(self),
|
||||
@ -836,8 +1321,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
|
||||
for (self.functions.items) |function| {
|
||||
const global = self.globals.entries.get(@intFromEnum(function.global));
|
||||
try writer.print(
|
||||
\\{s} {}{}{}{}void @{}() {}{}{{
|
||||
\\ ret void
|
||||
\\{s} {}{}{}{}{<}@{}{>} {}{}{{
|
||||
\\ ret {%}
|
||||
\\}}
|
||||
\\
|
||||
, .{
|
||||
@ -846,9 +1331,15 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
|
||||
global.value.preemption,
|
||||
global.value.visibility,
|
||||
global.value.dll_storage_class,
|
||||
global.value.type.fmt(self),
|
||||
global.key.fmt(self),
|
||||
global.value.type.fmt(self),
|
||||
global.value.unnamed_addr,
|
||||
global.value.alignment,
|
||||
self.typeExtraData(
|
||||
Type.Function,
|
||||
self.type_items.items[@intFromEnum(global.value.type)].data,
|
||||
).ret.fmt(self),
|
||||
});
|
||||
}
|
||||
try writer.writeByte('\n');
|
||||
|
||||
@ -317,6 +317,9 @@ pub const Type = opaque {
|
||||
pub const vectorType = LLVMVectorType;
|
||||
extern fn LLVMVectorType(ElementType: *Type, ElementCount: c_uint) *Type;
|
||||
|
||||
pub const scalableVectorType = LLVMScalableVectorType;
|
||||
extern fn LLVMScalableVectorType(ElementType: *Type, ElementCount: c_uint) *Type;
|
||||
|
||||
pub const structSetBody = LLVMStructSetBody;
|
||||
extern fn LLVMStructSetBody(
|
||||
StructTy: *Type,
|
||||
@ -1615,9 +1618,9 @@ pub const address_space = struct {
|
||||
|
||||
// See llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
|
||||
pub const wasm = struct {
|
||||
pub const variable = 1;
|
||||
pub const externref = 10;
|
||||
pub const funcref = 20;
|
||||
pub const variable: c_uint = 1;
|
||||
pub const externref: c_uint = 10;
|
||||
pub const funcref: c_uint = 20;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user