Basic bit fields
This commit is contained in:
parent
36fc4807bb
commit
eaa64a8d78
85
src/LLVM.zig
85
src/LLVM.zig
@ -507,6 +507,9 @@ pub const Context = opaque {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const get_struct_type = api.llvm_context_get_struct_type;
|
pub const get_struct_type = api.llvm_context_get_struct_type;
|
||||||
|
|
||||||
|
pub const get_void_type = api.LLVMVoidTypeInContext;
|
||||||
|
pub const get_integer_type = api.LLVMIntTypeInContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const BasicBlock = opaque {
|
pub const BasicBlock = opaque {
|
||||||
@ -658,6 +661,14 @@ pub const Builder = opaque {
|
|||||||
pub fn create_insert_value(builder: *Builder, aggregate: *Value, element: *Value, index: c_uint) *Value {
|
pub fn create_insert_value(builder: *Builder, aggregate: *Value, element: *Value, index: c_uint) *Value {
|
||||||
return api.LLVMBuildInsertValue(builder, aggregate, element, index, "");
|
return api.LLVMBuildInsertValue(builder, aggregate, element, index, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_zero_extend(builder: *Builder, value: *Value, destination_type: *Type) *Value {
|
||||||
|
return api.LLVMBuildZExt(builder, value, destination_type, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_sign_extend(builder: *Builder, value: *Value, destination_type: *Type) *Value {
|
||||||
|
return api.LLVMBuildSExt(builder, value, destination_type, "");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const GlobalValue = opaque {
|
pub const GlobalValue = opaque {
|
||||||
@ -868,6 +879,10 @@ pub const DI = struct {
|
|||||||
pub fn create_member_type(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, file: *DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, bit_offset: u64, flags: DI.Flags, member_type: *DI.Type) *DI.Type.Derived {
|
pub fn create_member_type(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, file: *DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, bit_offset: u64, flags: DI.Flags, member_type: *DI.Type) *DI.Type.Derived {
|
||||||
return api.LLVMDIBuilderCreateMemberType(builder, scope, name.ptr, name.len, file, line, bit_size, align_in_bits, bit_offset, flags, member_type);
|
return api.LLVMDIBuilderCreateMemberType(builder, scope, name.ptr, name.len, file, line, bit_size, align_in_bits, bit_offset, flags, member_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_bit_field_member_type(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, file: *DI.File, line: c_uint, bit_size: u64, bit_offset: u64, bit_storage_offset: u64, flags: DI.Flags, member_type: *DI.Type) *DI.Type.Derived {
|
||||||
|
return api.LLVMDIBuilderCreateBitFieldMemberType(builder, scope, name.ptr, name.len, file, line, bit_size, bit_offset, bit_storage_offset, flags, member_type);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const create_debug_location = api.LLVMDIBuilderCreateDebugLocation;
|
pub const create_debug_location = api.LLVMDIBuilderCreateDebugLocation;
|
||||||
@ -1234,69 +1249,7 @@ pub const lld = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Thread = struct {
|
|
||||||
context: *Context,
|
|
||||||
builder: *Builder,
|
|
||||||
i1: Integer,
|
|
||||||
i8: Integer,
|
|
||||||
i16: Integer,
|
|
||||||
i32: Integer,
|
|
||||||
i64: Integer,
|
|
||||||
i128: Integer,
|
|
||||||
|
|
||||||
pub const Integer = struct {
|
|
||||||
type: *Type.Integer,
|
|
||||||
zero: *Constant.Integer,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn initialize(thread: *Thread) void {
|
|
||||||
const context = Context.create();
|
|
||||||
const type_i1 = api.LLVMInt1TypeInContext(context);
|
|
||||||
const type_i8 = api.LLVMInt8TypeInContext(context);
|
|
||||||
const type_i16 = api.LLVMInt16TypeInContext(context);
|
|
||||||
const type_i32 = api.LLVMInt32TypeInContext(context);
|
|
||||||
const type_i64 = api.LLVMInt64TypeInContext(context);
|
|
||||||
const type_i128 = api.LLVMInt128TypeInContext(context);
|
|
||||||
const zero_i1 = type_i1.get_constant(0, 0);
|
|
||||||
const zero_i8 = type_i8.get_constant(0, 0);
|
|
||||||
const zero_i16 = type_i16.get_constant(0, 0);
|
|
||||||
const zero_i32 = type_i32.get_constant(0, 0);
|
|
||||||
const zero_i64 = type_i64.get_constant(0, 0);
|
|
||||||
const zero_i128 = type_i128.get_constant(0, 0);
|
|
||||||
|
|
||||||
thread.* = .{
|
|
||||||
.context = context,
|
|
||||||
.builder = context.create_builder(),
|
|
||||||
.i1 = .{
|
|
||||||
.type = type_i1,
|
|
||||||
.zero = zero_i1,
|
|
||||||
},
|
|
||||||
.i8 = .{
|
|
||||||
.type = type_i8,
|
|
||||||
.zero = zero_i8,
|
|
||||||
},
|
|
||||||
.i16 = .{
|
|
||||||
.type = type_i16,
|
|
||||||
.zero = zero_i16,
|
|
||||||
},
|
|
||||||
.i32 = .{
|
|
||||||
.type = type_i32,
|
|
||||||
.zero = zero_i32,
|
|
||||||
},
|
|
||||||
.i64 = .{
|
|
||||||
.type = type_i64,
|
|
||||||
.zero = zero_i64,
|
|
||||||
},
|
|
||||||
.i128 = .{
|
|
||||||
.type = type_i128,
|
|
||||||
.zero = zero_i128,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Global = struct {
|
pub const Global = struct {
|
||||||
threads: []Thread,
|
|
||||||
host_triple: []const u8,
|
host_triple: []const u8,
|
||||||
host_cpu_model: []const u8,
|
host_cpu_model: []const u8,
|
||||||
host_cpu_features: []const u8,
|
host_cpu_features: []const u8,
|
||||||
@ -1314,7 +1267,6 @@ pub fn initialize_all() void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
global = .{
|
global = .{
|
||||||
.threads = lib.global.arena.allocate(Thread, lib.global.thread_count),
|
|
||||||
.host_triple = api.llvm_default_target_triple().to_slice() orelse unreachable,
|
.host_triple = api.llvm_default_target_triple().to_slice() orelse unreachable,
|
||||||
.host_cpu_model = api.llvm_host_cpu_name().to_slice() orelse unreachable,
|
.host_cpu_model = api.llvm_host_cpu_name().to_slice() orelse unreachable,
|
||||||
.host_cpu_features = api.llvm_host_cpu_features().to_slice() orelse unreachable,
|
.host_cpu_features = api.llvm_host_cpu_features().to_slice() orelse unreachable,
|
||||||
@ -1336,16 +1288,11 @@ const LldArgvBuilder = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn default_initialize() *Thread {
|
pub fn default_initialize() void {
|
||||||
assert(lib.GlobalState.initialized);
|
assert(lib.GlobalState.initialized);
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
initialize_all();
|
initialize_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
const thread = &global.threads[0];
|
|
||||||
thread.initialize();
|
|
||||||
|
|
||||||
return thread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const GenerateObject = struct {
|
pub const GenerateObject = struct {
|
||||||
|
4538
src/c_abi.c
4538
src/c_abi.c
File diff suppressed because it is too large
Load Diff
@ -51,6 +51,7 @@ const GlobalKeyword = enum {
|
|||||||
const GlobalKind = enum {
|
const GlobalKind = enum {
|
||||||
@"fn",
|
@"fn",
|
||||||
@"struct",
|
@"struct",
|
||||||
|
bits,
|
||||||
};
|
};
|
||||||
|
|
||||||
const FunctionKeyword = enum {
|
const FunctionKeyword = enum {
|
||||||
@ -71,16 +72,21 @@ const CallingConvention = enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Module = struct {
|
const Module = struct {
|
||||||
llvm: *llvm.Module,
|
llvm: LLVM,
|
||||||
di_builder: ?*llvm.DI.Builder,
|
|
||||||
global_scope: *llvm.DI.Scope = undefined,
|
|
||||||
file: *llvm.DI.File = undefined,
|
|
||||||
debug_integer_types: [8]*llvm.DI.Type = undefined,
|
|
||||||
globals: Variable.Array = .{},
|
globals: Variable.Array = .{},
|
||||||
types: Type.Array = .{},
|
types: Type.Array = .{},
|
||||||
values: Value.Array = .{},
|
values: Value.Array = .{},
|
||||||
debug_tag: c_uint = 0,
|
|
||||||
current_function: ?*Variable = null,
|
current_function: ?*Variable = null,
|
||||||
|
debug_tag: c_uint = 0,
|
||||||
|
|
||||||
|
const LLVM = struct {
|
||||||
|
context: *llvm.Context,
|
||||||
|
handle: *llvm.Module,
|
||||||
|
builder: *llvm.Builder,
|
||||||
|
di_builder: ?*llvm.DI.Builder = null,
|
||||||
|
global_scope: *llvm.DI.Scope,
|
||||||
|
file: *llvm.DI.File,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn get_type(module: *Module, index: usize) *Type {
|
pub fn get_type(module: *Module, index: usize) *Type {
|
||||||
assert(index < module.types.count);
|
assert(index < module.types.count);
|
||||||
@ -89,13 +95,18 @@ const Module = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn integer_type(module: *Module, bit_count: u32, sign: bool) *Type {
|
pub fn integer_type(module: *Module, bit_count: u32, sign: bool) *Type {
|
||||||
assert(lib.is_power_of_two(bit_count));
|
switch (bit_count) {
|
||||||
const index = @as(usize, @intFromBool(sign)) * 4 + @ctz(bit_count) - 3;
|
1...64 => {
|
||||||
const result = module.get_type(index);
|
const index = @as(usize, @intFromBool(sign)) * 64 + bit_count;
|
||||||
assert(result.bb == .integer);
|
const result = module.get_type(index);
|
||||||
assert(result.bb.integer.bit_count == bit_count);
|
assert(result.bb == .integer);
|
||||||
assert(result.bb.integer.signed == sign);
|
assert(result.bb.integer.bit_count == bit_count);
|
||||||
return result;
|
assert(result.bb.integer.signed == sign);
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
128 => @trap(),
|
||||||
|
else => @trap(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn void_type(module: *Module) *Type {
|
pub fn void_type(module: *Module) *Type {
|
||||||
@ -105,15 +116,17 @@ const Module = struct {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize(arena: *Arena, thread: *llvm.Thread, options: ConvertOptions) *Module {
|
pub fn initialize(arena: *Arena, options: ConvertOptions) *Module {
|
||||||
const module = arena.allocate_one(Module);
|
const context = llvm.Context.create();
|
||||||
const m = thread.context.create_module(options.name);
|
const handle = context.create_module(options.name);
|
||||||
module.* = Module{
|
|
||||||
.llvm = m,
|
|
||||||
.di_builder = if (options.has_debug_info) m.create_di_builder() else null,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (module.di_builder) |di_builder| {
|
var maybe_di_builder: ?*llvm.DI.Builder = null;
|
||||||
|
var global_scope: *llvm.DI.Scope = undefined;
|
||||||
|
var file: *llvm.DI.File = undefined;
|
||||||
|
|
||||||
|
if (options.has_debug_info) {
|
||||||
|
const di_builder = handle.create_di_builder();
|
||||||
|
maybe_di_builder = di_builder;
|
||||||
var directory: []const u8 = undefined;
|
var directory: []const u8 = undefined;
|
||||||
var file_name: []const u8 = undefined;
|
var file_name: []const u8 = undefined;
|
||||||
if (lib.string.last_character(options.path, '/')) |index| {
|
if (lib.string.last_character(options.path, '/')) |index| {
|
||||||
@ -122,52 +135,69 @@ const Module = struct {
|
|||||||
} else {
|
} else {
|
||||||
os.abort();
|
os.abort();
|
||||||
}
|
}
|
||||||
const file = di_builder.create_file(file_name, directory);
|
file = di_builder.create_file(file_name, directory);
|
||||||
const compile_unit = di_builder.create_compile_unit(file, options.build_mode.is_optimized());
|
const compile_unit = di_builder.create_compile_unit(file, options.build_mode.is_optimized());
|
||||||
module.global_scope = compile_unit.to_scope();
|
global_scope = compile_unit.to_scope();
|
||||||
module.file = file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const module = arena.allocate_one(Module);
|
||||||
|
module.* = .{
|
||||||
|
.llvm = .{
|
||||||
|
.global_scope = global_scope,
|
||||||
|
.file = file,
|
||||||
|
.handle = handle,
|
||||||
|
.context = context,
|
||||||
|
.builder = context.create_builder(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var llvm_integer_types: [64]*llvm.Type = undefined;
|
||||||
|
|
||||||
|
for (1..64 + 1) |bit_count| {
|
||||||
|
llvm_integer_types[bit_count - 1] = context.get_integer_type(@intCast(bit_count)).to_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
const llvm_i128 = context.get_integer_type(128).to_type();
|
||||||
|
|
||||||
|
_ = module.types.add(.{
|
||||||
|
.name = "void",
|
||||||
|
.llvm = .{
|
||||||
|
.handle = context.get_void_type(),
|
||||||
|
.debug = if (maybe_di_builder) |di_builder| di_builder.create_basic_type("void", 0, .void, .{}) else undefined,
|
||||||
|
},
|
||||||
|
.bb = .void,
|
||||||
|
});
|
||||||
|
|
||||||
for ([2]bool{ false, true }) |sign| {
|
for ([2]bool{ false, true }) |sign| {
|
||||||
for (0..4) |i| {
|
for (1..64 + 1) |bit_count| {
|
||||||
var name_buffer = [3]u8{ if (sign) 's' else 'u', 0, 0 };
|
var name_buffer = [3]u8{ if (sign) 's' else 'u', 0, 0 };
|
||||||
const bit_count = @as(u32, 1) << @intCast(3 + i);
|
var digit_buffer = [2]u8{ 0, 0 };
|
||||||
switch (bit_count) {
|
|
||||||
8 => name_buffer[1] = '8',
|
var it = bit_count;
|
||||||
16 => {
|
var i: usize = 0;
|
||||||
name_buffer[1] = '1';
|
while (it != 0) : (i += 1) {
|
||||||
name_buffer[2] = '6';
|
const digit: u8 = @intCast((it % 10) + '0');
|
||||||
},
|
digit_buffer[i] = digit;
|
||||||
32 => {
|
it = it / 10;
|
||||||
name_buffer[1] = '3';
|
|
||||||
name_buffer[2] = '2';
|
|
||||||
},
|
|
||||||
64 => {
|
|
||||||
name_buffer[1] = '6';
|
|
||||||
name_buffer[2] = '4';
|
|
||||||
},
|
|
||||||
else => unreachable,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name_buffer[1] = digit_buffer[1];
|
||||||
|
name_buffer[2] = digit_buffer[0];
|
||||||
|
|
||||||
const name_length = @as(usize, 2) + @intFromBool(bit_count > 9);
|
const name_length = @as(usize, 2) + @intFromBool(bit_count > 9);
|
||||||
|
|
||||||
const name = arena.duplicate_string(name_buffer[0..name_length]);
|
const name = arena.duplicate_string(name_buffer[0..name_length]);
|
||||||
_ = module.types.add(.{
|
_ = module.types.add(.{
|
||||||
.name = name,
|
.name = name,
|
||||||
.bb = .{
|
.bb = .{
|
||||||
.integer = .{
|
.integer = .{
|
||||||
.bit_count = bit_count,
|
.bit_count = @intCast(bit_count),
|
||||||
.signed = sign,
|
.signed = sign,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.llvm = .{
|
.llvm = .{
|
||||||
.handle = switch (bit_count) {
|
.handle = llvm_integer_types[bit_count - 1],
|
||||||
1 => thread.i1.type.to_type(),
|
.debug = if (maybe_di_builder) |di_builder| blk: {
|
||||||
8 => thread.i8.type.to_type(),
|
|
||||||
16 => thread.i16.type.to_type(),
|
|
||||||
32 => thread.i32.type.to_type(),
|
|
||||||
64 => thread.i64.type.to_type(),
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.debug = if (module.di_builder) |di_builder| blk: {
|
|
||||||
const dwarf_type: llvm.Dwarf.Type = if (bit_count == 8 and !sign) .unsigned_char else if (sign) .signed else .unsigned;
|
const dwarf_type: llvm.Dwarf.Type = if (bit_count == 8 and !sign) .unsigned_char else if (sign) .signed else .unsigned;
|
||||||
break :blk di_builder.create_basic_type(name, bit_count, dwarf_type, .{});
|
break :blk di_builder.create_basic_type(name, bit_count, dwarf_type, .{});
|
||||||
} else undefined,
|
} else undefined,
|
||||||
@ -176,6 +206,26 @@ const Module = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ([2]bool{ false, true }) |sign| {
|
||||||
|
const name = if (sign) "s128" else "u128";
|
||||||
|
_ = module.types.add(.{
|
||||||
|
.name = name,
|
||||||
|
.bb = .{
|
||||||
|
.integer = .{
|
||||||
|
.bit_count = 128,
|
||||||
|
.signed = sign,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.llvm = .{
|
||||||
|
.handle = llvm_i128,
|
||||||
|
.debug = if (maybe_di_builder) |di_builder| blk: {
|
||||||
|
const dwarf_type: llvm.Dwarf.Type = if (sign) .signed else .unsigned;
|
||||||
|
break :blk di_builder.create_basic_type(name, 128, dwarf_type, .{});
|
||||||
|
} else undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -197,6 +247,7 @@ pub const Value = struct {
|
|||||||
instruction,
|
instruction,
|
||||||
constant_integer,
|
constant_integer,
|
||||||
struct_initialization,
|
struct_initialization,
|
||||||
|
bits_initialization,
|
||||||
},
|
},
|
||||||
type: *Type,
|
type: *Type,
|
||||||
llvm: *llvm.Value,
|
llvm: *llvm.Value,
|
||||||
@ -220,6 +271,12 @@ const Field = struct {
|
|||||||
byte_offset: usize,
|
byte_offset: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FunctionType = struct {
|
||||||
|
semantic_argument_types: []const *Type,
|
||||||
|
semantic_return_type: *Type,
|
||||||
|
calling_convention: CallingConvention,
|
||||||
|
};
|
||||||
|
|
||||||
const StructType = struct {
|
const StructType = struct {
|
||||||
fields: []const Field,
|
fields: []const Field,
|
||||||
bit_size: u64,
|
bit_size: u64,
|
||||||
@ -228,10 +285,9 @@ const StructType = struct {
|
|||||||
byte_alignment: u64,
|
byte_alignment: u64,
|
||||||
};
|
};
|
||||||
|
|
||||||
const FunctionType = struct {
|
const Bits = struct {
|
||||||
semantic_argument_types: []const *Type,
|
fields: []const Field,
|
||||||
semantic_return_type: *Type,
|
backing_type: *Type,
|
||||||
calling_convention: CallingConvention,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Type = struct {
|
pub const Type = struct {
|
||||||
@ -247,6 +303,7 @@ pub const Type = struct {
|
|||||||
signed: bool,
|
signed: bool,
|
||||||
},
|
},
|
||||||
@"struct": StructType,
|
@"struct": StructType,
|
||||||
|
bits: Bits,
|
||||||
function: FunctionType,
|
function: FunctionType,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -254,6 +311,7 @@ pub const Type = struct {
|
|||||||
return switch (ty.bb) {
|
return switch (ty.bb) {
|
||||||
.integer => |integer| integer.bit_count,
|
.integer => |integer| integer.bit_count,
|
||||||
.@"struct" => |struct_type| struct_type.bit_size,
|
.@"struct" => |struct_type| struct_type.bit_size,
|
||||||
|
.bits => |bits| bits.backing_type.get_bit_size(),
|
||||||
.void, .forward_declaration, .function => unreachable,
|
.void, .forward_declaration, .function => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -262,6 +320,7 @@ pub const Type = struct {
|
|||||||
return switch (ty.bb) {
|
return switch (ty.bb) {
|
||||||
.integer => |integer| @divExact(@max(8, lib.next_power_of_two(integer.bit_count)), 8),
|
.integer => |integer| @divExact(@max(8, lib.next_power_of_two(integer.bit_count)), 8),
|
||||||
.@"struct" => |struct_type| struct_type.byte_size,
|
.@"struct" => |struct_type| struct_type.byte_size,
|
||||||
|
.bits => |bits| bits.backing_type.get_byte_size(),
|
||||||
.void, .forward_declaration, .function => unreachable,
|
.void, .forward_declaration, .function => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -270,6 +329,7 @@ pub const Type = struct {
|
|||||||
return switch (ty.bb) {
|
return switch (ty.bb) {
|
||||||
.integer => |integer| integer.bit_count,
|
.integer => |integer| integer.bit_count,
|
||||||
.@"struct" => |struct_type| struct_type.bit_alignment,
|
.@"struct" => |struct_type| struct_type.bit_alignment,
|
||||||
|
.bits => |bits| bits.backing_type.get_bit_alignment(),
|
||||||
.void, .forward_declaration, .function => unreachable,
|
.void, .forward_declaration, .function => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -277,13 +337,14 @@ pub const Type = struct {
|
|||||||
pub fn get_byte_alignment(ty: *const Type) u64 {
|
pub fn get_byte_alignment(ty: *const Type) u64 {
|
||||||
return switch (ty.bb) {
|
return switch (ty.bb) {
|
||||||
.integer => |integer| @divExact(@max(8, lib.next_power_of_two(integer.bit_count)), 8),
|
.integer => |integer| @divExact(@max(8, lib.next_power_of_two(integer.bit_count)), 8),
|
||||||
.@"struct" => |struct_type| struct_type.bit_alignment,
|
.@"struct" => |struct_type| struct_type.byte_alignment,
|
||||||
|
.bits => |bits| bits.backing_type.get_byte_alignment(),
|
||||||
.void, .forward_declaration, .function => unreachable,
|
.void, .forward_declaration, .function => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Array = struct {
|
const Array = struct {
|
||||||
buffer: [64]Type = undefined,
|
buffer: [1024]Type = undefined,
|
||||||
count: usize = 0,
|
count: usize = 0,
|
||||||
|
|
||||||
pub fn get(types: *Array) []Type {
|
pub fn get(types: *Array) []Type {
|
||||||
@ -523,7 +584,7 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias module: *Module) void {
|
fn parse_block(noalias converter: *Converter, noalias module: *Module) void {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
const current_function_global = module.current_function orelse unreachable;
|
const current_function_global = module.current_function orelse unreachable;
|
||||||
@ -534,8 +595,8 @@ const Converter = struct {
|
|||||||
const current_scope = current_function.current_scope;
|
const current_scope = current_function.current_scope;
|
||||||
defer current_function.current_scope = current_scope;
|
defer current_function.current_scope = current_scope;
|
||||||
|
|
||||||
if (module.di_builder) |di_builder| {
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
const lexical_block = di_builder.create_lexical_block(current_scope, module.file, block_line, block_column);
|
const lexical_block = di_builder.create_lexical_block(current_scope, module.llvm.file, block_line, block_column);
|
||||||
current_function.current_scope = lexical_block.to_scope();
|
current_function.current_scope = lexical_block.to_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,10 +622,10 @@ const Converter = struct {
|
|||||||
const column = converter.get_column();
|
const column = converter.get_column();
|
||||||
|
|
||||||
var statement_debug_location: *llvm.DI.Location = undefined;
|
var statement_debug_location: *llvm.DI.Location = undefined;
|
||||||
if (module.di_builder) |_| {
|
if (module.llvm.di_builder) |_| {
|
||||||
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
||||||
statement_debug_location = llvm.DI.create_debug_location(thread.context, line, column, current_function.current_scope, inlined_at);
|
statement_debug_location = llvm.DI.create_debug_location(module.llvm.context, line, column, current_function.current_scope, inlined_at);
|
||||||
thread.builder.set_current_debug_location(statement_debug_location);
|
module.llvm.builder.set_current_debug_location(statement_debug_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
const statement_start_ch = converter.content[converter.offset];
|
const statement_start_ch = converter.content[converter.offset];
|
||||||
@ -588,33 +649,33 @@ const Converter = struct {
|
|||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
if (module.di_builder) |_| {
|
if (module.llvm.di_builder) |_| {
|
||||||
thread.builder.clear_current_debug_location();
|
module.llvm.builder.clear_current_debug_location();
|
||||||
}
|
}
|
||||||
|
|
||||||
const local_storage = module.values.add();
|
const local_storage = module.values.add();
|
||||||
local_storage.* = .{
|
local_storage.* = .{
|
||||||
.llvm = thread.builder.create_alloca(local_type.llvm.handle, local_name),
|
.llvm = module.llvm.builder.create_alloca(local_type.llvm.handle, local_name),
|
||||||
.type = local_type,
|
.type = local_type,
|
||||||
.bb = .local,
|
.bb = .local,
|
||||||
};
|
};
|
||||||
|
|
||||||
const value = converter.parse_value(thread, module, local_type);
|
const value = converter.parse_value(module, local_type);
|
||||||
|
|
||||||
if (module.di_builder) |di_builder| {
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
thread.builder.set_current_debug_location(statement_debug_location);
|
module.llvm.builder.set_current_debug_location(statement_debug_location);
|
||||||
const debug_type = local_type.llvm.debug;
|
const debug_type = local_type.llvm.debug;
|
||||||
const always_preserve = true;
|
const always_preserve = true;
|
||||||
// TODO:
|
// TODO:
|
||||||
const alignment = 0;
|
const alignment = 0;
|
||||||
const flags = llvm.DI.Flags{};
|
const flags = llvm.DI.Flags{};
|
||||||
const local_variable = di_builder.create_auto_variable(current_function.current_scope, local_name, module.file, line, debug_type, always_preserve, flags, alignment);
|
const local_variable = di_builder.create_auto_variable(current_function.current_scope, local_name, module.llvm.file, line, debug_type, always_preserve, flags, alignment);
|
||||||
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
||||||
const debug_location = llvm.DI.create_debug_location(thread.context, line, column, current_function.current_scope, inlined_at);
|
const debug_location = llvm.DI.create_debug_location(module.llvm.context, line, column, current_function.current_scope, inlined_at);
|
||||||
_ = di_builder.insert_declare_record_at_end(local_storage.llvm, local_variable, di_builder.null_expression(), debug_location, current_function.current_basic_block);
|
_ = di_builder.insert_declare_record_at_end(local_storage.llvm, local_variable, di_builder.null_expression(), debug_location, current_function.current_basic_block);
|
||||||
thread.builder.set_current_debug_location(statement_debug_location);
|
module.llvm.builder.set_current_debug_location(statement_debug_location);
|
||||||
}
|
}
|
||||||
_ = thread.builder.create_store(value.llvm, local_storage.llvm);
|
_ = module.llvm.builder.create_store(value.llvm, local_storage.llvm);
|
||||||
|
|
||||||
const local = current_function.locals.add();
|
const local = current_function.locals.add();
|
||||||
local.* = .{
|
local.* = .{
|
||||||
@ -630,27 +691,27 @@ const Converter = struct {
|
|||||||
if (string_to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| {
|
if (string_to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| {
|
||||||
switch (statement_start_keyword) {
|
switch (statement_start_keyword) {
|
||||||
.@"return" => {
|
.@"return" => {
|
||||||
const return_value = converter.parse_value(thread, module, current_function_global.value.type.bb.function.semantic_return_type);
|
const return_value = converter.parse_value(module, current_function_global.value.type.bb.function.semantic_return_type);
|
||||||
thread.builder.create_ret(return_value.llvm);
|
module.llvm.builder.create_ret(return_value.llvm);
|
||||||
},
|
},
|
||||||
.@"if" => {
|
.@"if" => {
|
||||||
const taken_block = thread.context.create_basic_block("", current_function_global.value.llvm.to_function());
|
const taken_block = module.llvm.context.create_basic_block("", current_function_global.value.llvm.to_function());
|
||||||
const not_taken_block = thread.context.create_basic_block("", current_function_global.value.llvm.to_function());
|
const not_taken_block = module.llvm.context.create_basic_block("", current_function_global.value.llvm.to_function());
|
||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
converter.expect_character(left_parenthesis);
|
converter.expect_character(left_parenthesis);
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
const condition = converter.parse_value(thread, module, null);
|
const condition = converter.parse_value(module, null);
|
||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
converter.expect_character(right_parenthesis);
|
converter.expect_character(right_parenthesis);
|
||||||
|
|
||||||
_ = thread.builder.create_conditional_branch(condition.llvm, taken_block, not_taken_block);
|
_ = module.llvm.builder.create_conditional_branch(condition.llvm, taken_block, not_taken_block);
|
||||||
thread.builder.position_at_end(taken_block);
|
module.llvm.builder.position_at_end(taken_block);
|
||||||
|
|
||||||
converter.parse_block(thread, module);
|
converter.parse_block(module);
|
||||||
|
|
||||||
const is_first_block_terminated = current_function.current_basic_block.get_terminator() != null;
|
const is_first_block_terminated = current_function.current_basic_block.get_terminator() != null;
|
||||||
if (!is_first_block_terminated) {
|
if (!is_first_block_terminated) {
|
||||||
@ -670,8 +731,8 @@ const Converter = struct {
|
|||||||
|
|
||||||
var is_second_block_terminated = false;
|
var is_second_block_terminated = false;
|
||||||
if (is_else) {
|
if (is_else) {
|
||||||
thread.builder.position_at_end(not_taken_block);
|
module.llvm.builder.position_at_end(not_taken_block);
|
||||||
converter.parse_block(thread, module);
|
converter.parse_block(module);
|
||||||
is_second_block_terminated = current_function.current_basic_block.get_terminator() != null;
|
is_second_block_terminated = current_function.current_basic_block.get_terminator() != null;
|
||||||
} else {
|
} else {
|
||||||
@trap();
|
@trap();
|
||||||
@ -692,7 +753,7 @@ const Converter = struct {
|
|||||||
const variable = if (current_function.locals.find(statement_start_identifier)) |local| local else if (module.globals.find(statement_start_identifier)) |global| global else {
|
const variable = if (current_function.locals.find(statement_start_identifier)) |local| local else if (module.globals.find(statement_start_identifier)) |global| global else {
|
||||||
converter.report_error();
|
converter.report_error();
|
||||||
};
|
};
|
||||||
const call = thread.builder.create_call(variable.value.type.llvm.handle.to_function(), variable.value.llvm, &.{});
|
const call = module.llvm.builder.create_call(variable.value.type.llvm.handle.to_function(), variable.value.llvm, &.{});
|
||||||
_ = call;
|
_ = call;
|
||||||
@trap();
|
@trap();
|
||||||
} else {
|
} else {
|
||||||
@ -738,7 +799,7 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parse_value(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias module: *Module, maybe_expected_type: ?*Type) *Value {
|
fn parse_value(noalias converter: *Converter, noalias module: *Module, maybe_expected_type: ?*Type) *Value {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
var value_state = ExpressionState.none;
|
var value_state = ExpressionState.none;
|
||||||
@ -751,9 +812,14 @@ const Converter = struct {
|
|||||||
iterative_expected_type = previous_value.?.type;
|
iterative_expected_type = previous_value.?.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
const current_value = switch (converter.content[converter.offset] == left_parenthesis) {
|
const current_value = switch (converter.consume_character_if_match(left_parenthesis)) {
|
||||||
true => os.abort(),
|
true => blk: {
|
||||||
false => converter.parse_single_value(thread, module, iterative_expected_type),
|
const r = converter.parse_value(module, iterative_expected_type);
|
||||||
|
converter.skip_space();
|
||||||
|
converter.expect_character(right_parenthesis);
|
||||||
|
break :blk r;
|
||||||
|
},
|
||||||
|
false => converter.parse_single_value(module, iterative_expected_type),
|
||||||
};
|
};
|
||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
@ -766,20 +832,20 @@ const Converter = struct {
|
|||||||
|
|
||||||
const llvm_value = switch (value_state) {
|
const llvm_value = switch (value_state) {
|
||||||
.none => current_value.llvm,
|
.none => current_value.llvm,
|
||||||
.sub => thread.builder.create_sub(left.?.llvm, right.llvm),
|
.sub => module.llvm.builder.create_sub(left.?.llvm, right.llvm),
|
||||||
.add => thread.builder.create_add(left.?.llvm, right.llvm),
|
.add => module.llvm.builder.create_add(left.?.llvm, right.llvm),
|
||||||
.mul => thread.builder.create_mul(left.?.llvm, right.llvm),
|
.mul => module.llvm.builder.create_mul(left.?.llvm, right.llvm),
|
||||||
.sdiv => thread.builder.create_sdiv(left.?.llvm, right.llvm),
|
.sdiv => module.llvm.builder.create_sdiv(left.?.llvm, right.llvm),
|
||||||
.udiv => thread.builder.create_udiv(left.?.llvm, right.llvm),
|
.udiv => module.llvm.builder.create_udiv(left.?.llvm, right.llvm),
|
||||||
.srem => thread.builder.create_srem(left.?.llvm, right.llvm),
|
.srem => module.llvm.builder.create_srem(left.?.llvm, right.llvm),
|
||||||
.urem => thread.builder.create_urem(left.?.llvm, right.llvm),
|
.urem => module.llvm.builder.create_urem(left.?.llvm, right.llvm),
|
||||||
.shl => thread.builder.create_shl(left.?.llvm, right.llvm),
|
.shl => module.llvm.builder.create_shl(left.?.llvm, right.llvm),
|
||||||
.ashr => thread.builder.create_ashr(left.?.llvm, right.llvm),
|
.ashr => module.llvm.builder.create_ashr(left.?.llvm, right.llvm),
|
||||||
.lshr => thread.builder.create_lshr(left.?.llvm, right.llvm),
|
.lshr => module.llvm.builder.create_lshr(left.?.llvm, right.llvm),
|
||||||
.@"and" => thread.builder.create_and(left.?.llvm, right.llvm),
|
.@"and" => module.llvm.builder.create_and(left.?.llvm, right.llvm),
|
||||||
.@"or" => thread.builder.create_or(left.?.llvm, right.llvm),
|
.@"or" => module.llvm.builder.create_or(left.?.llvm, right.llvm),
|
||||||
.xor => thread.builder.create_xor(left.?.llvm, right.llvm),
|
.xor => module.llvm.builder.create_xor(left.?.llvm, right.llvm),
|
||||||
.icmp_ne => |icmp| thread.builder.create_compare(icmp.to_int_predicate(), left.?.llvm, right.llvm),
|
.icmp_ne => |icmp| module.llvm.builder.create_compare(icmp.to_int_predicate(), left.?.llvm, right.llvm),
|
||||||
};
|
};
|
||||||
|
|
||||||
previous_value = module.values.add();
|
previous_value = module.values.add();
|
||||||
@ -891,16 +957,60 @@ const Converter = struct {
|
|||||||
negative,
|
negative,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parse_single_value(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias module: *Module, expected_type: ?*Type) *Value {
|
const Intrinsic = enum {
|
||||||
|
extend,
|
||||||
|
foo,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn parse_intrinsic(noalias converter: *Converter, noalias module: *Module, expected_type: ?*Type) *Value {
|
||||||
|
converter.expect_character('#');
|
||||||
|
converter.skip_space();
|
||||||
|
const intrinsic_name = converter.parse_identifier();
|
||||||
|
const intrinsic_keyword = string_to_enum(Intrinsic, intrinsic_name) orelse converter.report_error();
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
converter.expect_character(left_parenthesis);
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
switch (intrinsic_keyword) {
|
||||||
|
.extend => {
|
||||||
|
const source_value = converter.parse_value(module, null);
|
||||||
|
converter.skip_space();
|
||||||
|
converter.expect_character(right_parenthesis);
|
||||||
|
const source_type = source_value.type;
|
||||||
|
const destination_type = expected_type orelse converter.report_error();
|
||||||
|
if (source_type.get_bit_size() >= destination_type.get_bit_size()) {
|
||||||
|
converter.report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
const extension_instruction = switch (source_type.bb.integer.signed) {
|
||||||
|
true => module.llvm.builder.create_sign_extend(source_value.llvm, destination_type.llvm.handle),
|
||||||
|
false => module.llvm.builder.create_zero_extend(source_value.llvm, destination_type.llvm.handle),
|
||||||
|
};
|
||||||
|
const value = module.values.add();
|
||||||
|
value.* = .{
|
||||||
|
.llvm = extension_instruction,
|
||||||
|
.type = destination_type,
|
||||||
|
.bb = .instruction,
|
||||||
|
};
|
||||||
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_single_value(noalias converter: *Converter, noalias module: *Module, expected_type: ?*Type) *Value {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
if (module.current_function) |function| {
|
if (module.current_function) |function| {
|
||||||
if (module.di_builder) |_| {
|
if (module.llvm.di_builder) |_| {
|
||||||
const line = converter.get_line();
|
const line = converter.get_line();
|
||||||
const column = converter.get_column();
|
const column = converter.get_column();
|
||||||
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
||||||
const debug_location = llvm.DI.create_debug_location(thread.context, line, column, function.value.bb.function.current_scope, inlined_at);
|
const debug_location = llvm.DI.create_debug_location(module.llvm.context, line, column, function.value.bb.function.current_scope, inlined_at);
|
||||||
thread.builder.set_current_debug_location(debug_location);
|
module.llvm.builder.set_current_debug_location(debug_location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -950,7 +1060,7 @@ const Converter = struct {
|
|||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
const field_value = converter.parse_value(thread, module, field.type);
|
const field_value = converter.parse_value(module, field.type);
|
||||||
|
|
||||||
if (must_be_constant) {
|
if (must_be_constant) {
|
||||||
if (field_index != field_count) {
|
if (field_index != field_count) {
|
||||||
@ -958,7 +1068,7 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
@trap();
|
@trap();
|
||||||
} else {
|
} else {
|
||||||
llvm_value = thread.builder.create_insert_value(llvm_value, field_value.llvm, field_index);
|
llvm_value = module.llvm.builder.create_insert_value(llvm_value, field_value.llvm, field_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
@ -984,11 +1094,65 @@ const Converter = struct {
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
|
.bits => |*bits| {
|
||||||
|
var field_count: usize = 0;
|
||||||
|
|
||||||
|
var llvm_value = bits.backing_type.llvm.handle.to_integer().get_constant(0, @intFromBool(false)).to_value();
|
||||||
|
|
||||||
|
while (converter.consume_character_if_match('.')) : (field_count += 1) {
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
const field_name = converter.parse_identifier();
|
||||||
|
const field_index: u32 = for (bits.fields, 0..) |*field, field_index| {
|
||||||
|
if (lib.string.equal(field.name, field_name)) {
|
||||||
|
break @intCast(field_index);
|
||||||
|
}
|
||||||
|
} else converter.report_error();
|
||||||
|
|
||||||
|
const field = bits.fields[field_index];
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
converter.expect_character('=');
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
const field_value = converter.parse_value(module, field.type);
|
||||||
|
|
||||||
|
const extended_field_value = module.llvm.builder.create_zero_extend(field_value.llvm, bits.backing_type.llvm.handle);
|
||||||
|
const shifted_value = module.llvm.builder.create_shl(extended_field_value, bits.backing_type.llvm.handle.to_integer().get_constant(field.bit_offset, @intFromBool(false)).to_value());
|
||||||
|
const or_value = module.llvm.builder.create_or(llvm_value, shifted_value);
|
||||||
|
llvm_value = or_value;
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
_ = converter.consume_character_if_match(',');
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_count != bits.fields.len) {
|
||||||
|
// expect: 'zero' keyword
|
||||||
|
@trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
converter.expect_character(right_brace);
|
||||||
|
|
||||||
|
const value = module.values.add();
|
||||||
|
value.* = .{
|
||||||
|
.llvm = llvm_value,
|
||||||
|
.type = ty,
|
||||||
|
.bb = .bits_initialization,
|
||||||
|
};
|
||||||
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
else => converter.report_error(),
|
else => converter.report_error(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@trap();
|
@trap();
|
||||||
},
|
},
|
||||||
|
'#' => return converter.parse_intrinsic(module, expected_type),
|
||||||
else => os.abort(),
|
else => os.abort(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1027,14 +1191,14 @@ const Converter = struct {
|
|||||||
@trap();
|
@trap();
|
||||||
},
|
},
|
||||||
.unknown => {
|
.unknown => {
|
||||||
const argument_value = converter.parse_value(thread, module, variable.value.type.bb.function.semantic_argument_types[argument_count]);
|
const argument_value = converter.parse_value(module, variable.value.type.bb.function.semantic_argument_types[argument_count]);
|
||||||
llvm_arguments[argument_count] = argument_value.llvm;
|
llvm_arguments[argument_count] = argument_value.llvm;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const llvm_argument_values = llvm_arguments[0..argument_count];
|
const llvm_argument_values = llvm_arguments[0..argument_count];
|
||||||
const llvm_call = thread.builder.create_call(variable.value.type.llvm.handle.to_function(), variable.value.llvm, llvm_argument_values);
|
const llvm_call = module.llvm.builder.create_call(variable.value.type.llvm.handle.to_function(), variable.value.llvm, llvm_argument_values);
|
||||||
llvm_call.to_instruction().set_calling_convention(variable.value.llvm.get_calling_convention());
|
llvm_call.to_instruction().set_calling_convention(variable.value.llvm.get_calling_convention());
|
||||||
const call = module.values.add();
|
const call = module.values.add();
|
||||||
call.* = .{
|
call.* = .{
|
||||||
@ -1055,22 +1219,43 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
} else converter.report_error();
|
} else converter.report_error();
|
||||||
const field = struct_type.fields[field_index];
|
const field = struct_type.fields[field_index];
|
||||||
const gep = thread.builder.create_struct_gep(variable.value.type.llvm.handle.to_struct(), variable.value.llvm, field_index);
|
const gep = module.llvm.builder.create_struct_gep(variable.value.type.llvm.handle.to_struct(), variable.value.llvm, field_index);
|
||||||
const load = module.values.add();
|
const load = module.values.add();
|
||||||
// const llvm_field_index = thread.llvminteger_type.get_constant(field_index, @intFromBool(false));
|
|
||||||
load.* = .{
|
load.* = .{
|
||||||
.llvm = thread.builder.create_load(field.type.llvm.handle, gep),
|
.llvm = module.llvm.builder.create_load(field.type.llvm.handle, gep),
|
||||||
.type = field.type,
|
.type = field.type,
|
||||||
.bb = .instruction,
|
.bb = .instruction,
|
||||||
};
|
};
|
||||||
break :b load;
|
break :b load;
|
||||||
},
|
},
|
||||||
|
.bits => |*bits| {
|
||||||
|
const field_name = converter.parse_identifier();
|
||||||
|
const field_index: u32 = for (bits.fields, 0..) |field, field_index| {
|
||||||
|
if (lib.string.equal(field.name, field_name)) {
|
||||||
|
break @intCast(field_index);
|
||||||
|
}
|
||||||
|
} else converter.report_error();
|
||||||
|
const field = bits.fields[field_index];
|
||||||
|
|
||||||
|
const bitfield_load = module.llvm.builder.create_load(bits.backing_type.llvm.handle, variable.value.llvm);
|
||||||
|
const bitfield_shifted = module.llvm.builder.create_lshr(bitfield_load, bits.backing_type.llvm.handle.to_integer().get_constant(field.bit_offset, @intFromBool(false)).to_value());
|
||||||
|
const bitfield_masked = module.llvm.builder.create_and(bitfield_shifted, bits.backing_type.llvm.handle.to_integer().get_constant((@as(u64, 1) << @intCast(field.type.get_bit_size())) - 1, @intFromBool(false)).to_value());
|
||||||
|
|
||||||
|
const value = module.values.add();
|
||||||
|
value.* = .{
|
||||||
|
.type = bits.backing_type,
|
||||||
|
.llvm = bitfield_masked,
|
||||||
|
.bb = .instruction,
|
||||||
|
};
|
||||||
|
|
||||||
|
break :b value;
|
||||||
|
},
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const load = module.values.add();
|
const load = module.values.add();
|
||||||
load.* = .{
|
load.* = .{
|
||||||
.llvm = thread.builder.create_load(variable.value.type.llvm.handle, variable.value.llvm),
|
.llvm = module.llvm.builder.create_load(variable.value.type.llvm.handle, variable.value.llvm),
|
||||||
.type = variable.value.type,
|
.type = variable.value.type,
|
||||||
.bb = .instruction,
|
.bb = .instruction,
|
||||||
};
|
};
|
||||||
@ -1154,9 +1339,9 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
.line_character_offset = 0,
|
.line_character_offset = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const thread = llvm.default_initialize();
|
llvm.default_initialize();
|
||||||
|
|
||||||
const module = Module.initialize(lib.global.arena, thread, options);
|
const module = Module.initialize(lib.global.arena, options);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
@ -1322,7 +1507,7 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
for (arguments, argument_types, debug_argument_types[1..]) |*argument, *argument_type, *debug_argument_type| {
|
for (arguments, argument_types, debug_argument_types[1..]) |*argument, *argument_type, *debug_argument_type| {
|
||||||
argument_type.* = argument.type.llvm.handle;
|
argument_type.* = argument.type.llvm.handle;
|
||||||
debug_argument_type.* = argument.type.llvm.debug;
|
debug_argument_type.* = argument.type.llvm.debug;
|
||||||
if (module.di_builder) |_| {
|
if (module.llvm.di_builder) |_| {
|
||||||
assert(@intFromPtr(argument.type.llvm.debug) != 0xaaaa_aaaa_aaaa_aaaa);
|
assert(@intFromPtr(argument.type.llvm.debug) != 0xaaaa_aaaa_aaaa_aaaa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1333,7 +1518,7 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const llvm_function_type = llvm.Type.Function.get(return_type.llvm.handle, argument_types, false);
|
const llvm_function_type = llvm.Type.Function.get(return_type.llvm.handle, argument_types, false);
|
||||||
const llvm_handle = module.llvm.create_function(.{
|
const llvm_handle = module.llvm.handle.create_function(.{
|
||||||
.name = global_name,
|
.name = global_name,
|
||||||
.linkage = switch (is_export) {
|
.linkage = switch (is_export) {
|
||||||
true => .ExternalLinkage,
|
true => .ExternalLinkage,
|
||||||
@ -1343,20 +1528,20 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
});
|
});
|
||||||
llvm_handle.set_calling_convention(calling_convention.to_llvm());
|
llvm_handle.set_calling_convention(calling_convention.to_llvm());
|
||||||
|
|
||||||
const entry_block = thread.context.create_basic_block("entry", llvm_handle);
|
const entry_block = module.llvm.context.create_basic_block("entry", llvm_handle);
|
||||||
thread.builder.position_at_end(entry_block);
|
module.llvm.builder.position_at_end(entry_block);
|
||||||
|
|
||||||
const global = module.globals.add();
|
const global = module.globals.add();
|
||||||
|
|
||||||
var subroutine_type: *llvm.DI.Type.Subroutine = undefined;
|
var subroutine_type: *llvm.DI.Type.Subroutine = undefined;
|
||||||
const current_scope: *llvm.DI.Scope = if (module.di_builder) |di_builder| blk: {
|
const current_scope: *llvm.DI.Scope = if (module.llvm.di_builder) |di_builder| blk: {
|
||||||
const subroutine_type_flags = llvm.DI.Flags{};
|
const subroutine_type_flags = llvm.DI.Flags{};
|
||||||
subroutine_type = di_builder.create_subroutine_type(module.file, debug_argument_types, subroutine_type_flags);
|
subroutine_type = di_builder.create_subroutine_type(module.llvm.file, debug_argument_types, subroutine_type_flags);
|
||||||
const scope_line: u32 = @intCast(converter.line_offset + 1);
|
const scope_line: u32 = @intCast(converter.line_offset + 1);
|
||||||
const local_to_unit = !is_export;
|
const local_to_unit = !is_export;
|
||||||
const flags = llvm.DI.Flags{};
|
const flags = llvm.DI.Flags{};
|
||||||
const is_definition = true;
|
const is_definition = true;
|
||||||
const subprogram = di_builder.create_function(module.global_scope, global_name, linkage_name, module.file, global_line, subroutine_type, local_to_unit, is_definition, scope_line, flags, options.build_mode.is_optimized());
|
const subprogram = di_builder.create_function(module.llvm.global_scope, global_name, linkage_name, module.llvm.file, global_line, subroutine_type, local_to_unit, is_definition, scope_line, flags, options.build_mode.is_optimized());
|
||||||
llvm_handle.set_subprogram(subprogram);
|
llvm_handle.set_subprogram(subprogram);
|
||||||
|
|
||||||
break :blk @ptrCast(subprogram);
|
break :blk @ptrCast(subprogram);
|
||||||
@ -1408,7 +1593,7 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
const argument_variables = global.value.bb.function.arguments.add_many(argument_count);
|
const argument_variables = global.value.bb.function.arguments.add_many(argument_count);
|
||||||
|
|
||||||
for (argument_variables, arguments) |*argument_variable, *argument| {
|
for (argument_variables, arguments) |*argument_variable, *argument| {
|
||||||
const argument_alloca = thread.builder.create_alloca(argument.type.llvm.handle, argument.name);
|
const argument_alloca = module.llvm.builder.create_alloca(argument.type.llvm.handle, argument.name);
|
||||||
const argument_value = module.values.add();
|
const argument_value = module.values.add();
|
||||||
argument_value.* = .{
|
argument_value.* = .{
|
||||||
.llvm = argument_alloca,
|
.llvm = argument_alloca,
|
||||||
@ -1429,31 +1614,31 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
switch (calling_convention) {
|
switch (calling_convention) {
|
||||||
.unknown => {
|
.unknown => {
|
||||||
for (argument_variables, llvm_arguments) |*argument_variable, llvm_argument| {
|
for (argument_variables, llvm_arguments) |*argument_variable, llvm_argument| {
|
||||||
_ = thread.builder.create_store(llvm_argument.to_value(), argument_variable.value.llvm);
|
_ = module.llvm.builder.create_store(llvm_argument.to_value(), argument_variable.value.llvm);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.c => @trap(),
|
.c => @trap(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.di_builder) |di_builder| {
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
for (argument_variables, arguments, 0..) |argument_variable, argument, argument_number| {
|
for (argument_variables, arguments, 0..) |argument_variable, argument, argument_number| {
|
||||||
const always_preserve = true;
|
const always_preserve = true;
|
||||||
const flags = llvm.DI.Flags{};
|
const flags = llvm.DI.Flags{};
|
||||||
const parameter_variable = di_builder.create_parameter_variable(global.value.bb.function.current_scope, argument_variable.name, @intCast(argument_number + 1), module.file, argument.line, argument.type.llvm.debug, always_preserve, flags);
|
const parameter_variable = di_builder.create_parameter_variable(global.value.bb.function.current_scope, argument_variable.name, @intCast(argument_number + 1), module.llvm.file, argument.line, argument.type.llvm.debug, always_preserve, flags);
|
||||||
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
||||||
const debug_location = llvm.DI.create_debug_location(thread.context, argument.line, argument.column, global.value.bb.function.current_scope, inlined_at);
|
const debug_location = llvm.DI.create_debug_location(module.llvm.context, argument.line, argument.column, global.value.bb.function.current_scope, inlined_at);
|
||||||
_ = di_builder.insert_declare_record_at_end(argument_variable.value.llvm, parameter_variable, di_builder.null_expression(), debug_location, global.value.bb.function.current_basic_block);
|
_ = di_builder.insert_declare_record_at_end(argument_variable.value.llvm, parameter_variable, di_builder.null_expression(), debug_location, global.value.bb.function.current_basic_block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
converter.parse_block(thread, module);
|
converter.parse_block(module);
|
||||||
|
|
||||||
if (module.di_builder) |di_builder| {
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
di_builder.finalize_subprogram(llvm_handle.get_subprogram());
|
di_builder.finalize_subprogram(llvm_handle.get_subprogram());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lib.optimization_mode == .Debug and module.di_builder == null) {
|
if (lib.optimization_mode == .Debug and module.llvm.di_builder == null) {
|
||||||
const verify_result = llvm_handle.verify();
|
const verify_result = llvm_handle.verify();
|
||||||
if (!verify_result.success) {
|
if (!verify_result.success) {
|
||||||
os.abort();
|
os.abort();
|
||||||
@ -1469,14 +1654,14 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
@trap();
|
@trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
const llvm_struct_type = thread.context.create_forward_declared_struct_type(global_name);
|
const llvm_struct_type = module.llvm.context.create_forward_declared_struct_type(global_name);
|
||||||
const struct_type = module.types.add(.{
|
const struct_type = module.types.add(.{
|
||||||
.name = global_name,
|
.name = global_name,
|
||||||
.bb = .forward_declaration,
|
.bb = .forward_declaration,
|
||||||
.llvm = .{
|
.llvm = .{
|
||||||
.handle = llvm_struct_type.to_type(),
|
.handle = llvm_struct_type.to_type(),
|
||||||
.debug = if (module.di_builder) |di_builder| blk: {
|
.debug = if (module.llvm.di_builder) |di_builder| blk: {
|
||||||
const r = di_builder.create_replaceable_composite_type(module.debug_tag, global_name, module.global_scope, module.file, global_line);
|
const r = di_builder.create_replaceable_composite_type(module.debug_tag, global_name, module.llvm.global_scope, module.llvm.file, global_line);
|
||||||
module.debug_tag += 1;
|
module.debug_tag += 1;
|
||||||
break :blk r.to_type();
|
break :blk r.to_type();
|
||||||
} else undefined,
|
} else undefined,
|
||||||
@ -1523,8 +1708,8 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
};
|
};
|
||||||
llvm_field_type_buffer[field_count] = field_type.llvm.handle;
|
llvm_field_type_buffer[field_count] = field_type.llvm.handle;
|
||||||
|
|
||||||
if (module.di_builder) |di_builder| {
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
const member_type = di_builder.create_member_type(module.global_scope, field_name, module.file, field_line, field_bit_size, @intCast(field_bit_alignment), field_bit_offset, .{}, field_type.llvm.debug);
|
const member_type = di_builder.create_member_type(module.llvm.global_scope, field_name, module.llvm.file, field_line, field_bit_size, @intCast(field_bit_alignment), field_bit_offset, .{}, field_type.llvm.debug);
|
||||||
llvm_debug_member_type_buffer[field_count] = member_type;
|
llvm_debug_member_type_buffer[field_count] = member_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1555,9 +1740,9 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
const element_types = llvm_field_type_buffer[0..field_count];
|
const element_types = llvm_field_type_buffer[0..field_count];
|
||||||
llvm_struct_type.set_body(element_types);
|
llvm_struct_type.set_body(element_types);
|
||||||
|
|
||||||
if (module.di_builder) |di_builder| {
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
const member_types = llvm_debug_member_type_buffer[0..field_count];
|
const member_types = llvm_debug_member_type_buffer[0..field_count];
|
||||||
const debug_struct_type = di_builder.create_struct_type(module.global_scope, global_name, module.file, global_line, bit_size, @intCast(bit_alignment), .{}, member_types);
|
const debug_struct_type = di_builder.create_struct_type(module.llvm.global_scope, global_name, module.llvm.file, global_line, bit_size, @intCast(bit_alignment), .{}, member_types);
|
||||||
const forward_declared: *llvm.DI.Type.Composite = @ptrCast(struct_type.llvm.debug);
|
const forward_declared: *llvm.DI.Type.Composite = @ptrCast(struct_type.llvm.debug);
|
||||||
forward_declared.replace_all_uses_with(debug_struct_type);
|
forward_declared.replace_all_uses_with(debug_struct_type);
|
||||||
struct_type.llvm.debug = debug_struct_type.to_type();
|
struct_type.llvm.debug = debug_struct_type.to_type();
|
||||||
@ -1573,19 +1758,103 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
.bits => {
|
||||||
|
// TODO: allow implicit backing type?
|
||||||
|
const backing_type = converter.parse_type(module);
|
||||||
|
if (backing_type.bb != .integer) {
|
||||||
|
converter.report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backing_type.get_bit_size() > 64) {
|
||||||
|
converter.report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
converter.expect_character(left_brace);
|
||||||
|
|
||||||
|
var field_buffer: [128]Field = undefined;
|
||||||
|
var llvm_debug_field_buffer: [128]*llvm.DI.Type.Derived = undefined;
|
||||||
|
var field_count: usize = 0;
|
||||||
|
|
||||||
|
var field_bit_offset: u64 = 0;
|
||||||
|
|
||||||
|
while (true) : (field_count += 1) {
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
if (converter.consume_character_if_match(right_brace)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const field_line = converter.get_line();
|
||||||
|
|
||||||
|
const field_name = converter.parse_identifier();
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
converter.expect_character(':');
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
const field_type = converter.parse_type(module);
|
||||||
|
|
||||||
|
field_buffer[field_count] = .{
|
||||||
|
.name = field_name,
|
||||||
|
.type = field_type,
|
||||||
|
.bit_offset = field_bit_offset,
|
||||||
|
.byte_offset = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const field_bit_size = field_type.get_bit_size();
|
||||||
|
field_bit_offset += field_bit_size;
|
||||||
|
|
||||||
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
|
const member_type = di_builder.create_bit_field_member_type(module.llvm.global_scope, field_name, module.llvm.file, field_line, field_bit_size, field_bit_offset, 0, .{}, backing_type.llvm.debug);
|
||||||
|
llvm_debug_field_buffer[field_count] = member_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
_ = converter.consume_character_if_match(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = converter.consume_character_if_match(';');
|
||||||
|
|
||||||
|
const fields = lib.global.arena.allocate(Field, field_count);
|
||||||
|
@memcpy(fields, field_buffer[0..field_count]);
|
||||||
|
|
||||||
|
const bit_size = backing_type.get_bit_size();
|
||||||
|
const bit_alignment = backing_type.get_bit_alignment();
|
||||||
|
|
||||||
|
const debug_member_types = llvm_debug_field_buffer[0..field_count];
|
||||||
|
|
||||||
|
_ = module.types.add(.{
|
||||||
|
.name = global_name,
|
||||||
|
.llvm = .{
|
||||||
|
.handle = backing_type.llvm.handle,
|
||||||
|
.debug = if (module.llvm.di_builder) |di_builder| di_builder.create_struct_type(module.llvm.global_scope, global_name, module.llvm.file, global_line, bit_size, @intCast(bit_alignment), .{}, debug_member_types).to_type() else undefined,
|
||||||
|
},
|
||||||
|
.bb = .{
|
||||||
|
.bits = .{
|
||||||
|
.fields = fields,
|
||||||
|
.backing_type = backing_type,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
converter.report_error();
|
converter.report_error();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (global_type) |expected_type| {
|
if (global_type) |expected_type| {
|
||||||
const value = converter.parse_value(thread, module, expected_type);
|
const value = converter.parse_value(module, expected_type);
|
||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
converter.expect_character(';');
|
converter.expect_character(';');
|
||||||
|
|
||||||
const global_variable = module.llvm.create_global_variable(.{
|
const global_variable = module.llvm.handle.create_global_variable(.{
|
||||||
.linkage = switch (is_export) {
|
.linkage = switch (is_export) {
|
||||||
true => .ExternalLinkage,
|
true => .ExternalLinkage,
|
||||||
false => .InternalLinkage,
|
false => .InternalLinkage,
|
||||||
@ -1595,11 +1864,11 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
.type = expected_type.llvm.handle,
|
.type = expected_type.llvm.handle,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (module.di_builder) |di_builder| {
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
const linkage_name = global_name;
|
const linkage_name = global_name;
|
||||||
const local_to_unit = is_export; // TODO: extern
|
const local_to_unit = is_export; // TODO: extern
|
||||||
const alignment = 0; // TODO
|
const alignment = 0; // TODO
|
||||||
const global_variable_expression = di_builder.create_global_variable(module.global_scope, global_name, linkage_name, module.file, global_line, expected_type.llvm.debug, local_to_unit, di_builder.null_expression(), alignment);
|
const global_variable_expression = di_builder.create_global_variable(module.llvm.global_scope, global_name, linkage_name, module.llvm.file, global_line, expected_type.llvm.debug, local_to_unit, di_builder.null_expression(), alignment);
|
||||||
global_variable.add_debug_info(global_variable_expression);
|
global_variable.add_debug_info(global_variable_expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1621,21 +1890,21 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.di_builder) |di_builder| {
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
di_builder.finalize();
|
di_builder.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lib.optimization_mode == .Debug) {
|
if (lib.optimization_mode == .Debug) {
|
||||||
const verify_result = module.llvm.verify();
|
const verify_result = module.llvm.handle.verify();
|
||||||
if (!verify_result.success) {
|
if (!verify_result.success) {
|
||||||
lib.print_string(module.llvm.to_string());
|
lib.print_string(module.llvm.handle.to_string());
|
||||||
lib.print_string("============================\n");
|
lib.print_string("============================\n");
|
||||||
lib.print_string(verify_result.error_message orelse unreachable);
|
lib.print_string(verify_result.error_message orelse unreachable);
|
||||||
os.abort();
|
os.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lib.is_test) {
|
if (!lib.is_test) {
|
||||||
const module_string = module.llvm.to_string();
|
const module_string = module.llvm.handle.to_string();
|
||||||
lib.print_string_stderr(module_string);
|
lib.print_string_stderr(module_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1654,7 +1923,7 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
os.abort();
|
os.abort();
|
||||||
};
|
};
|
||||||
|
|
||||||
const object_generate_result = llvm.object_generate(module.llvm, target_machine, .{
|
const object_generate_result = llvm.object_generate(module.llvm.handle, target_machine, .{
|
||||||
.optimize_when_possible = @intFromBool(@intFromEnum(options.build_mode) > @intFromEnum(BuildMode.soft_optimize)),
|
.optimize_when_possible = @intFromBool(@intFromEnum(options.build_mode) > @intFromEnum(BuildMode.soft_optimize)),
|
||||||
.debug_info = options.has_debug_info,
|
.debug_info = options.has_debug_info,
|
||||||
.optimization_level = if (options.build_mode != .debug_none) options.build_mode.to_llvm_ir() else null,
|
.optimization_level = if (options.build_mode != .debug_none) options.build_mode.to_llvm_ir() else null,
|
||||||
|
@ -160,3 +160,11 @@ test "basic_call" {
|
|||||||
test "struct" {
|
test "struct" {
|
||||||
try invsrc(@src());
|
try invsrc(@src());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "extend" {
|
||||||
|
try invsrc(@src());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "bits" {
|
||||||
|
try invsrc(@src());
|
||||||
|
}
|
||||||
|
@ -53,6 +53,8 @@ pub extern fn LLVMBuildLoad2(builder: *llvm.Builder, ty: *llvm.Type, pointer: *l
|
|||||||
pub extern fn LLVMBuildCall2(builder: *llvm.Builder, ty: *llvm.Type.Function, pointer: *llvm.Value, argument_pointer: [*]const *llvm.Value, argument_count: c_uint, name: [*:0]const u8) *llvm.Value;
|
pub extern fn LLVMBuildCall2(builder: *llvm.Builder, ty: *llvm.Type.Function, pointer: *llvm.Value, argument_pointer: [*]const *llvm.Value, argument_count: c_uint, name: [*:0]const u8) *llvm.Value;
|
||||||
pub extern fn LLVMBuildStructGEP2(builder: *llvm.Builder, struct_type: *llvm.Type.Struct, pointer: *llvm.Value, index: c_uint, name: [*:0]const u8) *llvm.Value;
|
pub extern fn LLVMBuildStructGEP2(builder: *llvm.Builder, struct_type: *llvm.Type.Struct, pointer: *llvm.Value, index: c_uint, name: [*:0]const u8) *llvm.Value;
|
||||||
pub extern fn LLVMBuildInsertValue(builder: *llvm.Builder, aggregate: *llvm.Value, element: *llvm.Value, index: c_uint, name: [*:0]const u8) *llvm.Value;
|
pub extern fn LLVMBuildInsertValue(builder: *llvm.Builder, aggregate: *llvm.Value, element: *llvm.Value, index: c_uint, name: [*:0]const u8) *llvm.Value;
|
||||||
|
pub extern fn LLVMBuildZExt(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value;
|
||||||
|
pub extern fn LLVMBuildSExt(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value;
|
||||||
|
|
||||||
pub extern fn LLVMSetCurrentDebugLocation2(builder: *llvm.Builder, location: ?*llvm.DI.Location) void;
|
pub extern fn LLVMSetCurrentDebugLocation2(builder: *llvm.Builder, location: ?*llvm.DI.Location) void;
|
||||||
|
|
||||||
@ -62,6 +64,7 @@ pub extern fn llvm_value_is_instruction(value: *llvm.Value) bool;
|
|||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
// Types: integers
|
// Types: integers
|
||||||
|
pub extern fn LLVMVoidTypeInContext(context: *llvm.Context) *llvm.Type;
|
||||||
pub extern fn LLVMInt1TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
pub extern fn LLVMInt1TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
||||||
pub extern fn LLVMInt8TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
pub extern fn LLVMInt8TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
||||||
pub extern fn LLVMInt16TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
pub extern fn LLVMInt16TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
||||||
@ -133,6 +136,7 @@ pub extern fn LLVMDIBuilderCreateLexicalBlock(builder: *llvm.DI.Builder, scope:
|
|||||||
pub extern fn LLVMDIBuilderCreateReplaceableCompositeType(builder: *llvm.DI.Builder, tag: c_uint, name_pointer: [*]const u8, name_length: usize, scope: *llvm.DI.Scope, file: *llvm.DI.File, line: c_uint, runtime_language: c_uint, bit_size: u64, align_in_bits: u32, flags: llvm.DI.Flags, unique_identifier_pointer: ?[*]const u8, unique_identifier_length: usize) *llvm.DI.Type.Composite;
|
pub extern fn LLVMDIBuilderCreateReplaceableCompositeType(builder: *llvm.DI.Builder, tag: c_uint, name_pointer: [*]const u8, name_length: usize, scope: *llvm.DI.Scope, file: *llvm.DI.File, line: c_uint, runtime_language: c_uint, bit_size: u64, align_in_bits: u32, flags: llvm.DI.Flags, unique_identifier_pointer: ?[*]const u8, unique_identifier_length: usize) *llvm.DI.Type.Composite;
|
||||||
pub extern fn LLVMDIBuilderCreateStructType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, flags: llvm.DI.Flags, derived_from: ?*llvm.DI.Type, member_pointer: [*]const *llvm.DI.Type.Derived, member_length: c_uint, runtime_language: c_uint, vtable_holder: ?*llvm.DI.Metadata, unique_id_pointer: ?[*]const u8, unique_id_length: usize) *llvm.DI.Type.Composite;
|
pub extern fn LLVMDIBuilderCreateStructType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, flags: llvm.DI.Flags, derived_from: ?*llvm.DI.Type, member_pointer: [*]const *llvm.DI.Type.Derived, member_length: c_uint, runtime_language: c_uint, vtable_holder: ?*llvm.DI.Metadata, unique_id_pointer: ?[*]const u8, unique_id_length: usize) *llvm.DI.Type.Composite;
|
||||||
pub extern fn LLVMDIBuilderCreateMemberType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, bit_offset: u64, flags: llvm.DI.Flags, member_type: *llvm.DI.Type) *llvm.DI.Type.Derived;
|
pub extern fn LLVMDIBuilderCreateMemberType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, bit_offset: u64, flags: llvm.DI.Flags, member_type: *llvm.DI.Type) *llvm.DI.Type.Derived;
|
||||||
|
pub extern fn LLVMDIBuilderCreateBitFieldMemberType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, bit_offset: u64, bit_storage_offset: u64, flags: llvm.DI.Flags, member_type: *llvm.DI.Type) *llvm.DI.Type.Derived;
|
||||||
|
|
||||||
pub extern fn LLVMMetadataReplaceAllUsesWith(forward: *llvm.DI.Type.Composite, complete: *llvm.DI.Type.Composite) void;
|
pub extern fn LLVMMetadataReplaceAllUsesWith(forward: *llvm.DI.Type.Composite, complete: *llvm.DI.Type.Composite) void;
|
||||||
|
|
||||||
|
@ -136,6 +136,11 @@ pub const panic = struct {
|
|||||||
@branchHint(.cold);
|
@branchHint(.cold);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sliceCastLenRemainder(_: usize) noreturn {
|
||||||
|
@branchHint(.cold);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int {
|
pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int {
|
||||||
|
18
tests/bits.bbb
Normal file
18
tests/bits.bbb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
BitField = bits u8
|
||||||
|
{
|
||||||
|
a: u2,
|
||||||
|
b: u2,
|
||||||
|
c: u2,
|
||||||
|
d: u2,
|
||||||
|
};
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>b: BitField = {
|
||||||
|
.a = 3,
|
||||||
|
.b = 2,
|
||||||
|
.c = 2,
|
||||||
|
.d = 3,
|
||||||
|
};
|
||||||
|
return #extend((b.a - b.d) + (b.b - b.c));
|
||||||
|
}
|
@ -13,7 +13,7 @@ BigStruct = struct
|
|||||||
e: u8,
|
e: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallPackedStruct = bitfield(u8)
|
SmallPackedStruct = bits u8
|
||||||
{
|
{
|
||||||
a: u2,
|
a: u2,
|
||||||
b: u2,
|
b: u2,
|
||||||
@ -140,6 +140,14 @@ ByVal = struct
|
|||||||
[extern] c_modify_by_ref_param = fn [cc(.c)] (x: ByRef) ByRef;
|
[extern] c_modify_by_ref_param = fn [cc(.c)] (x: ByRef) ByRef;
|
||||||
[extern] c_func_ptr_byval fn [cc(c)] (a: u64, b: u64, c: ByVal, d: u64, e: u64, f: u64) void;
|
[extern] c_func_ptr_byval fn [cc(c)] (a: u64, b: u64, c: ByVal, d: u64, e: u64, f: u64) void;
|
||||||
|
|
||||||
|
[export] require = fn [cc(c)] (ok: u8)
|
||||||
|
{
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[export] main = fn [cc(c)] () s32
|
[export] main = fn [cc(c)] () s32
|
||||||
{
|
{
|
||||||
run_c_tests();
|
run_c_tests();
|
||||||
|
5
tests/extend.bbb
Normal file
5
tests/extend.bbb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>result: s8 = 0;
|
||||||
|
return #extend(result);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user