Constant sub
This commit is contained in:
parent
34a3514856
commit
c4d25ca393
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@ -74,6 +74,7 @@ jobs:
|
|||||||
version: master
|
version: master
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get update && sudo apt-get install -y llvm-dev liblld-dev
|
run: sudo apt-get update && sudo apt-get install -y llvm-dev liblld-dev
|
||||||
|
if: matrix.os == 'ubuntu-24.04'
|
||||||
- name: Build and test (Packaged LLVM)
|
- name: Build and test (Packaged LLVM)
|
||||||
run: |
|
run: |
|
||||||
zig build test --summary all -Doptimize=${{matrix.BIRTH_ZIG_BUILD_TYPE}} -Dsystem_llvm=false
|
zig build test --summary all -Doptimize=${{matrix.BIRTH_ZIG_BUILD_TYPE}} -Dsystem_llvm=false
|
||||||
|
31
src/LLVM.zig
31
src/LLVM.zig
@ -1,7 +1,8 @@
|
|||||||
const lib = @import("lib.zig");
|
const lib = @import("lib.zig");
|
||||||
const builtin = @import("builtin");
|
|
||||||
const Arena = lib.Arena;
|
const Arena = lib.Arena;
|
||||||
const assert = lib.assert;
|
const assert = lib.assert;
|
||||||
|
const os = lib.os;
|
||||||
|
const builtin = @import("builtin");
|
||||||
const api = @import("llvm_api.zig");
|
const api = @import("llvm_api.zig");
|
||||||
|
|
||||||
/// This is a String which ABI-compatible with C++
|
/// This is a String which ABI-compatible with C++
|
||||||
@ -539,6 +540,13 @@ pub const Builder = opaque {
|
|||||||
pub const position_at_end = api.LLVMPositionBuilderAtEnd;
|
pub const position_at_end = api.LLVMPositionBuilderAtEnd;
|
||||||
|
|
||||||
pub const create_ret = api.LLVMBuildRet;
|
pub const create_ret = api.LLVMBuildRet;
|
||||||
|
pub fn create_add(builder: *Builder, left: *Value, right: *Value) *Value {
|
||||||
|
return api.LLVMBuildAdd(builder, left, right, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_sub(builder: *Builder, left: *Value, right: *Value) *Value {
|
||||||
|
return api.LLVMBuildSub(builder, left, right, "");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_ret_void(builder: *Builder) void {
|
pub fn create_ret_void(builder: *Builder) void {
|
||||||
builder.create_ret(null);
|
builder.create_ret(null);
|
||||||
@ -695,6 +703,7 @@ pub const lld = struct {
|
|||||||
|
|
||||||
pub const Thread = struct {
|
pub const Thread = struct {
|
||||||
context: *Context,
|
context: *Context,
|
||||||
|
builder: *Builder,
|
||||||
i1: Integer,
|
i1: Integer,
|
||||||
i8: Integer,
|
i8: Integer,
|
||||||
i16: Integer,
|
i16: Integer,
|
||||||
@ -724,6 +733,7 @@ pub const Thread = struct {
|
|||||||
|
|
||||||
thread.* = .{
|
thread.* = .{
|
||||||
.context = context,
|
.context = context,
|
||||||
|
.builder = context.create_builder(),
|
||||||
.i1 = .{
|
.i1 = .{
|
||||||
.type = type_i1,
|
.type = type_i1,
|
||||||
.zero = zero_i1,
|
.zero = zero_i1,
|
||||||
@ -793,21 +803,6 @@ const LldArgvBuilder = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ModuleBuilder = struct {
|
|
||||||
module: *Module,
|
|
||||||
builder: *Builder,
|
|
||||||
|
|
||||||
pub fn initialize(thread: *Thread, module_name: []const u8) ModuleBuilder {
|
|
||||||
const module = thread.context.create_module(module_name);
|
|
||||||
const builder = thread.context.create_builder();
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.module = module,
|
|
||||||
.builder = builder,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const FunctionBuilder = struct {
|
pub const FunctionBuilder = struct {
|
||||||
function: *Function,
|
function: *Function,
|
||||||
current_basic_block: *BasicBlock,
|
current_basic_block: *BasicBlock,
|
||||||
@ -901,7 +896,9 @@ pub fn link(arena: *Arena, options: LinkOptions) lld.Result {
|
|||||||
const dynamic_linker = true;
|
const dynamic_linker = true;
|
||||||
if (dynamic_linker) {
|
if (dynamic_linker) {
|
||||||
arg_builder.add("-dynamic-linker");
|
arg_builder.add("-dynamic-linker");
|
||||||
arg_builder.add("/usr/lib/ld-linux-x86-64.so.2");
|
|
||||||
|
const dynamic_linker_path = "/usr/lib64/ld-linux-x86-64.so.2";
|
||||||
|
arg_builder.add(dynamic_linker_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link_libc) {
|
if (link_libc) {
|
||||||
|
@ -75,8 +75,7 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_type(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias module_builder: *llvm.ModuleBuilder) *llvm.Type {
|
pub fn parse_type(noalias converter: *Converter, noalias thread: *llvm.Thread) *llvm.Type {
|
||||||
_ = module_builder;
|
|
||||||
const identifier = converter.parse_identifier();
|
const identifier = converter.parse_identifier();
|
||||||
var integer_type = identifier.len > 1 and identifier[0] == 's' or identifier[0] == 'u';
|
var integer_type = identifier.len > 1 and identifier[0] == 's' or identifier[0] == 'u';
|
||||||
if (integer_type) {
|
if (integer_type) {
|
||||||
@ -150,6 +149,10 @@ const Converter = struct {
|
|||||||
const integer_start_ch = converter.content[start];
|
const integer_start_ch = converter.content[start];
|
||||||
assert(!is_space(integer_start_ch));
|
assert(!is_space(integer_start_ch));
|
||||||
assert(is_decimal_ch(integer_start_ch));
|
assert(is_decimal_ch(integer_start_ch));
|
||||||
|
const integer_type = expected_type.to_integer();
|
||||||
|
|
||||||
|
const sign_extend = false;
|
||||||
|
var value: u64 = 0;
|
||||||
|
|
||||||
switch (integer_start_ch) {
|
switch (integer_start_ch) {
|
||||||
'0' => {
|
'0' => {
|
||||||
@ -172,18 +175,25 @@ const Converter = struct {
|
|||||||
converter.report_error();
|
converter.report_error();
|
||||||
},
|
},
|
||||||
// Zero literal
|
// Zero literal
|
||||||
else => {
|
else => {},
|
||||||
const integer_type = expected_type.to_integer();
|
}
|
||||||
const sign_extend = false;
|
},
|
||||||
const integer_value = integer_type.get_constant(0, @intFromBool(sign_extend));
|
'1'...'9' => {
|
||||||
return integer_value.to_value();
|
while (true) {
|
||||||
},
|
const ch = converter.content[converter.offset];
|
||||||
|
if (!is_decimal_ch(ch)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
converter.offset += 1;
|
||||||
|
value = lib.parse.accumulate_decimal(value, ch);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// TODO: decimal number
|
|
||||||
'1'...'9' => converter.report_error(),
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const integer_value = integer_type.get_constant(value, @intFromBool(sign_extend));
|
||||||
|
return integer_value.to_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_character(noalias converter: *Converter, expected_ch: u8) void {
|
fn expect_character(noalias converter: *Converter, expected_ch: u8) void {
|
||||||
@ -192,8 +202,7 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(noalias converter: *Converter, thread: *llvm.Thread, module_builder: *llvm.ModuleBuilder, function_builder: *llvm.FunctionBuilder) void {
|
fn parse_block(noalias converter: *Converter, noalias thread: *llvm.Thread, noalias function_builder: *llvm.FunctionBuilder) void {
|
||||||
_ = thread;
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
converter.expect_character(left_brace);
|
converter.expect_character(left_brace);
|
||||||
@ -216,8 +225,8 @@ 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(function_builder.function.get_type().get_return_type());
|
const return_value = converter.parse_value(thread, function_builder.function.get_type().get_return_type());
|
||||||
module_builder.builder.create_ret(return_value);
|
thread.builder.create_ret(return_value);
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
@ -239,7 +248,51 @@ const Converter = struct {
|
|||||||
converter.expect_character(right_brace);
|
converter.expect_character(right_brace);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_value(noalias converter: *Converter, expected_type: *llvm.Type) *llvm.Value {
|
const ExpressionState = enum {
|
||||||
|
none,
|
||||||
|
sub,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn parse_value(noalias converter: *Converter, noalias thread: *llvm.Thread, expected_type: *llvm.Type) *llvm.Value {
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
var value_state = ExpressionState.none;
|
||||||
|
var previous_value: *llvm.Value = undefined;
|
||||||
|
|
||||||
|
const value = while (true) {
|
||||||
|
const current_value = switch (converter.content[converter.offset] == left_parenthesis) {
|
||||||
|
true => os.abort(),
|
||||||
|
false => converter.parse_single_value(expected_type),
|
||||||
|
};
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
switch (value_state) {
|
||||||
|
.none => previous_value = current_value,
|
||||||
|
.sub => {
|
||||||
|
const left = previous_value;
|
||||||
|
const right = current_value;
|
||||||
|
previous_value = thread.builder.create_sub(left, right);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const ch = converter.content[converter.offset];
|
||||||
|
value_state = switch (ch) {
|
||||||
|
';' => break previous_value,
|
||||||
|
'-' => blk: {
|
||||||
|
converter.offset += 1;
|
||||||
|
break :blk .sub;
|
||||||
|
},
|
||||||
|
else => os.abort(),
|
||||||
|
};
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
};
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_single_value(noalias converter: *Converter, expected_type: *llvm.Type) *llvm.Value {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
const start = converter.offset;
|
const start = converter.offset;
|
||||||
@ -299,6 +352,81 @@ pub const BuildMode = enum {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn invoke(name: []const u8) !void {
|
||||||
|
if (!lib.GlobalState.initialized) {
|
||||||
|
lib.GlobalState.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
comptime assert(lib.is_test);
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
|
||||||
|
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
|
||||||
|
const build_mode = @field(BuildMode, f.name);
|
||||||
|
inline for ([2]u1{ 0, 1 }) |has_debug_info| {
|
||||||
|
var tmp_dir = std.testing.tmpDir(.{});
|
||||||
|
defer tmp_dir.cleanup();
|
||||||
|
const base_path = lib.global.arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
|
||||||
|
const executable_path = base_path;
|
||||||
|
invoke_wrapper(.{
|
||||||
|
.object_path = lib.global.arena.join_string(&.{ base_path, ".o" }),
|
||||||
|
.executable_path = executable_path,
|
||||||
|
.file_path = lib.global.arena.join_string(&.{ "tests/", name, ".bbb" }),
|
||||||
|
.name = name,
|
||||||
|
}, build_mode, has_debug_info);
|
||||||
|
const run_result = std.process.Child.run(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
.argv = &.{executable_path},
|
||||||
|
}) catch |err| {
|
||||||
|
std.debug.print("error: {}\n", .{err});
|
||||||
|
const path = lib.global.arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
|
||||||
|
const r = try std.process.Child.run(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
.argv = &.{ "/usr/bin/ls", "-lasR", path },
|
||||||
|
.max_output_bytes = std.math.maxInt(usize),
|
||||||
|
});
|
||||||
|
defer allocator.free(r.stdout);
|
||||||
|
defer allocator.free(r.stderr);
|
||||||
|
std.debug.print("ls {s} {s}\n", .{ path, r.stdout });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
const success = switch (run_result.term) {
|
||||||
|
.Exited => |exit_code| exit_code == 0,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
if (!success) {
|
||||||
|
return error.executable_failed_to_run_successfully;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const InvokeWrapper = struct {
|
||||||
|
executable_path: [:0]const u8,
|
||||||
|
object_path: [:0]const u8,
|
||||||
|
file_path: [:0]const u8,
|
||||||
|
name: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return invoke_single(options, build_mode, has_debug_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invoke_single(options: InvokeWrapper, build_mode: BuildMode, has_debug_info: u1) void {
|
||||||
|
const file_content = lib.file.read(lib.global.arena, options.file_path);
|
||||||
|
|
||||||
|
convert(.{
|
||||||
|
.path = options.file_path,
|
||||||
|
.content = file_content,
|
||||||
|
.object = options.object_path,
|
||||||
|
.executable = options.executable_path,
|
||||||
|
.build_mode = build_mode,
|
||||||
|
.name = options.name,
|
||||||
|
.has_debug_info = has_debug_info,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const ConvertOptions = struct {
|
const ConvertOptions = struct {
|
||||||
content: []const u8,
|
content: []const u8,
|
||||||
path: [:0]const u8,
|
path: [:0]const u8,
|
||||||
@ -316,8 +444,7 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const thread = llvm.default_initialize();
|
const thread = llvm.default_initialize();
|
||||||
var module_builder_memory = llvm.ModuleBuilder.initialize(thread, options.name);
|
const module = thread.context.create_module(options.name);
|
||||||
const module_builder = &module_builder_memory;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
@ -418,10 +545,10 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
const return_type = converter.parse_type(thread, module_builder);
|
const return_type = converter.parse_type(thread);
|
||||||
const function_type = llvm.Type.Function.get(return_type, &.{}, false);
|
const function_type = llvm.Type.Function.get(return_type, &.{}, false);
|
||||||
|
|
||||||
const function = module_builder.module.create_function(.{
|
const function = module.create_function(.{
|
||||||
.name = global_name,
|
.name = global_name,
|
||||||
.linkage = switch (is_export) {
|
.linkage = switch (is_export) {
|
||||||
true => .ExternalLinkage,
|
true => .ExternalLinkage,
|
||||||
@ -431,14 +558,14 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const entry_block = thread.context.create_basic_block("entry", function);
|
const entry_block = thread.context.create_basic_block("entry", function);
|
||||||
module_builder.builder.position_at_end(entry_block);
|
thread.builder.position_at_end(entry_block);
|
||||||
|
|
||||||
var function_builder = llvm.FunctionBuilder{
|
var function_builder = llvm.FunctionBuilder{
|
||||||
.function = function,
|
.function = function,
|
||||||
.current_basic_block = entry_block,
|
.current_basic_block = entry_block,
|
||||||
};
|
};
|
||||||
|
|
||||||
converter.parse_block(thread, module_builder, &function_builder);
|
converter.parse_block(thread, &function_builder);
|
||||||
|
|
||||||
if (lib.optimization_mode == .Debug) {
|
if (lib.optimization_mode == .Debug) {
|
||||||
const verify_result = function.verify();
|
const verify_result = function.verify();
|
||||||
@ -452,13 +579,13 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lib.optimization_mode == .Debug) {
|
if (lib.optimization_mode == .Debug) {
|
||||||
const verify_result = module_builder.module.verify();
|
const verify_result = module.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_builder.module.to_string();
|
const module_string = module.to_string();
|
||||||
lib.print_string_stderr(module_string);
|
lib.print_string_stderr(module_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,7 +604,7 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
os.abort();
|
os.abort();
|
||||||
};
|
};
|
||||||
|
|
||||||
const object_generate_result = llvm.object_generate(module_builder.module, target_machine, .{
|
const object_generate_result = llvm.object_generate(module, 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,
|
||||||
@ -501,47 +628,9 @@ pub noinline fn convert(options: ConvertOptions) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "minimal" {
|
test "minimal" {
|
||||||
invoke("minimal");
|
try invoke("minimal");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invoke(name: []const u8) void {
|
test "constant sub" {
|
||||||
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
|
try invoke("constant_sub");
|
||||||
const build_mode = @field(BuildMode, f.name);
|
|
||||||
inline for ([2]u1{ 0, 1 }) |has_debug_info| {
|
|
||||||
invoke_wrapper(name, build_mode, has_debug_info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We invoke a function with comptime parameters so it's easily visible in CI stack traces
|
|
||||||
fn invoke_wrapper(name: []const u8, comptime build_mode: BuildMode, comptime has_debug_info: u1) void {
|
|
||||||
return invoke_single(name, build_mode, has_debug_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invoke_single(name: []const u8, build_mode: BuildMode, has_debug_info: u1) void {
|
|
||||||
const std = @import("std");
|
|
||||||
if (!lib.GlobalState.initialized) {
|
|
||||||
lib.GlobalState.initialize();
|
|
||||||
}
|
|
||||||
var tmp_dir = if (lib.is_test) std.testing.tmpDir(.{}) else {};
|
|
||||||
defer {
|
|
||||||
if (lib.is_test) {
|
|
||||||
tmp_dir.cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const object_path = lib.global.arena.join_string(if (lib.is_test) &.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name, ".o" } else &.{ name, ".o" });
|
|
||||||
const executable_path = lib.global.arena.join_string(if (lib.is_test) &.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name, ".o" } else &.{name});
|
|
||||||
const file_path = lib.global.arena.join_string(&.{ "tests/", name, ".bbb" });
|
|
||||||
const file_content = lib.file.read(lib.global.arena, file_path);
|
|
||||||
|
|
||||||
convert(.{
|
|
||||||
.path = file_path,
|
|
||||||
.content = file_content,
|
|
||||||
.object = object_path,
|
|
||||||
.executable = executable_path,
|
|
||||||
.build_mode = build_mode,
|
|
||||||
.name = name,
|
|
||||||
.has_debug_info = has_debug_info,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -2492,11 +2492,15 @@ pub const parse = struct {
|
|||||||
|
|
||||||
for (str) |ch| {
|
for (str) |ch| {
|
||||||
assert(is_decimal_digit(ch));
|
assert(is_decimal_digit(ch));
|
||||||
value = (value * 10) + (ch - '0');
|
value = accumulate_decimal(value, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn accumulate_decimal(accumulator: u64, ch: u8) u64 {
|
||||||
|
return (accumulator * 10) + (ch - '0');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn vprint(format_string: [*:0]const u8, args: *VariableArguments) void {
|
fn vprint(format_string: [*:0]const u8, args: *VariableArguments) void {
|
||||||
|
@ -19,6 +19,8 @@ pub extern fn llvm_module_to_string(module: *llvm.Module) llvm.String;
|
|||||||
// Builder API
|
// Builder API
|
||||||
pub extern fn LLVMPositionBuilderAtEnd(builder: *llvm.Builder, basic_block: *llvm.BasicBlock) void;
|
pub extern fn LLVMPositionBuilderAtEnd(builder: *llvm.Builder, basic_block: *llvm.BasicBlock) void;
|
||||||
pub extern fn LLVMBuildRet(builder: *llvm.Builder, value: ?*llvm.Value) void;
|
pub extern fn LLVMBuildRet(builder: *llvm.Builder, value: ?*llvm.Value) void;
|
||||||
|
pub extern fn LLVMBuildAdd(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
||||||
|
pub extern fn LLVMBuildSub(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
||||||
|
|
||||||
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;
|
||||||
|
5
tests/constant_sub.bbb
Normal file
5
tests/constant_sub.bbb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
return 1 - 1;
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user