Implement basic debug information
This commit is contained in:
parent
e6c3c55179
commit
423a559dba
281
src/LLVM.zig
281
src/LLVM.zig
@ -606,6 +606,12 @@ pub const Builder = opaque {
|
|||||||
pub fn create_load(builder: *Builder, ty: *Type, pointer: *Value) *Value {
|
pub fn create_load(builder: *Builder, ty: *Type, pointer: *Value) *Value {
|
||||||
return api.LLVMBuildLoad2(builder, ty, pointer, "");
|
return api.LLVMBuildLoad2(builder, ty, pointer, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear_current_debug_location(builder: *Builder) void {
|
||||||
|
return builder.set_current_debug_location(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const set_current_debug_location = api.LLVMSetCurrentDebugLocation2;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const GlobalValue = opaque {
|
pub const GlobalValue = opaque {
|
||||||
@ -632,6 +638,8 @@ pub const Function = opaque {
|
|||||||
result.error_message = string.to_slice();
|
result.error_message = string.to_slice();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
pub const set_subprogram = api.LLVMSetSubprogram;
|
||||||
|
pub const get_subprogram = api.LLVMGetSubprogram;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Constant = opaque {
|
pub const Constant = opaque {
|
||||||
@ -652,48 +660,107 @@ pub const Value = opaque {
|
|||||||
|
|
||||||
pub const DI = struct {
|
pub const DI = struct {
|
||||||
pub const Builder = opaque {
|
pub const Builder = opaque {
|
||||||
pub fn create_file(builder: *DI.Builder, file_name: []const u8, directory_name: []const u8) *File {
|
pub fn create_file(builder: *DI.Builder, file_name: []const u8, directory: []const u8) *File {
|
||||||
return api.LLVMCreateDIBuilder(builder, file_name.ptr, file_name.len, directory_name.ptr, directory_name.len);
|
return api.LLVMDIBuilderCreateFile(builder, String.from_slice(file_name), String.from_slice(directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_compile_unit(builder: *DI.Builder, file: *DI.File, optimized: bool) *DI.CompileUnit {
|
||||||
|
return api.LLVMDIBuilderCreateCompileUnit(builder, .C17, file, String.from_slice("bloat buster"), @intFromBool(optimized), String{}, 0, String{}, .full, 0, 0, @intFromBool(optimized), String{}, String{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const finalize = api.LLVMDIBuilderFinalize;
|
||||||
|
|
||||||
|
pub fn create_subroutine_type(builder: *DI.Builder, file: *DI.File, parameter_types: []const *DI.Type, flags: DI.Flags) *DI.Type.Subroutine {
|
||||||
|
return api.LLVMDIBuilderCreateSubroutineType(builder, file, parameter_types.ptr, @intCast(parameter_types.len), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_function(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, linkage_name: []const u8, file: *DI.File, line_number: c_uint, subroutine_type: *DI.Type.Subroutine, local_to_unit: bool, is_definition: bool, scope_line: c_uint, flags: DI.Flags, is_optimized: bool) *DI.Subprogram {
|
||||||
|
return api.LLVMDIBuilderCreateFunction(builder, scope, String.from_slice(name), String.from_slice(linkage_name), file, line_number, subroutine_type, @intFromBool(local_to_unit), @intFromBool(is_definition), scope_line, flags, @intFromBool(is_optimized));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_basic_type(builder: *DI.Builder, name: []const u8, bit_count: u64, dwarf_type: Dwarf.Type, flags: DI.Flags) *DI.Type {
|
||||||
|
return api.LLVMDIBuilderCreateBasicType(builder, name.ptr, name.len, bit_count, dwarf_type, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const finalize_subprogram = api.LLVMDIBuilderFinalizeSubprogram;
|
||||||
|
|
||||||
|
pub fn create_expression(builder: *DI.Builder, slice: []const u64) *DI.Expression {
|
||||||
|
return api.LLVMDIBuilderCreateExpression(builder, slice.ptr, slice.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn null_expression(builder: *DI.Builder) *DI.Expression {
|
||||||
|
return api.LLVMDIBuilderCreateExpression(builder, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_auto_variable(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, file: *DI.File, line: c_uint, auto_type: *DI.Type, always_preserve: bool, flags: DI.Flags, alignment_in_bits: u32) *DI.LocalVariable {
|
||||||
|
return api.LLVMDIBuilderCreateAutoVariable(builder, scope, name.ptr, name.len, file, line, auto_type, @intFromBool(always_preserve), flags, alignment_in_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const insert_declare_record_at_end = api.LLVMDIBuilderInsertDeclareRecordAtEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const create_debug_location = api.LLVMDIBuilderCreateDebugLocation;
|
||||||
|
|
||||||
|
pub const CompileUnit = opaque {
|
||||||
|
pub fn to_scope(compile_unit: *DI.CompileUnit) *DI.Scope {
|
||||||
|
return @ptrCast(compile_unit);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
pub const File = opaque {};
|
pub const File = opaque {};
|
||||||
|
pub const Scope = opaque {};
|
||||||
|
pub const Subprogram = opaque {};
|
||||||
|
pub const Expression = opaque {};
|
||||||
|
pub const LocalVariable = opaque {};
|
||||||
|
pub const Location = opaque {};
|
||||||
|
pub const Metadata = opaque {};
|
||||||
|
pub const Record = opaque {};
|
||||||
|
|
||||||
const Flags = enum(c_int) {
|
pub const Type = opaque {
|
||||||
_,
|
pub const Subroutine = opaque {};
|
||||||
const Zero = 0;
|
};
|
||||||
const Private = 1;
|
|
||||||
const Protected = 2;
|
pub const Flags = packed struct(u32) {
|
||||||
const Public = 3;
|
visibility: Visibility = .none,
|
||||||
const FwdDecl = 1 << 2;
|
forward_declaration: bool = false,
|
||||||
const AppleBlock = 1 << 3;
|
apple_block: bool = false,
|
||||||
const ReservedBit4 = 1 << 4;
|
block_by_ref_struct: bool = false,
|
||||||
const Virtual = 1 << 5;
|
virtual: bool = false,
|
||||||
const Artificial = 1 << 6;
|
artificial: bool = false,
|
||||||
const Explicit = 1 << 7;
|
explicit: bool = false,
|
||||||
const Prototyped = 1 << 8;
|
prototyped: bool = false,
|
||||||
const ObjcClassComplete = 1 << 9;
|
objective_c_class_complete: bool = false,
|
||||||
const ObjectPointer = 1 << 10;
|
object_pointer: bool = false,
|
||||||
const Vector = 1 << 11;
|
vector: bool = false,
|
||||||
const StaticMember = 1 << 12;
|
static_member: bool = false,
|
||||||
const LValueReference = 1 << 13;
|
lvalue_reference: bool = false,
|
||||||
const RValueReference = 1 << 14;
|
rvalue_reference: bool = false,
|
||||||
const Reserved = 1 << 15;
|
reserved: bool = false,
|
||||||
const SingleInheritance = 1 << 16;
|
inheritance: Inheritance = .none,
|
||||||
const MultipleInheritance = 2 << 16;
|
introduced_virtual: bool = false,
|
||||||
const VirtualInheritance = 3 << 16;
|
bit_field: bool = false,
|
||||||
const IntroducedVirtual = 1 << 18;
|
no_return: bool = false,
|
||||||
const BitField = 1 << 19;
|
type_pass_by_value: bool = false,
|
||||||
const NoReturn = 1 << 20;
|
type_pass_by_reference: bool = false,
|
||||||
const TypePassByValue = 1 << 22;
|
enum_class: bool = false,
|
||||||
const TypePassByReference = 1 << 23;
|
thunk: bool = false,
|
||||||
const EnumClass = 1 << 24;
|
non_trivial: bool = false,
|
||||||
const Thunk = 1 << 25;
|
big_endian: bool = false,
|
||||||
const NonTrivial = 1 << 26;
|
little_endian: bool = false,
|
||||||
const BigEndian = 1 << 27;
|
all_calls_described: bool = false,
|
||||||
const LittleEndian = 1 << 28;
|
_: u3 = 0,
|
||||||
const IndirectVirtualBase = (1 << 2) | (1 << 5);
|
|
||||||
const Accessibility = Private | Protected | Public;
|
const Visibility = enum(u2) {
|
||||||
const PtrToMemberRep = SingleInheritance | MultipleInheritance | VirtualInheritance;
|
none = 0,
|
||||||
|
private = 1,
|
||||||
|
protected = 2,
|
||||||
|
public = 3,
|
||||||
|
};
|
||||||
|
const Inheritance = enum(u2) {
|
||||||
|
none = 0,
|
||||||
|
single = 1,
|
||||||
|
multiple = 2,
|
||||||
|
virtual = 3,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -722,6 +789,131 @@ pub const Type = opaque {
|
|||||||
pub fn to_type(integer: *Type.Integer) *Type {
|
pub fn to_type(integer: *Type.Integer) *Type {
|
||||||
return @ptrCast(integer);
|
return @ptrCast(integer);
|
||||||
}
|
}
|
||||||
|
pub const get_bit_count = api.llvm_integer_type_get_bit_count;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Dwarf = struct {
|
||||||
|
pub const Type = enum(c_uint) {
|
||||||
|
void = 0x0,
|
||||||
|
address = 0x1,
|
||||||
|
boolean = 0x2,
|
||||||
|
complex_float = 0x3,
|
||||||
|
float = 0x4,
|
||||||
|
signed = 0x5,
|
||||||
|
signed_char = 0x6,
|
||||||
|
unsigned = 0x7,
|
||||||
|
unsigned_char = 0x8,
|
||||||
|
|
||||||
|
// DWARF 3.
|
||||||
|
imaginary_float = 0x9,
|
||||||
|
packed_decimal = 0xa,
|
||||||
|
numeric_string = 0xb,
|
||||||
|
edited = 0xc,
|
||||||
|
signed_fixed = 0xd,
|
||||||
|
unsigned_fixed = 0xe,
|
||||||
|
decimal_float = 0xf,
|
||||||
|
|
||||||
|
// DWARF 4.
|
||||||
|
UTF = 0x10,
|
||||||
|
|
||||||
|
// DWARF 5.
|
||||||
|
UCS = 0x11,
|
||||||
|
ASCII = 0x12,
|
||||||
|
|
||||||
|
// HP extensions.
|
||||||
|
HP_float80 = 0x80, // Floating-point (80 bit).
|
||||||
|
HP_complex_float80 = 0x81, // Complex floating-point (80 bit).
|
||||||
|
HP_float128 = 0x82, // Floating-point (128 bit).
|
||||||
|
HP_complex_float128 = 0x83, // Complex fp (128 bit).
|
||||||
|
HP_floathpintel = 0x84, // Floating-point (82 bit IA64).
|
||||||
|
HP_imaginary_float80 = 0x85,
|
||||||
|
HP_imaginary_float128 = 0x86,
|
||||||
|
HP_VAX_float = 0x88, // F or G floating.
|
||||||
|
HP_VAX_float_d = 0x89, // D floating.
|
||||||
|
HP_packed_decimal = 0x8a, // Cobol.
|
||||||
|
HP_zoned_decimal = 0x8b, // Cobol.
|
||||||
|
HP_edited = 0x8c, // Cobol.
|
||||||
|
HP_signed_fixed = 0x8d, // Cobol.
|
||||||
|
HP_unsigned_fixed = 0x8e, // Cobol.
|
||||||
|
HP_VAX_complex_float = 0x8f, // F or G floating complex.
|
||||||
|
HP_VAX_complex_float_d = 0x90, // D floating complex.
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const EmissionKind = enum(c_int) {
|
||||||
|
none,
|
||||||
|
full,
|
||||||
|
line_tables_only,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SourceLanguage = enum(c_int) {
|
||||||
|
C89,
|
||||||
|
C,
|
||||||
|
Ada83,
|
||||||
|
C_plus_plus,
|
||||||
|
Cobol74,
|
||||||
|
Cobol85,
|
||||||
|
Fortran77,
|
||||||
|
Fortran90,
|
||||||
|
Pascal83,
|
||||||
|
Modula2,
|
||||||
|
// New in DWARF v3:
|
||||||
|
Java,
|
||||||
|
C99,
|
||||||
|
Ada95,
|
||||||
|
Fortran95,
|
||||||
|
PLI,
|
||||||
|
ObjC,
|
||||||
|
ObjC_plus_plus,
|
||||||
|
UPC,
|
||||||
|
D,
|
||||||
|
// New in DWARF v4:
|
||||||
|
Python,
|
||||||
|
// New in DWARF v5:
|
||||||
|
OpenCL,
|
||||||
|
Go,
|
||||||
|
Modula3,
|
||||||
|
Haskell,
|
||||||
|
C_plus_plus_03,
|
||||||
|
C_plus_plus_11,
|
||||||
|
OCaml,
|
||||||
|
Rust,
|
||||||
|
C11,
|
||||||
|
Swift,
|
||||||
|
Julia,
|
||||||
|
Dylan,
|
||||||
|
C_plus_plus_14,
|
||||||
|
Fortran03,
|
||||||
|
Fortran08,
|
||||||
|
RenderScript,
|
||||||
|
BLISS,
|
||||||
|
Kotlin,
|
||||||
|
Zig,
|
||||||
|
Crystal,
|
||||||
|
C_plus_plus_17,
|
||||||
|
C_plus_plus_20,
|
||||||
|
C17,
|
||||||
|
Fortran18,
|
||||||
|
Ada2005,
|
||||||
|
Ada2012,
|
||||||
|
HIP,
|
||||||
|
Assembly,
|
||||||
|
C_sharp,
|
||||||
|
Mojo,
|
||||||
|
GLSL,
|
||||||
|
GLSL_ES,
|
||||||
|
HLSL,
|
||||||
|
OpenCL_CPP,
|
||||||
|
CPP_for_OpenCL,
|
||||||
|
SYCL,
|
||||||
|
Ruby,
|
||||||
|
Move,
|
||||||
|
Hylo,
|
||||||
|
|
||||||
|
// Vendor extensions:
|
||||||
|
Mips_Assembler,
|
||||||
|
GOOGLE_RenderScript,
|
||||||
|
BORLAND_Delphi,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -739,15 +931,6 @@ pub const LinkageType = enum(c_int) {
|
|||||||
CommonLinkage,
|
CommonLinkage,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const DwarfSourceLanguage = enum(c_int) {
|
|
||||||
c17 = 0x2c,
|
|
||||||
};
|
|
||||||
pub const DwarfEmissionKind = enum(c_int) {
|
|
||||||
none,
|
|
||||||
full,
|
|
||||||
line_tables_only,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const lld = struct {
|
pub const lld = struct {
|
||||||
pub const Result = extern struct {
|
pub const Result = extern struct {
|
||||||
stdout: String,
|
stdout: String,
|
||||||
@ -881,7 +1064,7 @@ pub const GenerateObject = struct {
|
|||||||
pub const ObjectGenerate = struct {
|
pub const ObjectGenerate = struct {
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
optimization_level: ?OptimizationLevel,
|
optimization_level: ?OptimizationLevel,
|
||||||
debug_info: u1,
|
debug_info: bool,
|
||||||
optimize_when_possible: u1,
|
optimize_when_possible: u1,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -889,7 +1072,7 @@ pub fn object_generate(module: *Module, target_machine: *Target.Machine, generat
|
|||||||
module.set_target(target_machine);
|
module.set_target(target_machine);
|
||||||
|
|
||||||
if (generate.optimization_level) |optimization_level| {
|
if (generate.optimization_level) |optimization_level| {
|
||||||
module.run_optimization_pipeline(target_machine, OptimizationPipelineOptions.default(.{ .optimization_level = optimization_level, .debug_info = generate.debug_info }));
|
module.run_optimization_pipeline(target_machine, OptimizationPipelineOptions.default(.{ .optimization_level = optimization_level, .debug_info = @intFromBool(generate.debug_info) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = module.run_code_generation_pipeline(target_machine, CodeGenerationPipelineOptions{
|
const result = module.run_code_generation_pipeline(target_machine, CodeGenerationPipelineOptions{
|
||||||
|
@ -72,6 +72,7 @@ const Local = struct {
|
|||||||
pub const FunctionBuilder = struct {
|
pub const FunctionBuilder = struct {
|
||||||
function: *llvm.Function,
|
function: *llvm.Function,
|
||||||
current_basic_block: *llvm.BasicBlock,
|
current_basic_block: *llvm.BasicBlock,
|
||||||
|
current_scope: *llvm.DI.Scope,
|
||||||
return_type: Type,
|
return_type: Type,
|
||||||
local_buffer: [64]Local = undefined,
|
local_buffer: [64]Local = undefined,
|
||||||
local_count: u32 = 0,
|
local_count: u32 = 0,
|
||||||
@ -92,11 +93,32 @@ const Type = packed struct(u64) {
|
|||||||
pub fn get(t: Type) *llvm.Type {
|
pub fn get(t: Type) *llvm.Type {
|
||||||
return @ptrFromInt(t.llvm);
|
return @ptrFromInt(t.llvm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_debug_type(ty: Type, module: *ModuleBuilder) *llvm.DI.Type {
|
||||||
|
if (ty.get().is_integer()) {
|
||||||
|
const integer_type = ty.get().to_integer();
|
||||||
|
const bit_count = integer_type.get_bit_count();
|
||||||
|
const index = (@ctz(bit_count) - 3) + (@as(u8, 4) * @intFromBool(ty.signedness));
|
||||||
|
return module.integer_types[index];
|
||||||
|
} else {
|
||||||
|
os.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Converter = struct {
|
const Converter = struct {
|
||||||
content: []const u8,
|
content: []const u8,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
|
line_offset: usize,
|
||||||
|
line_character_offset: usize,
|
||||||
|
|
||||||
|
fn get_line(converter: *const Converter) u32 {
|
||||||
|
return @intCast(converter.line_offset + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_column(converter: *const Converter) u32 {
|
||||||
|
return @intCast(converter.offset - converter.line_character_offset + 1);
|
||||||
|
}
|
||||||
|
|
||||||
fn report_error(noalias converter: *Converter) noreturn {
|
fn report_error(noalias converter: *Converter) noreturn {
|
||||||
@branchHint(.cold);
|
@branchHint(.cold);
|
||||||
@ -106,6 +128,8 @@ const Converter = struct {
|
|||||||
|
|
||||||
fn skip_space(noalias converter: *Converter) void {
|
fn skip_space(noalias converter: *Converter) void {
|
||||||
while (converter.offset < converter.content.len and is_space(converter.content[converter.offset])) {
|
while (converter.offset < converter.content.len and is_space(converter.content[converter.offset])) {
|
||||||
|
converter.line_offset += @intFromBool(converter.content[converter.offset] == '\n');
|
||||||
|
converter.line_character_offset = if (converter.content[converter.offset] == '\n') converter.offset else converter.line_character_offset;
|
||||||
converter.offset += 1;
|
converter.offset += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,13 +279,13 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias function_builder: *FunctionBuilder) void {
|
fn parse_block(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias module: *ModuleBuilder, noalias function: *FunctionBuilder) void {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
converter.expect_character(left_brace);
|
converter.expect_character(left_brace);
|
||||||
|
|
||||||
const local_offset = function_builder.local_count;
|
const local_offset = function.local_count;
|
||||||
defer function_builder.local_count = local_offset;
|
defer function.local_count = local_offset;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
@ -276,6 +300,16 @@ const Converter = struct {
|
|||||||
|
|
||||||
const require_semicolon = true;
|
const require_semicolon = true;
|
||||||
|
|
||||||
|
const line = converter.get_line();
|
||||||
|
const column = converter.get_column();
|
||||||
|
|
||||||
|
var statement_debug_location: *llvm.DI.Location = undefined;
|
||||||
|
if (module.di_builder) |_| {
|
||||||
|
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
||||||
|
statement_debug_location = llvm.DI.create_debug_location(thread.context, line, column, function.current_scope, inlined_at);
|
||||||
|
thread.builder.set_current_debug_location(statement_debug_location);
|
||||||
|
}
|
||||||
|
|
||||||
const statement_start_ch = converter.content[converter.offset];
|
const statement_start_ch = converter.content[converter.offset];
|
||||||
if (statement_start_ch == '>') {
|
if (statement_start_ch == '>') {
|
||||||
converter.offset += 1;
|
converter.offset += 1;
|
||||||
@ -297,12 +331,30 @@ const Converter = struct {
|
|||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
const value = converter.parse_value(thread, local_type, function_builder);
|
if (module.di_builder) |_| {
|
||||||
|
thread.builder.clear_current_debug_location();
|
||||||
|
}
|
||||||
const alloca = thread.builder.create_alloca(local_type.get(), local_name);
|
const alloca = thread.builder.create_alloca(local_type.get(), local_name);
|
||||||
|
|
||||||
|
const value = converter.parse_value(thread, module, function, local_type);
|
||||||
|
|
||||||
|
if (module.di_builder) |di_builder| {
|
||||||
|
thread.builder.set_current_debug_location(statement_debug_location);
|
||||||
|
const debug_type = local_type.to_debug_type(module);
|
||||||
|
const always_preserve = true;
|
||||||
|
// TODO:
|
||||||
|
const alignment = 0;
|
||||||
|
const flags = llvm.DI.Flags{};
|
||||||
|
const local_variable = di_builder.create_auto_variable(function.current_scope, local_name, module.file, line, debug_type, always_preserve, flags, alignment);
|
||||||
|
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
||||||
|
const debug_location = llvm.DI.create_debug_location(thread.context, line, column, function.current_scope, inlined_at);
|
||||||
|
_ = di_builder.insert_declare_record_at_end(alloca, local_variable, di_builder.null_expression(), debug_location, function.current_basic_block);
|
||||||
|
thread.builder.set_current_debug_location(statement_debug_location);
|
||||||
|
}
|
||||||
_ = thread.builder.create_store(value, alloca);
|
_ = thread.builder.create_store(value, alloca);
|
||||||
|
|
||||||
const local = &function_builder.local_buffer[function_builder.local_count];
|
const local = &function.local_buffer[function.local_count];
|
||||||
function_builder.local_count += 1;
|
function.local_count += 1;
|
||||||
local.* = .{
|
local.* = .{
|
||||||
.name = local_name,
|
.name = local_name,
|
||||||
.alloca = alloca,
|
.alloca = alloca,
|
||||||
@ -317,7 +369,7 @@ 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, function_builder.return_type, function_builder);
|
const return_value = converter.parse_value(thread, module, function, function.return_type);
|
||||||
thread.builder.create_ret(return_value);
|
thread.builder.create_ret(return_value);
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -356,7 +408,7 @@ const Converter = struct {
|
|||||||
xor,
|
xor,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parse_value(noalias converter: *Converter, noalias thread: *llvm.Thread, expected_type: Type, function_builder: *FunctionBuilder) *llvm.Value {
|
fn parse_value(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias module: *ModuleBuilder, noalias function: *FunctionBuilder, expected_type: Type) *llvm.Value {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
var value_state = ExpressionState.none;
|
var value_state = ExpressionState.none;
|
||||||
@ -365,7 +417,7 @@ const Converter = struct {
|
|||||||
const value = while (true) {
|
const value = while (true) {
|
||||||
const current_value = switch (converter.content[converter.offset] == left_parenthesis) {
|
const current_value = switch (converter.content[converter.offset] == left_parenthesis) {
|
||||||
true => os.abort(),
|
true => os.abort(),
|
||||||
false => converter.parse_single_value(thread, expected_type, function_builder),
|
false => converter.parse_single_value(thread, module, function, expected_type),
|
||||||
};
|
};
|
||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
@ -470,9 +522,17 @@ const Converter = struct {
|
|||||||
negative,
|
negative,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parse_single_value(noalias converter: *Converter, thread: *llvm.Thread, expected_type: Type, noalias function_builder: *FunctionBuilder) *llvm.Value {
|
fn parse_single_value(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias module: *ModuleBuilder, noalias function: *FunctionBuilder, expected_type: Type) *llvm.Value {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
|
if (module.di_builder) |_| {
|
||||||
|
const line = converter.get_line();
|
||||||
|
const column = converter.get_column();
|
||||||
|
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
||||||
|
const debug_location = llvm.DI.create_debug_location(thread.context, line, column, function.current_scope, inlined_at);
|
||||||
|
thread.builder.set_current_debug_location(debug_location);
|
||||||
|
}
|
||||||
|
|
||||||
const prefix_offset = converter.offset;
|
const prefix_offset = converter.offset;
|
||||||
const prefix_ch = converter.content[prefix_offset];
|
const prefix_ch = converter.content[prefix_offset];
|
||||||
const prefix: Prefix = switch (prefix_ch) {
|
const prefix: Prefix = switch (prefix_ch) {
|
||||||
@ -492,7 +552,7 @@ const Converter = struct {
|
|||||||
const value = switch (value_start_ch) {
|
const value = switch (value_start_ch) {
|
||||||
'a'...'z', 'A'...'Z', '_' => b: {
|
'a'...'z', 'A'...'Z', '_' => b: {
|
||||||
const identifier = converter.parse_identifier();
|
const identifier = converter.parse_identifier();
|
||||||
for (function_builder.local_buffer[0..function_builder.local_count]) |*local| {
|
for (function.local_buffer[0..function.local_count]) |*local| {
|
||||||
if (lib.string.equal(identifier, local.name)) {
|
if (lib.string.equal(identifier, local.name)) {
|
||||||
break :b thread.builder.create_load(local.type.get(), local.alloca);
|
break :b thread.builder.create_load(local.type.get(), local.alloca);
|
||||||
}
|
}
|
||||||
@ -527,6 +587,10 @@ pub const BuildMode = enum {
|
|||||||
aggressively_optimize_for_speed,
|
aggressively_optimize_for_speed,
|
||||||
aggressively_optimize_for_size,
|
aggressively_optimize_for_size,
|
||||||
|
|
||||||
|
fn is_optimized(build_mode: BuildMode) bool {
|
||||||
|
return @intFromEnum(build_mode) >= @intFromEnum(BuildMode.soft_optimize);
|
||||||
|
}
|
||||||
|
|
||||||
fn to_llvm_ir(build_mode: BuildMode) llvm.OptimizationLevel {
|
fn to_llvm_ir(build_mode: BuildMode) llvm.OptimizationLevel {
|
||||||
return switch (build_mode) {
|
return switch (build_mode) {
|
||||||
.debug_none => unreachable,
|
.debug_none => unreachable,
|
||||||
@ -559,17 +623,77 @@ const ConvertOptions = struct {
|
|||||||
executable: [:0]const u8,
|
executable: [:0]const u8,
|
||||||
build_mode: BuildMode,
|
build_mode: BuildMode,
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
has_debug_info: u1,
|
has_debug_info: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ModuleBuilder = struct {
|
||||||
|
handle: *llvm.Module,
|
||||||
|
di_builder: ?*llvm.DI.Builder,
|
||||||
|
global_scope: *llvm.DI.Scope,
|
||||||
|
file: *llvm.DI.File,
|
||||||
|
integer_types: [8]*llvm.DI.Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub noinline fn convert(options: ConvertOptions) void {
|
pub noinline fn convert(options: ConvertOptions) void {
|
||||||
var converter = Converter{
|
var converter = Converter{
|
||||||
.content = options.content,
|
.content = options.content,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
|
.line_offset = 0,
|
||||||
|
.line_character_offset = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const thread = llvm.default_initialize();
|
const thread = llvm.default_initialize();
|
||||||
const module = thread.context.create_module(options.name);
|
|
||||||
|
const m = thread.context.create_module(options.name);
|
||||||
|
var module = ModuleBuilder{
|
||||||
|
.handle = m,
|
||||||
|
.di_builder = if (options.has_debug_info) m.create_di_builder() else null,
|
||||||
|
.global_scope = undefined,
|
||||||
|
.file = undefined,
|
||||||
|
.integer_types = undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (module.di_builder) |di_builder| {
|
||||||
|
var directory: []const u8 = undefined;
|
||||||
|
var file_name: []const u8 = undefined;
|
||||||
|
if (lib.string.last_character(options.path, '/')) |index| {
|
||||||
|
directory = options.path[0..index];
|
||||||
|
file_name = options.path[index + 1 ..];
|
||||||
|
} else {
|
||||||
|
os.abort();
|
||||||
|
}
|
||||||
|
const file = di_builder.create_file(file_name, directory);
|
||||||
|
const compile_unit = di_builder.create_compile_unit(file, options.build_mode.is_optimized());
|
||||||
|
module.global_scope = compile_unit.to_scope();
|
||||||
|
module.file = file;
|
||||||
|
|
||||||
|
for ([2]bool{ false, true }) |sign| {
|
||||||
|
for (0..4) |i| {
|
||||||
|
var name_buffer = [3]u8{ if (sign) 's' else 'u', 0, 0 };
|
||||||
|
const bit_count = @as(u64, 1) << @intCast(3 + i);
|
||||||
|
switch (bit_count) {
|
||||||
|
8 => name_buffer[1] = '8',
|
||||||
|
16 => {
|
||||||
|
name_buffer[1] = '1';
|
||||||
|
name_buffer[2] = '6';
|
||||||
|
},
|
||||||
|
32 => {
|
||||||
|
name_buffer[1] = '3';
|
||||||
|
name_buffer[2] = '2';
|
||||||
|
},
|
||||||
|
64 => {
|
||||||
|
name_buffer[1] = '6';
|
||||||
|
name_buffer[2] = '4';
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
const name_length = @as(usize, 2) + @intFromBool(bit_count > 9);
|
||||||
|
const name = name_buffer[0..name_length];
|
||||||
|
const dwarf_type: llvm.Dwarf.Type = if (bit_count == 8 and !sign) .unsigned_char else if (sign) .signed else .unsigned;
|
||||||
|
module.integer_types[i + @as(usize, 4) * @intFromBool(sign)] = di_builder.create_basic_type(name, bit_count, dwarf_type, .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
@ -580,6 +704,8 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
|
|
||||||
var is_export = false;
|
var is_export = false;
|
||||||
|
|
||||||
|
const global_line_offset = converter.line_offset;
|
||||||
|
|
||||||
if (converter.content[converter.offset] == left_bracket) {
|
if (converter.content[converter.offset] == left_bracket) {
|
||||||
converter.offset += 1;
|
converter.offset += 1;
|
||||||
|
|
||||||
@ -673,7 +799,7 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
const return_type = converter.parse_type(thread);
|
const return_type = converter.parse_type(thread);
|
||||||
const function_type = llvm.Type.Function.get(return_type.get(), &.{}, false);
|
const function_type = llvm.Type.Function.get(return_type.get(), &.{}, false);
|
||||||
|
|
||||||
const function = module.create_function(.{
|
const handle = module.handle.create_function(.{
|
||||||
.name = global_name,
|
.name = global_name,
|
||||||
.linkage = switch (is_export) {
|
.linkage = switch (is_export) {
|
||||||
true => .ExternalLinkage,
|
true => .ExternalLinkage,
|
||||||
@ -682,19 +808,39 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
.type = function_type,
|
.type = function_type,
|
||||||
});
|
});
|
||||||
|
|
||||||
const entry_block = thread.context.create_basic_block("entry", function);
|
const entry_block = thread.context.create_basic_block("entry", handle);
|
||||||
thread.builder.position_at_end(entry_block);
|
thread.builder.position_at_end(entry_block);
|
||||||
|
|
||||||
var function_builder = FunctionBuilder{
|
var function = FunctionBuilder{
|
||||||
.function = function,
|
.function = handle,
|
||||||
.current_basic_block = entry_block,
|
.current_basic_block = entry_block,
|
||||||
.return_type = return_type,
|
.return_type = return_type,
|
||||||
|
.current_scope = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
converter.parse_block(thread, &function_builder);
|
if (module.di_builder) |di_builder| {
|
||||||
|
const debug_return_type = return_type.to_debug_type(&module);
|
||||||
|
const subroutine_type = di_builder.create_subroutine_type(module.file, &.{debug_return_type}, .{});
|
||||||
|
const linkage_name = global_name;
|
||||||
|
const line: u32 = @intCast(global_line_offset + 1);
|
||||||
|
const scope_line: u32 = @intCast(converter.line_offset + 1);
|
||||||
|
const local_to_unit = !is_export;
|
||||||
|
const flags = llvm.DI.Flags{};
|
||||||
|
const is_definition = true;
|
||||||
|
const subprogram = di_builder.create_function(module.global_scope, global_name, linkage_name, module.file, line, subroutine_type, local_to_unit, is_definition, scope_line, flags, options.build_mode.is_optimized());
|
||||||
|
handle.set_subprogram(subprogram);
|
||||||
|
|
||||||
if (lib.optimization_mode == .Debug) {
|
function.current_scope = @ptrCast(subprogram);
|
||||||
const verify_result = function.verify();
|
}
|
||||||
|
|
||||||
|
converter.parse_block(thread, &module, &function);
|
||||||
|
|
||||||
|
if (module.di_builder) |di_builder| {
|
||||||
|
di_builder.finalize_subprogram(handle.get_subprogram());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lib.optimization_mode == .Debug and module.di_builder == null) {
|
||||||
|
const verify_result = handle.verify();
|
||||||
if (!verify_result.success) {
|
if (!verify_result.success) {
|
||||||
os.abort();
|
os.abort();
|
||||||
}
|
}
|
||||||
@ -704,14 +850,18 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (module.di_builder) |di_builder| {
|
||||||
|
di_builder.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
if (lib.optimization_mode == .Debug) {
|
if (lib.optimization_mode == .Debug) {
|
||||||
const verify_result = module.verify();
|
const verify_result = module.handle.verify();
|
||||||
if (!verify_result.success) {
|
if (!verify_result.success) {
|
||||||
os.abort();
|
os.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lib.is_test) {
|
if (!lib.is_test) {
|
||||||
const module_string = module.to_string();
|
const module_string = module.handle.to_string();
|
||||||
lib.print_string_stderr(module_string);
|
lib.print_string_stderr(module_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -730,7 +880,7 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
os.abort();
|
os.abort();
|
||||||
};
|
};
|
||||||
|
|
||||||
const object_generate_result = llvm.object_generate(module, target_machine, .{
|
const object_generate_result = llvm.object_generate(module.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,
|
||||||
|
@ -15,7 +15,7 @@ fn invoke(name: []const u8) !void {
|
|||||||
|
|
||||||
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
|
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
|
||||||
const build_mode = @field(BuildMode, f.name);
|
const build_mode = @field(BuildMode, f.name);
|
||||||
inline for ([2]u1{ 0, 1 }) |has_debug_info| {
|
inline for ([2]bool{ false, true }) |has_debug_info| {
|
||||||
var tmp_dir = std.testing.tmpDir(.{});
|
var tmp_dir = std.testing.tmpDir(.{});
|
||||||
defer tmp_dir.cleanup();
|
defer tmp_dir.cleanup();
|
||||||
const base_path = lib.global.arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
|
const base_path = lib.global.arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
|
||||||
@ -61,11 +61,11 @@ const InvokeWrapper = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// We invoke a function with comptime parameters so it's easily visible in CI stack traces
|
// We invoke a function with comptime parameters so it's easily visible in CI stack traces
|
||||||
fn invoke_wrapper(options: InvokeWrapper, comptime build_mode: BuildMode, comptime has_debug_info: u1) void {
|
fn invoke_wrapper(options: InvokeWrapper, comptime build_mode: BuildMode, comptime has_debug_info: bool) void {
|
||||||
return invoke_single(options, build_mode, has_debug_info);
|
return invoke_single(options, build_mode, has_debug_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invoke_single(options: InvokeWrapper, build_mode: BuildMode, has_debug_info: u1) void {
|
fn invoke_single(options: InvokeWrapper, build_mode: BuildMode, has_debug_info: bool) void {
|
||||||
const file_content = lib.file.read(lib.global.arena, options.file_path);
|
const file_content = lib.file.read(lib.global.arena, options.file_path);
|
||||||
|
|
||||||
converter.convert(.{
|
converter.convert(.{
|
||||||
|
14
src/lib.zig
14
src/lib.zig
@ -518,11 +518,25 @@ pub const os = struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn absolute_path_stack(noalias buffer: []u8, noalias relative_path: [*:0]const u8) [:0]const u8 {
|
||||||
|
const real_path = libc.realpath(relative_path, buffer.ptr) orelse unreachable;
|
||||||
|
const result = cstring.to_slice(real_path);
|
||||||
|
assert(result.len < buffer.len);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn absolute_path(arena: *Arena, noalias relative_path: [*:0]const u8) [:0]const u8 {
|
||||||
|
// TODO: pick a more correct number
|
||||||
|
var buffer: [4096]u8 = undefined;
|
||||||
|
return arena.duplicate_string(absolute_path_stack(&buffer, relative_path));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const libc = struct {
|
pub const libc = struct {
|
||||||
pub extern "c" fn exit(c_int) noreturn;
|
pub extern "c" fn exit(c_int) noreturn;
|
||||||
pub extern "c" fn memcmp(a: [*]const u8, b: [*]const u8, byte_count: usize) c_int;
|
pub extern "c" fn memcmp(a: [*]const u8, b: [*]const u8, byte_count: usize) c_int;
|
||||||
|
pub extern "c" fn realpath(noalias path: [*:0]const u8, noalias resolved_path: [*]u8) ?[*:0]const u8;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const string = struct {
|
pub const string = struct {
|
||||||
|
@ -65,6 +65,12 @@ EXPORT bool llvm_type_is_integer(const Type& type)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT unsigned llvm_integer_type_get_bit_count(const IntegerType& integer_type)
|
||||||
|
{
|
||||||
|
auto result = integer_type.getBitWidth();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT Function* llvm_module_create_function(Module* module, FunctionType* function_type, GlobalValue::LinkageTypes linkage_type, unsigned address_space, BBLLVMString name)
|
EXPORT Function* llvm_module_create_function(Module* module, FunctionType* function_type, GlobalValue::LinkageTypes linkage_type, unsigned address_space, BBLLVMString name)
|
||||||
{
|
{
|
||||||
auto* function = Function::Create(function_type, linkage_type, address_space, name.string_ref(), module);
|
auto* function = Function::Create(function_type, linkage_type, address_space, name.string_ref(), module);
|
||||||
|
@ -37,6 +37,8 @@ pub extern fn llvm_builder_create_alloca(builder: *llvm.Builder, ty: *llvm.Type,
|
|||||||
pub extern fn LLVMBuildStore(builder: *llvm.Builder, value: *llvm.Value, pointer: *llvm.Value) *llvm.Value;
|
pub extern fn LLVMBuildStore(builder: *llvm.Builder, value: *llvm.Value, pointer: *llvm.Value) *llvm.Value;
|
||||||
pub extern fn LLVMBuildLoad2(builder: *llvm.Builder, ty: *llvm.Type, pointer: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
pub extern fn LLVMBuildLoad2(builder: *llvm.Builder, ty: *llvm.Type, pointer: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
||||||
|
|
||||||
|
pub extern fn LLVMSetCurrentDebugLocation2(builder: *llvm.Builder, location: ?*llvm.DI.Location) void;
|
||||||
|
|
||||||
pub extern fn LLVMTypeOf(value: *llvm.Value) *llvm.Type;
|
pub extern fn LLVMTypeOf(value: *llvm.Value) *llvm.Type;
|
||||||
pub extern fn LLVMGlobalGetValueType(value: *llvm.GlobalValue) *llvm.Type;
|
pub extern fn LLVMGlobalGetValueType(value: *llvm.GlobalValue) *llvm.Type;
|
||||||
|
|
||||||
@ -61,6 +63,8 @@ pub extern fn LLVMFP128TypeInContext(context: *llvm.Context) *llvm.Type;
|
|||||||
pub extern fn LLVMFunctionType(return_type: *llvm.Type, parameter_type_pointer: [*]const *llvm.Type, parameter_type_count: c_uint, is_var_arg: Bool) *llvm.Type.Function;
|
pub extern fn LLVMFunctionType(return_type: *llvm.Type, parameter_type_pointer: [*]const *llvm.Type, parameter_type_count: c_uint, is_var_arg: Bool) *llvm.Type.Function;
|
||||||
pub extern fn LLVMIsFunctionVarArg(function_type: *llvm.Type.Function) Bool;
|
pub extern fn LLVMIsFunctionVarArg(function_type: *llvm.Type.Function) Bool;
|
||||||
pub extern fn LLVMGetReturnType(function_type: *llvm.Type.Function) *llvm.Type;
|
pub extern fn LLVMGetReturnType(function_type: *llvm.Type.Function) *llvm.Type;
|
||||||
|
pub extern fn LLVMSetSubprogram(function: *llvm.Function, subprogram: *llvm.DI.Subprogram) void;
|
||||||
|
pub extern fn LLVMGetSubprogram(function: *llvm.Function) *llvm.DI.Subprogram;
|
||||||
pub extern fn LLVMCountParamTypes(function_type: *llvm.Type.Function) c_uint;
|
pub extern fn LLVMCountParamTypes(function_type: *llvm.Type.Function) c_uint;
|
||||||
pub extern fn LLVMGetParamTypes(function_type: *llvm.Type.Function, types: [*]*llvm.Type) void;
|
pub extern fn LLVMGetParamTypes(function_type: *llvm.Type.Function, types: [*]*llvm.Type) void;
|
||||||
|
|
||||||
@ -81,14 +85,24 @@ pub extern fn LLVMScalableVectorType(element_type: *llvm.Type, element_count: c_
|
|||||||
pub extern fn llvm_type_is_function(ty: *llvm.Type) bool;
|
pub extern fn llvm_type_is_function(ty: *llvm.Type) bool;
|
||||||
pub extern fn llvm_type_is_integer(ty: *llvm.Type) bool;
|
pub extern fn llvm_type_is_integer(ty: *llvm.Type) bool;
|
||||||
|
|
||||||
|
pub extern fn llvm_integer_type_get_bit_count(integer_type: *llvm.Type.Integer) c_uint;
|
||||||
|
|
||||||
// VALUES
|
// VALUES
|
||||||
pub extern fn LLVMConstInt(type: *llvm.Type.Integer, value: c_ulonglong, sign_extend: Bool) *llvm.Constant.Integer;
|
pub extern fn LLVMConstInt(type: *llvm.Type.Integer, value: c_ulonglong, sign_extend: Bool) *llvm.Constant.Integer;
|
||||||
|
|
||||||
// Debug info API
|
// Debug info API
|
||||||
pub extern fn LLVMCreateDIBuilder(module: *llvm.Module) *llvm.DI.Builder;
|
pub extern fn LLVMCreateDIBuilder(module: *llvm.Module) *llvm.DI.Builder;
|
||||||
|
pub extern fn LLVMDIBuilderFinalize(builder: *llvm.DI.Builder) void;
|
||||||
pub extern fn LLVMDIBuilderCreateFile(builder: *llvm.DI.Builder, file_name: llvm.String, directory_name: llvm.String) *llvm.DI.File;
|
pub extern fn LLVMDIBuilderCreateFile(builder: *llvm.DI.Builder, file_name: llvm.String, directory_name: llvm.String) *llvm.DI.File;
|
||||||
pub extern fn LLVMDIBuilderCreateCompileUnit(builder: *llvm.DI.Builder, language: llvm.DwarfSourceLanguage, file: *llvm.DI.File, producer_name: llvm.String, optimized: Bool, flags: llvm.String, runtime_version: c_uint, split_name: llvm.String, dwarf_emission_kind: llvm.DwarfEmissionKind, debug_with_offset_id: c_uint, split_debug_inlining: Bool, debug_info_for_profiling: Bool, sysroot: llvm.String, sdk: llvm.String) *llvm.DI.CompileUnit;
|
pub extern fn LLVMDIBuilderCreateCompileUnit(builder: *llvm.DI.Builder, language: llvm.Dwarf.SourceLanguage, file: *llvm.DI.File, producer_name: llvm.String, optimized: Bool, flags: llvm.String, runtime_version: c_uint, split_name: llvm.String, dwarf_emission_kind: llvm.Dwarf.EmissionKind, debug_with_offset_id: c_uint, split_debug_inlining: Bool, debug_info_for_profiling: Bool, sysroot: llvm.String, sdk: llvm.String) *llvm.DI.CompileUnit;
|
||||||
|
pub extern fn LLVMDIBuilderCreateSubroutineType(builder: *llvm.DI.Builder, file: *llvm.DI.File, parameter_type_pointer: [*]const *llvm.DI.Type, parameter_type_count: c_uint, flags: llvm.DI.Flags) *llvm.DI.Type.Subroutine;
|
||||||
pub extern fn LLVMDIBuilderCreateFunction(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name: llvm.String, linkage_name: llvm.String, file: *llvm.DI.File, line_number: c_uint, type: *llvm.DI.Type.Subroutine, local_to_unit: Bool, is_definition: Bool, scope_line: c_uint, flags: llvm.DI.Flags, is_optimized: Bool) *llvm.DI.Subprogram;
|
pub extern fn LLVMDIBuilderCreateFunction(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name: llvm.String, linkage_name: llvm.String, file: *llvm.DI.File, line_number: c_uint, type: *llvm.DI.Type.Subroutine, local_to_unit: Bool, is_definition: Bool, scope_line: c_uint, flags: llvm.DI.Flags, is_optimized: Bool) *llvm.DI.Subprogram;
|
||||||
|
pub extern fn LLVMDIBuilderFinalizeSubprogram(builder: *llvm.DI.Builder, subprogram: *llvm.DI.Subprogram) void;
|
||||||
|
pub extern fn LLVMDIBuilderCreateExpression(builder: *llvm.DI.Builder, address: ?[*]const u64, length: u64) *llvm.DI.Expression;
|
||||||
|
pub extern fn LLVMDIBuilderCreateDebugLocation(context: *llvm.Context, line: c_uint, column: c_uint, scope: *llvm.DI.Scope, inlined_at: ?*llvm.DI.Metadata) *llvm.DI.Location;
|
||||||
|
pub extern fn LLVMDIBuilderCreateBasicType(builder: *llvm.DI.Builder, name_pointer: [*]const u8, name_length: usize, bit_count: u64, dwarf_type: llvm.Dwarf.Type, flags: llvm.DI.Flags) *llvm.DI.Type;
|
||||||
|
pub extern fn LLVMDIBuilderCreateAutoVariable(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, type: *llvm.DI.Type, always_preserve: Bool, flags: llvm.DI.Flags, align_in_bits: u32) *llvm.DI.LocalVariable;
|
||||||
|
pub extern fn LLVMDIBuilderInsertDeclareRecordAtEnd(builder: *llvm.DI.Builder, storage: *llvm.Value, local_variable: *llvm.DI.LocalVariable, expression: *llvm.DI.Expression, debug_location: *llvm.DI.Location, basic_block: *llvm.BasicBlock) *llvm.DI.Record;
|
||||||
|
|
||||||
// Target
|
// Target
|
||||||
pub extern fn llvm_default_target_triple() llvm.String;
|
pub extern fn llvm_default_target_triple() llvm.String;
|
||||||
|
21
src/main.zig
21
src/main.zig
@ -142,19 +142,19 @@ pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int
|
|||||||
lib.print_string("Failed to match argument count");
|
lib.print_string("Failed to match argument count");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
const file_path_pointer = argv[1] orelse return 1;
|
const relative_file_path_pointer = argv[1] orelse return 1;
|
||||||
const file_path = lib.cstring.to_slice(file_path_pointer);
|
const relative_file_path = lib.cstring.to_slice(relative_file_path_pointer);
|
||||||
if (file_path.len < 5) {
|
if (relative_file_path.len < 5) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const extension_start = lib.string.last_character(file_path, '.') orelse return 1;
|
const extension_start = lib.string.last_character(relative_file_path, '.') orelse return 1;
|
||||||
if (!lib.string.equal(file_path[extension_start..], ".bbb")) {
|
if (!lib.string.equal(relative_file_path[extension_start..], ".bbb")) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
const separator_index = lib.string.last_character(file_path, '/') orelse 0;
|
const separator_index = lib.string.last_character(relative_file_path, '/') orelse 0;
|
||||||
const base_start = separator_index + @intFromBool(separator_index != 0 or file_path[separator_index] == '/');
|
const base_start = separator_index + @intFromBool(separator_index != 0 or relative_file_path[separator_index] == '/');
|
||||||
const base_name = file_path[base_start..extension_start];
|
const base_name = relative_file_path[base_start..extension_start];
|
||||||
|
|
||||||
lib.GlobalState.initialize();
|
lib.GlobalState.initialize();
|
||||||
|
|
||||||
@ -166,7 +166,8 @@ pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int
|
|||||||
const output_object_path = arena.join_string(&.{ output_path_base, ".o" });
|
const output_object_path = arena.join_string(&.{ output_path_base, ".o" });
|
||||||
const output_executable_path = output_path_base;
|
const output_executable_path = output_path_base;
|
||||||
|
|
||||||
const file_content = lib.file.read(arena, file_path);
|
const file_content = lib.file.read(arena, relative_file_path);
|
||||||
|
const file_path = os.absolute_path(arena, relative_file_path);
|
||||||
converter.convert(.{
|
converter.convert(.{
|
||||||
.executable = output_executable_path,
|
.executable = output_executable_path,
|
||||||
.object = output_object_path,
|
.object = output_object_path,
|
||||||
@ -174,7 +175,7 @@ pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int
|
|||||||
.build_mode = .debug_none,
|
.build_mode = .debug_none,
|
||||||
.content = file_content,
|
.content = file_content,
|
||||||
.path = file_path,
|
.path = file_path,
|
||||||
.has_debug_info = 1,
|
.has_debug_info = true,
|
||||||
});
|
});
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user