From e290f61890652948bed9f784dcc18579484063da Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Tue, 25 Feb 2025 09:26:45 -0600 Subject: [PATCH] Basic array --- src/LLVM.zig | 32 ++++ src/converter.zig | 404 ++++++++++++++++++++++++++++------------- src/converter_test.zig | 4 + src/lib.zig | 5 + src/llvm_api.zig | 4 + tests/basic_array.bbb | 5 + 6 files changed, 332 insertions(+), 122 deletions(-) create mode 100644 tests/basic_array.bbb diff --git a/src/LLVM.zig b/src/LLVM.zig index 3a64b6b..70ae75c 100644 --- a/src/LLVM.zig +++ b/src/LLVM.zig @@ -490,10 +490,13 @@ const targets = [@typeInfo(Architecture).@"enum".fields.len]type{ pub const Context = opaque { pub const create = api.LLVMContextCreate; + pub fn create_module(context: *Context, name: []const u8) *Module { return api.llvm_context_create_module(context, String.from_slice(name)); } + pub const create_builder = api.LLVMCreateBuilderInContext; + pub fn create_basic_block(context: *Context, name: []const u8, parent: *Function) *BasicBlock { return api.llvm_context_create_basic_block(context, String.from_slice(name), parent); } @@ -501,6 +504,7 @@ pub const Context = opaque { pub fn create_forward_declared_struct_type(context: *Context, name: []const u8) *Type.Struct { return api.llvm_context_create_forward_declared_struct_type(context, String.from_slice(name)); } + pub fn create_struct_type(context: *Context, element_types: []const *Type, name: []const u8) *Type.Struct { const is_packed = false; return api.llvm_context_create_struct_type(context, element_types.ptr, @intCast(element_types.len), String.from_slice(name), is_packed); @@ -658,6 +662,10 @@ pub const Builder = opaque { return api.LLVMBuildStructGEP2(builder, struct_type, pointer, index, ""); } + pub fn create_gep(builder: *Builder, ty: *Type, aggregate: *Value, indices: []const *Value) *Value { + return api.LLVMBuildInBoundsGEP2(builder, ty, aggregate, indices.ptr, @intCast(indices.len), ""); + } + pub fn create_insert_value(builder: *Builder, aggregate: *Value, element: *Value, index: c_uint) *Value { return api.LLVMBuildInsertValue(builder, aggregate, element, index, ""); } @@ -725,6 +733,12 @@ pub const Constant = opaque { return @ptrCast(constant); } }; + + pub const Array = opaque { + pub fn to_value(constant: *Constant.Array) *Value { + return @ptrCast(constant); + } + }; }; pub const Argument = opaque { @@ -867,6 +881,10 @@ pub const DI = struct { return api.LLVMDIBuilderCreateReplaceableCompositeType(builder, tag, name.ptr, name.len, scope, file, line, 0, 0, 0, .{}, null, 0); } + pub fn create_array_type(builder: *DI.Builder, element_count: u64, align_in_bits: u32, element_type: *DI.Type, subscripts: []const *DI.Metadata) *DI.Type.Composite { + return api.LLVMDIBuilderCreateArrayType(builder, element_count, align_in_bits, element_type, subscripts.ptr, @intCast(subscripts.len)); + } + pub fn create_struct_type(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, file: *DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, flags: DI.Flags, members: []const *DI.Type.Derived) *DI.Type.Composite { const derived_from: ?*DI.Type = null; const runtime_language: c_uint = 0; @@ -1040,6 +1058,20 @@ pub const Type = opaque { api.LLVMStructSetBody(struct_type, element_types.ptr, @intCast(element_types.len), @intFromBool(is_packed)); } }; + + pub const Array = opaque { + pub fn to_type(array_type: *Type.Array) *Type { + return @ptrCast(array_type); + } + }; + + pub fn get_array_type(element_type: *Type, element_count: u64) *Type.Array { + return api.LLVMArrayType2(element_type, element_count); + } + + pub fn get_constant_array(element_type: *Type, values: []const *Constant) *Constant.Array { + return api.LLVMConstArray2(element_type, values.ptr, values.len); + } }; pub const Dwarf = struct { diff --git a/src/converter.zig b/src/converter.zig index 49a21d2..f99dcdc 100644 --- a/src/converter.zig +++ b/src/converter.zig @@ -88,6 +88,10 @@ const Module = struct { file: *llvm.DI.File, }; + pub fn get_infer_or_ignore_value(module: *Module) *Value { + return &module.values.buffer[0]; + } + pub fn get_type(module: *Module, index: usize) *Type { assert(index < module.types.count); const result = &module.types.buffer[index]; @@ -226,6 +230,13 @@ const Module = struct { }); } + const infer_or_ignore_value = module.values.add(); + infer_or_ignore_value.* = .{ + .llvm = undefined, + .bb = .infer_or_ignore, + .type = undefined, + }; + return module; } }; @@ -245,9 +256,11 @@ pub const Value = struct { global, argument, instruction, - constant_integer, struct_initialization, bits_initialization, + infer_or_ignore, + constant_integer, + constant_array, }, type: *Type, llvm: *llvm.Value, @@ -262,6 +275,13 @@ pub const Value = struct { return result; } }; + + pub fn is_constant(value: *Value) bool { + return switch (value.bb) { + .constant_integer => true, + else => @trap(), + }; + } }; const Field = struct { @@ -290,6 +310,11 @@ const Bits = struct { backing_type: *Type, }; +pub const ArrayType = struct { + element_count: ?usize, + element_type: *Type, +}; + pub const Type = struct { bb: BB, llvm: LLVM, @@ -305,6 +330,7 @@ pub const Type = struct { @"struct": StructType, bits: Bits, function: FunctionType, + array: ArrayType, }; pub fn get_bit_size(ty: *const Type) u64 { @@ -313,6 +339,7 @@ pub const Type = struct { .@"struct" => |struct_type| struct_type.bit_size, .bits => |bits| bits.backing_type.get_bit_size(), .void, .forward_declaration, .function => unreachable, + .array => |*array| array.element_type.get_bit_size() * array.element_count.?, }; } @@ -322,6 +349,7 @@ pub const Type = struct { .@"struct" => |struct_type| struct_type.byte_size, .bits => |bits| bits.backing_type.get_byte_size(), .void, .forward_declaration, .function => unreachable, + .array => |*array| array.element_type.get_byte_size() * array.element_count.?, }; } @@ -331,6 +359,7 @@ pub const Type = struct { .@"struct" => |struct_type| struct_type.bit_alignment, .bits => |bits| bits.backing_type.get_bit_alignment(), .void, .forward_declaration, .function => unreachable, + .array => |*array| array.element_type.get_bit_alignment(), }; } @@ -340,6 +369,7 @@ pub const Type = struct { .@"struct" => |struct_type| struct_type.byte_alignment, .bits => |bits| bits.backing_type.get_byte_alignment(), .void, .forward_declaration, .function => unreachable, + .array => |*array| array.element_type.get_byte_alignment(), }; } @@ -347,6 +377,8 @@ pub const Type = struct { buffer: [1024]Type = undefined, count: usize = 0, + const buffer_size = 1024; + pub fn get(types: *Array) []Type { return types.buffer[0..types.count]; } @@ -442,26 +474,58 @@ const Converter = struct { } pub fn parse_type(noalias converter: *Converter, noalias module: *Module) *Type { - const identifier = converter.parse_identifier(); - var integer_type = identifier.len > 1 and identifier[0] == 's' or identifier[0] == 'u'; - if (integer_type) { - for (identifier[1..]) |ch| { - integer_type = integer_type and is_decimal_ch(ch); - } - } + switch (converter.content[converter.offset]) { + 'a'...'z', 'A'...'Z', '_' => { + const identifier = converter.parse_identifier(); + var integer_type = identifier.len > 1 and identifier[0] == 's' or identifier[0] == 'u'; + if (integer_type) { + for (identifier[1..]) |ch| { + integer_type = integer_type and is_decimal_ch(ch); + } + } - if (integer_type) { - const signedness = switch (identifier[0]) { - 's' => true, - 'u' => false, - else => unreachable, - }; - const bit_count: u32 = @intCast(lib.parse.integer_decimal(identifier[1..])); - const ty = module.integer_type(bit_count, signedness); - return ty; - } else { - const ty = module.types.find(identifier) orelse @trap(); - return ty; + if (integer_type) { + const signedness = switch (identifier[0]) { + 's' => true, + 'u' => false, + else => unreachable, + }; + const bit_count: u32 = @intCast(lib.parse.integer_decimal(identifier[1..])); + const ty = module.integer_type(bit_count, signedness); + return ty; + } else { + const ty = module.types.find(identifier) orelse @trap(); + return ty; + } + }, + left_bracket => { + converter.offset += 1; + + converter.skip_space(); + + const length_expression = converter.parse_value(module, null); + converter.skip_space(); + converter.expect_character(right_bracket); + + const element_type = converter.parse_type(module); + + if (length_expression.bb == .infer_or_ignore) { + const ty = module.types.add(.{ + .name = undefined, + .llvm = undefined, + .bb = .{ + .array = .{ + .element_count = null, + .element_type = element_type, + }, + }, + }); + return ty; + } else { + @trap(); + } + }, + else => @trap(), } } @@ -653,6 +717,8 @@ const Converter = struct { module.llvm.builder.clear_current_debug_location(); } + const value = converter.parse_value(module, local_type); + const local_storage = module.values.add(); local_storage.* = .{ .llvm = module.llvm.builder.create_alloca(local_type.llvm.handle, local_name), @@ -660,8 +726,6 @@ const Converter = struct { .bb = .local, }; - const value = converter.parse_value(module, local_type); - if (module.llvm.di_builder) |di_builder| { module.llvm.builder.set_current_debug_location(statement_debug_location); const debug_type = local_type.llvm.debug; @@ -827,8 +891,6 @@ const Converter = struct { const left = previous_value; const right = current_value; const next_ty = if (previous_value) |pv| pv.type else current_value.type; - // _ = left; - // _ = right; const llvm_value = switch (value_state) { .none => current_value.llvm, @@ -848,16 +910,21 @@ const Converter = struct { .icmp_ne => |icmp| module.llvm.builder.create_compare(icmp.to_int_predicate(), left.?.llvm, right.llvm), }; - previous_value = module.values.add(); - previous_value.?.* = .{ - .llvm = llvm_value, - .type = next_ty, - .bb = .instruction, - }; + switch (value_state) { + .none => previous_value = current_value, + else => { + previous_value = module.values.add(); + previous_value.?.* = .{ + .llvm = llvm_value, + .type = next_ty, + .bb = .instruction, + }; + }, + } const ch = converter.content[converter.offset]; value_state = switch (ch) { - ',', ';', right_parenthesis => break previous_value.?, + ',', ';', right_parenthesis, right_bracket => break previous_value.?, '-' => blk: { converter.offset += 1; break :blk .sub; @@ -1016,6 +1083,7 @@ const Converter = struct { const prefix_offset = converter.offset; const prefix_ch = converter.content[prefix_offset]; + const must_be_constant = module.current_function == null; const prefix: Prefix = switch (prefix_ch) { 'a'...'z', 'A'...'Z', '_', '0'...'9' => .none, '-' => blk: { @@ -1031,7 +1099,6 @@ const Converter = struct { converter.skip_space(); const ty = expected_type orelse converter.report_error(); - const must_be_constant = module.current_function == null; switch (ty.bb) { .@"struct" => |*struct_type| { @@ -1152,6 +1219,75 @@ const Converter = struct { @trap(); }, + left_bracket => { + converter.offset += 1; + + const ty = expected_type orelse converter.report_error(); + switch (ty.bb) { + .array => |*array| { + var element_count: usize = 0; + var element_buffer: [64]*llvm.Value = undefined; + + var elements_are_constant = true; + + while (true) : (element_count += 1) { + converter.skip_space(); + + if (converter.consume_character_if_match(right_bracket)) { + break; + } + + const element_value = converter.parse_value(module, array.element_type); + elements_are_constant = elements_are_constant and element_value.is_constant(); + element_buffer[element_count] = element_value.llvm; + + converter.skip_space(); + + _ = converter.consume_character_if_match(','); + } + + if (array.element_count) |ec| { + _ = ec; + @trap(); + } else { + array.element_count = element_count; + ty.llvm = .{ + .handle = array.element_type.llvm.handle.get_array_type(element_count).to_type(), + .debug = if (module.llvm.di_builder) |di_builder| di_builder.create_array_type(element_count, @intCast(array.element_type.get_bit_alignment()), array.element_type.llvm.debug, &.{}).to_type() else undefined, + }; + + var buffer: [256]u8 = undefined; + var i: usize = 0; + buffer[i] = left_bracket; + i += 1; + i += lib.string_format.integer_decimal(buffer[i..], element_count); + buffer[i] = right_bracket; + i += 1; + const element_name = array.element_type.name.?; + @memcpy(buffer[i..][0..element_name.len], element_name); + i += element_name.len; + ty.name = lib.global.arena.duplicate_string(buffer[0..i]); + } + + const array_elements = element_buffer[0..element_count]; + if (elements_are_constant) { + const array_constant = array.element_type.llvm.handle.get_constant_array(@ptrCast(array_elements)); + const value = module.values.add(); + value.* = .{ + .llvm = array_constant.to_value(), + .type = ty, + .bb = .constant_array, + }; + return value; + } else { + @trap(); + } + + @trap(); + }, + else => @trap(), + } + }, '#' => return converter.parse_intrinsic(module, expected_type), else => os.abort(), }; @@ -1162,104 +1298,128 @@ const Converter = struct { 'a'...'z', 'A'...'Z', '_' => b: { if (module.current_function) |current_function| { const identifier = converter.parse_identifier(); - const variable = blk: { - if (current_function.value.bb.function.locals.find(identifier)) |local| { - break :blk local; - } else if (current_function.value.bb.function.arguments.find(identifier)) |argument| { - break :blk argument; - } else if (module.globals.find(identifier)) |global| { - break :blk global; - } else { - converter.report_error(); - } - }; - - converter.skip_space(); - - if (converter.consume_character_if_match(left_parenthesis)) { - var llvm_arguments: [64]*llvm.Value = undefined; - var argument_count: usize = 0; - while (true) : (argument_count += 1) { - converter.skip_space(); - - if (converter.consume_character_if_match(right_parenthesis)) { - break; + if (lib.string.equal(identifier, "_")) { + return module.get_infer_or_ignore_value(); + } else { + const variable = blk: { + if (current_function.value.bb.function.locals.find(identifier)) |local| { + break :blk local; + } else if (current_function.value.bb.function.arguments.find(identifier)) |argument| { + break :blk argument; + } else if (module.globals.find(identifier)) |global| { + break :blk global; + } else { + converter.report_error(); } - - switch (variable.value.type.bb.function.calling_convention) { - .c => { - @trap(); - }, - .unknown => { - const argument_value = converter.parse_value(module, variable.value.type.bb.function.semantic_argument_types[argument_count]); - llvm_arguments[argument_count] = argument_value.llvm; - }, - } - } - - const llvm_argument_values = llvm_arguments[0..argument_count]; - 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()); - const call = module.values.add(); - call.* = .{ - .llvm = llvm_call, - .type = variable.value.type, - .bb = .instruction, }; - break :b call; - } else if (converter.consume_character_if_match('.')) { + converter.skip_space(); - switch (variable.value.type.bb) { - .@"struct" => |*struct_type| { - const field_name = converter.parse_identifier(); - const field_index: u32 = for (struct_type.fields, 0..) |field, field_index| { - if (lib.string.equal(field.name, field_name)) { - break @intCast(field_index); - } - } else converter.report_error(); - const field = struct_type.fields[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(); - load.* = .{ - .llvm = module.llvm.builder.create_load(field.type.llvm.handle, gep), - .type = field.type, - .bb = .instruction, - }; - 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]; + if (converter.consume_character_if_match(left_parenthesis)) { + var llvm_arguments: [64]*llvm.Value = undefined; + var argument_count: usize = 0; + while (true) : (argument_count += 1) { + converter.skip_space(); - 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()); + if (converter.consume_character_if_match(right_parenthesis)) { + break; + } - const value = module.values.add(); - value.* = .{ - .type = bits.backing_type, - .llvm = bitfield_masked, - .bb = .instruction, - }; + switch (variable.value.type.bb.function.calling_convention) { + .c => { + @trap(); + }, + .unknown => { + const argument_value = converter.parse_value(module, variable.value.type.bb.function.semantic_argument_types[argument_count]); + llvm_arguments[argument_count] = argument_value.llvm; + }, + } + } - break :b value; - }, - else => @trap(), + const llvm_argument_values = llvm_arguments[0..argument_count]; + 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()); + const call = module.values.add(); + call.* = .{ + .llvm = llvm_call, + .type = variable.value.type, + .bb = .instruction, + }; + break :b call; + } else if (converter.consume_character_if_match('.')) { + converter.skip_space(); + + switch (variable.value.type.bb) { + .@"struct" => |*struct_type| { + const field_name = converter.parse_identifier(); + const field_index: u32 = for (struct_type.fields, 0..) |field, field_index| { + if (lib.string.equal(field.name, field_name)) { + break @intCast(field_index); + } + } else converter.report_error(); + const field = struct_type.fields[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(); + load.* = .{ + .llvm = module.llvm.builder.create_load(field.type.llvm.handle, gep), + .type = field.type, + .bb = .instruction, + }; + 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 if (converter.consume_character_if_match(left_bracket)) { + converter.skip_space(); + + const index_type = module.integer_type(64, false); + const llvm_index_type = module.integer_type(64, false).llvm.handle.to_integer(); + const zero_index = llvm_index_type.get_constant(0, @intFromBool(false)).to_value(); + const index = converter.parse_value(module, index_type); + + converter.skip_space(); + converter.expect_character(right_bracket); + + const gep = module.llvm.builder.create_gep(variable.value.type.llvm.handle, variable.value.llvm, &.{ zero_index, index.llvm }); + const load = module.values.add(); + const load_type = variable.value.type.bb.array.element_type; + load.* = .{ + .llvm = module.llvm.builder.create_load(load_type.llvm.handle, gep), + .type = load_type, + .bb = .instruction, + }; + break :b load; + } else { + const load = module.values.add(); + load.* = .{ + .llvm = module.llvm.builder.create_load(variable.value.type.llvm.handle, variable.value.llvm), + .type = variable.value.type, + .bb = .instruction, + }; + break :b load; } - } else { - const load = module.values.add(); - load.* = .{ - .llvm = module.llvm.builder.create_load(variable.value.type.llvm.handle, variable.value.llvm), - .type = variable.value.type, - .bb = .instruction, - }; - break :b load; } } else { converter.report_error(); diff --git a/src/converter_test.zig b/src/converter_test.zig index 0b9079a..d9bdc54 100644 --- a/src/converter_test.zig +++ b/src/converter_test.zig @@ -168,3 +168,7 @@ test "extend" { test "bits" { try invsrc(@src()); } + +test "basic_array" { + try invsrc(@src()); +} diff --git a/src/lib.zig b/src/lib.zig index 7858eb5..ff981f7 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -9,6 +9,11 @@ test { _ = @import("lib_test.zig"); } +const CSlice = extern struct { + pointer: ?*anyopaque, + length: usize, +}; + pub const KB = 1024; pub const MB = 1024 * 1024; pub const GB = 1024 * 1024 * 1024; diff --git a/src/llvm_api.zig b/src/llvm_api.zig index 5c8623f..101dc8a 100644 --- a/src/llvm_api.zig +++ b/src/llvm_api.zig @@ -52,6 +52,8 @@ pub extern fn LLVMBuildStore(builder: *llvm.Builder, value: *llvm.Value, pointer pub extern fn LLVMBuildLoad2(builder: *llvm.Builder, ty: *llvm.Type, pointer: *llvm.Value, 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 LLVMBuildInBoundsGEP2(builder: *llvm.Builder, ty: *llvm.Type, aggregate: *llvm.Value, index_pointer: [*]const *llvm.Value, index_count: 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; @@ -112,6 +114,7 @@ pub extern fn llvm_integer_type_get_bit_count(integer_type: *llvm.Type.Integer) // VALUES pub extern fn LLVMGetPoison(type: *llvm.Type) *llvm.Value; pub extern fn LLVMConstInt(type: *llvm.Type.Integer, value: c_ulonglong, sign_extend: Bool) *llvm.Constant.Integer; +pub extern fn LLVMConstArray2(element_type: *llvm.Type, value_pointer: [*]const *llvm.Constant, value_length: u64) *llvm.Constant.Array; pub extern fn LLVMGetValueKind(value: *llvm.Value) llvm.Value.Kind; pub extern fn LLVMIsConstant(value: *llvm.Value) Bool; @@ -134,6 +137,7 @@ pub extern fn LLVMDIBuilderCreateGlobalVariableExpression(builder: *llvm.DI.Buil pub extern fn llvm_global_variable_add_debug_info(global_variable: *llvm.GlobalVariable, debug_global_variable: *llvm.DI.GlobalVariableExpression) void; pub extern fn LLVMDIBuilderCreateLexicalBlock(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, file: *llvm.DI.File, line: c_uint, column: c_uint) *llvm.DI.LexicalBlock; 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 LLVMDIBuilderCreateArrayType(builder: *llvm.DI.Builder, element_count: u64, align_in_bits: u32, element_type: *llvm.DI.Type, subscript_pointer: ?[*]const *llvm.DI.Metadata, subscript_count: c_uint) *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 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; diff --git a/tests/basic_array.bbb b/tests/basic_array.bbb new file mode 100644 index 0000000..a496845 --- /dev/null +++ b/tests/basic_array.bbb @@ -0,0 +1,5 @@ +[export] main = fn [cc(c)] () s32 +{ + >array: [_]s32 = [3, 2, 1, 0]; + return array[3]; +}