Minimal stack arithmetic
All checks were successful
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 30s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 29s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 37s
CI / ci (Debug, ubuntu-latest) (push) Successful in 44s

This commit is contained in:
David Gonzalez Martin 2025-04-06 09:47:44 +02:00
parent 5e1443f37f
commit 1c50a06cce
4 changed files with 136 additions and 79 deletions

View File

@ -409,9 +409,29 @@ const Binary = struct {
@"<", @"<",
@">=", @">=",
@"<=", @"<=",
fn is_boolean(id: Binary.Id) bool {
return switch (id) {
.@"==",
.@"!=",
.@">",
.@"<",
.@">=",
.@"<=",
=> true,
else => false,
};
}
}; };
}; };
fn negate_llvm_value(value: *llvm.Value, is_constant: bool) *llvm.Value {
return switch (is_constant) {
true => value.to_constant().negate().to_value(),
false => @trap(),
};
}
pub const Value = struct { pub const Value = struct {
bb: union(enum) { bb: union(enum) {
function: Function, function: Function,
@ -431,13 +451,6 @@ pub const Value = struct {
}; };
} }
fn negate_llvm(value: *Value) *llvm.Value {
return switch (value.is_constant()) {
true => value.llvm.?.to_constant().negate().to_value(),
false => @trap(),
};
}
pub const Buffer = struct { pub const Buffer = struct {
buffer: lib.VirtualBuffer(Value), buffer: lib.VirtualBuffer(Value),
pub fn initialize() Buffer { pub fn initialize() Buffer {
@ -2551,62 +2564,77 @@ pub const Module = struct {
pub fn analyze(module: *Module, function: *Global, value: *Value, analysis: ValueAnalysis) void { pub fn analyze(module: *Module, function: *Global, value: *Value, analysis: ValueAnalysis) void {
module.analyze_value_type(function, value, analysis); module.analyze_value_type(function, value, analysis);
module.emit_value(function, value, analysis); module.emit_value(function, value);
} }
pub fn emit_value(module: *Module, function: *Global, value: *Value, analysis: ValueAnalysis) void { pub fn emit_value(module: *Module, function: *Global, value: *Value) void {
_ = function;
_ = analysis;
const value_type = value.type orelse unreachable; const value_type = value.type orelse unreachable;
assert(value.llvm == null); assert(value.llvm == null);
const llvm_value: *llvm.Value = switch (value.bb) { const llvm_value: *llvm.Value = switch (value.bb) {
.constant_integer => |constant_integer| value_type.llvm.handle.?.to_integer().get_constant(constant_integer.value, @intFromBool(constant_integer.signed)).to_value(), .constant_integer => |constant_integer| value_type.llvm.handle.?.to_integer().get_constant(constant_integer.value, @intFromBool(constant_integer.signed)).to_value(),
.unary => |unary| switch (unary.id) { .unary => |unary| switch (unary.id) {
.@"-" => unary.value.negate_llvm(), .@"-" => blk: {
const unary_value = unary.value.llvm orelse b: {
module.emit_value(function, unary.value);
break :b unary.value.llvm orelse unreachable;
};
break :blk negate_llvm_value(unary_value, unary.value.is_constant());
},
else => @trap(), else => @trap(),
}, },
.binary => |binary| switch (value_type.bb) { .binary => |binary| blk: {
const left = if (binary.left.llvm) |left_llvm| left_llvm else b: {
module.emit_value(function, binary.left);
break :b binary.left.llvm orelse unreachable;
};
const right = if (binary.right.llvm) |right_llvm| right_llvm else b: {
module.emit_value(function, binary.right);
break :b binary.right.llvm orelse unreachable;
};
const result = switch (value_type.bb) {
.integer => |integer| switch (binary.id) { .integer => |integer| switch (binary.id) {
.@"+" => module.llvm.builder.create_add(binary.left.llvm.?, binary.right.llvm.?), .@"+" => module.llvm.builder.create_add(left, right),
.@"-" => module.llvm.builder.create_sub(binary.left.llvm.?, binary.right.llvm.?), .@"-" => module.llvm.builder.create_sub(left, right),
.@"*" => module.llvm.builder.create_mul(binary.left.llvm.?, binary.right.llvm.?), .@"*" => module.llvm.builder.create_mul(left, right),
.@"/" => switch (integer.signed) { .@"/" => switch (integer.signed) {
true => module.llvm.builder.create_sdiv(binary.left.llvm.?, binary.right.llvm.?), true => module.llvm.builder.create_sdiv(left, right),
false => module.llvm.builder.create_udiv(binary.left.llvm.?, binary.right.llvm.?), false => module.llvm.builder.create_udiv(left, right),
}, },
.@"%" => switch (integer.signed) { .@"%" => switch (integer.signed) {
true => module.llvm.builder.create_srem(binary.left.llvm.?, binary.right.llvm.?), true => module.llvm.builder.create_srem(left, right),
false => module.llvm.builder.create_urem(binary.left.llvm.?, binary.right.llvm.?), false => module.llvm.builder.create_urem(left, right),
}, },
.@"&" => module.llvm.builder.create_and(binary.left.llvm.?, binary.right.llvm.?), .@"&" => module.llvm.builder.create_and(left, right),
.@"|" => module.llvm.builder.create_or(binary.left.llvm.?, binary.right.llvm.?), .@"|" => module.llvm.builder.create_or(left, right),
.@"^" => module.llvm.builder.create_xor(binary.left.llvm.?, binary.right.llvm.?), .@"^" => module.llvm.builder.create_xor(left, right),
.@"<<" => module.llvm.builder.create_shl(binary.left.llvm.?, binary.right.llvm.?), .@"<<" => module.llvm.builder.create_shl(left, right),
.@">>" => switch (integer.signed) { .@">>" => switch (integer.signed) {
true => module.llvm.builder.create_ashr(binary.left.llvm.?, binary.right.llvm.?), true => module.llvm.builder.create_ashr(left, right),
false => module.llvm.builder.create_lshr(binary.left.llvm.?, binary.right.llvm.?), false => module.llvm.builder.create_lshr(left, right),
}, },
.@"==" => module.llvm.builder.create_integer_compare(.eq, binary.left.llvm.?, binary.right.llvm.?), .@"==" => module.llvm.builder.create_integer_compare(.eq, left, right),
.@"!=" => module.llvm.builder.create_integer_compare(.ne, binary.left.llvm.?, binary.right.llvm.?), .@"!=" => module.llvm.builder.create_integer_compare(.ne, left, right),
.@">" => switch (integer.signed) { .@">" => switch (integer.signed) {
true => module.llvm.builder.create_integer_compare(.sgt, binary.left.llvm.?, binary.right.llvm.?), true => module.llvm.builder.create_integer_compare(.sgt, left, right),
false => module.llvm.builder.create_integer_compare(.ugt, binary.left.llvm.?, binary.right.llvm.?), false => module.llvm.builder.create_integer_compare(.ugt, left, right),
}, },
.@"<" => switch (integer.signed) { .@"<" => switch (integer.signed) {
true => module.llvm.builder.create_integer_compare(.slt, binary.left.llvm.?, binary.right.llvm.?), true => module.llvm.builder.create_integer_compare(.slt, left, right),
false => module.llvm.builder.create_integer_compare(.ult, binary.left.llvm.?, binary.right.llvm.?), false => module.llvm.builder.create_integer_compare(.ult, left, right),
}, },
.@">=" => switch (integer.signed) { .@">=" => switch (integer.signed) {
true => module.llvm.builder.create_integer_compare(.sge, binary.left.llvm.?, binary.right.llvm.?), true => module.llvm.builder.create_integer_compare(.sge, left, right),
false => module.llvm.builder.create_integer_compare(.uge, binary.left.llvm.?, binary.right.llvm.?), false => module.llvm.builder.create_integer_compare(.uge, left, right),
}, },
.@"<=" => switch (integer.signed) { .@"<=" => switch (integer.signed) {
true => module.llvm.builder.create_integer_compare(.sle, binary.left.llvm.?, binary.right.llvm.?), true => module.llvm.builder.create_integer_compare(.sle, left, right),
false => module.llvm.builder.create_integer_compare(.ule, binary.left.llvm.?, binary.right.llvm.?), false => module.llvm.builder.create_integer_compare(.ule, left, right),
}, },
}, },
else => @trap(), else => @trap(),
};
break :blk result;
}, },
.variable_reference => |variable| if (variable.type == value_type) switch (value_type.get_evaluation_kind()) { .variable_reference => |variable| if (variable.type == value_type) switch (value_type.get_evaluation_kind()) {
.scalar => module.create_load(.{ .scalar => module.create_load(.{
@ -2648,7 +2676,7 @@ pub const Module = struct {
switch (unary.id) { switch (unary.id) {
.@"+" => @trap(), .@"+" => @trap(),
.@"-" => { .@"-" => {
module.analyze(function, unary.value, analysis); module.analyze_value_type(function, unary.value, analysis);
if (!unary.value.type.?.is_signed()) { if (!unary.value.type.?.is_signed()) {
module.report_error(); module.report_error();
} }
@ -2659,16 +2687,7 @@ pub const Module = struct {
} }
}, },
.binary => |binary| { .binary => |binary| {
const is_boolean = switch (binary.id) { const is_boolean = binary.id.is_boolean();
.@"==",
.@"!=",
.@">",
.@"<",
.@">=",
.@"<=",
=> true,
else => false,
};
const boolean_type = module.integer_type(1, false); const boolean_type = module.integer_type(1, false);
@ -2676,11 +2695,11 @@ pub const Module = struct {
module.report_error(); module.report_error();
} }
module.analyze(function, binary.left, .{ module.analyze_value_type(function, binary.left, .{
.type = if (is_boolean) null else expected_type, .type = if (is_boolean) null else expected_type,
}); });
module.analyze(function, binary.right, .{ module.analyze_value_type(function, binary.right, .{
.type = binary.left.type, .type = binary.left.type,
}); });
}, },
@ -2695,6 +2714,34 @@ pub const Module = struct {
}; };
const value_type = if (analysis.type) |expected_type| expected_type else switch (value.bb) { const value_type = if (analysis.type) |expected_type| expected_type else switch (value.bb) {
.binary => |binary| blk: {
if (binary.left.bb == .constant_integer and binary.right.bb == .constant_integer) {
module.report_error();
}
if (binary.left.bb == .constant_integer) {
module.analyze_value_type(function, binary.right, .{});
module.analyze_value_type(function, binary.left, .{
.type = binary.right.type,
});
} else if (binary.right.bb == .constant_integer) {
module.analyze_value_type(function, binary.left, .{});
module.analyze_value_type(function, binary.right, .{
.type = binary.left.type,
});
} else {
module.analyze_value_type(function, binary.left, .{});
module.analyze_value_type(function, binary.right, .{});
}
assert(binary.left.type != null);
assert(binary.right.type != null);
assert(binary.left.type == binary.right.type);
break :blk binary.left.type.?;
},
.variable_reference => |variable| blk: {
break :blk variable.type;
},
else => @trap(), else => @trap(),
}; };
@ -2832,18 +2879,14 @@ pub const Module = struct {
_ = module.llvm.builder.clear_insertion_position(); _ = module.llvm.builder.clear_insertion_position();
}, },
.local => |local| { .local => |local| {
if (local.variable.type) |expected_type| { const expected_type = local.variable.type;
assert(local.variable.storage == null); assert(local.variable.storage == null);
module.analyze_value_type(function, local.variable.initial_value, .{ .type = local.variable.type }); module.analyze_value_type(function, local.variable.initial_value, .{ .type = local.variable.type });
local.variable.resolve_type(local.variable.initial_value.type.?); local.variable.resolve_type(local.variable.initial_value.type.?);
assert(expected_type == local.variable.type); if (expected_type) |lvt| assert(lvt == local.variable.type);
module.emit_local_storage(local, last_statement_debug_location); module.emit_local_storage(local, last_statement_debug_location);
module.emit_assignment(function, local.variable.storage.?, local.variable.initial_value); module.emit_assignment(function, local.variable.storage.?, local.variable.initial_value);
} else {
@trap();
}
}, },
} }
} }
@ -2859,7 +2902,7 @@ pub const Module = struct {
switch (value_type.get_evaluation_kind()) { switch (value_type.get_evaluation_kind()) {
.scalar => { .scalar => {
module.emit_value(function, right, .{}); module.emit_value(function, right);
_ = module.create_store(.{ _ = module.create_store(.{
.source_value = right.llvm.?, .source_value = right.llvm.?,
.destination_value = left.llvm.?, .destination_value = left.llvm.?,

View File

@ -183,7 +183,9 @@ const names = &[_][]const u8{
"constant_shift_left", "constant_shift_left",
"constant_shift_right", "constant_shift_right",
"minimal_stack", "minimal_stack",
// "minimal_stack_arithmetic", "minimal_stack_arithmetic",
"minimal_stack_arithmetic2",
"minimal_stack_arithmetic3",
// "pointer", // "pointer",
// "extend", // "extend",
}; };

View File

@ -0,0 +1,6 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = 1;
>b = a - 1;
return b;
}

View File

@ -0,0 +1,6 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = 1;
>b = 1 - a;
return b;
}