Enable more tests
All checks were successful
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 37s
CI / ci (ReleaseFast, ubuntu-latest) (pull_request) Successful in 25s
CI / ci (ReleaseSafe, ubuntu-latest) (pull_request) Successful in 31s
CI / ci (ReleaseSmall, ubuntu-latest) (pull_request) Successful in 24s
CI / ci (Debug, ubuntu-latest) (push) Successful in 38s
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 25s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 31s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 23s
All checks were successful
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 37s
CI / ci (ReleaseFast, ubuntu-latest) (pull_request) Successful in 25s
CI / ci (ReleaseSafe, ubuntu-latest) (pull_request) Successful in 31s
CI / ci (ReleaseSmall, ubuntu-latest) (pull_request) Successful in 24s
CI / ci (Debug, ubuntu-latest) (push) Successful in 38s
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 25s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 31s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 23s
This commit is contained in:
parent
a84572df7f
commit
8b74db15df
@ -361,14 +361,66 @@ pub const Statement = struct {
|
|||||||
column: u32,
|
column: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Unary = struct {
|
||||||
|
value: *Value,
|
||||||
|
id: Id,
|
||||||
|
|
||||||
|
const Id = enum {
|
||||||
|
@"-",
|
||||||
|
@"+",
|
||||||
|
@"&",
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const Binary = struct {
|
||||||
|
left: *Value,
|
||||||
|
right: *Value,
|
||||||
|
id: Id,
|
||||||
|
|
||||||
|
const Id = enum {
|
||||||
|
@"+",
|
||||||
|
@"-",
|
||||||
|
@"*",
|
||||||
|
@"/",
|
||||||
|
@"%",
|
||||||
|
@"&",
|
||||||
|
@"|",
|
||||||
|
@"^",
|
||||||
|
@"<<",
|
||||||
|
@">>",
|
||||||
|
@"==",
|
||||||
|
@"!=",
|
||||||
|
@">",
|
||||||
|
@"<",
|
||||||
|
@">=",
|
||||||
|
@"<=",
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
pub const Value = struct {
|
pub const Value = struct {
|
||||||
bb: union(enum) {
|
bb: union(enum) {
|
||||||
function: Function,
|
function: Function,
|
||||||
constant_integer: ConstantInteger,
|
constant_integer: ConstantInteger,
|
||||||
|
unary: Unary,
|
||||||
|
binary: Binary,
|
||||||
},
|
},
|
||||||
type: ?*Type = null,
|
type: ?*Type = null,
|
||||||
llvm: ?*llvm.Value = null,
|
llvm: ?*llvm.Value = null,
|
||||||
|
|
||||||
|
fn is_constant(value: *Value) bool {
|
||||||
|
return switch (value.bb) {
|
||||||
|
.constant_integer => true,
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
@ -441,12 +493,6 @@ pub const Value = struct {
|
|||||||
v.kind = kind;
|
v.kind = kind;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_type(vb: Builder, ty: ?*Type) Builder {
|
|
||||||
var v = vb;
|
|
||||||
v.type = ty;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1410,7 +1456,10 @@ pub const Module = struct {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@trap();
|
const after_rule = token_rule.after orelse module.report_error();
|
||||||
|
const old = result;
|
||||||
|
const new = after_rule(module, value_builder.with_token(token).with_precedence(.none).with_left(old));
|
||||||
|
result = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.?;
|
return result.?;
|
||||||
@ -1526,15 +1575,73 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rule_after_binary(noalias module: *Module, value_builder: Value.Builder) *Value {
|
fn rule_after_binary(noalias module: *Module, value_builder: Value.Builder) *Value {
|
||||||
_ = module;
|
const binary_operator_token = value_builder.token;
|
||||||
_ = value_builder;
|
const binary_operator_token_precedence = rules[@intFromEnum(binary_operator_token)].precedence;
|
||||||
@trap();
|
const left = value_builder.left orelse module.report_error();
|
||||||
|
assert(binary_operator_token_precedence != .assignment); // TODO: this may be wrong. Assignment operator is not allowed in expressions
|
||||||
|
const right_precedence = if (binary_operator_token_precedence == .assignment) .assignment else binary_operator_token_precedence.increment();
|
||||||
|
const right = module.parse_precedence(value_builder.with_precedence(right_precedence).with_token(.none).with_left(null));
|
||||||
|
|
||||||
|
const binary_operation_kind: Binary.Id = switch (binary_operator_token) {
|
||||||
|
.none => unreachable,
|
||||||
|
.@"+" => .@"+",
|
||||||
|
.@"-" => .@"-",
|
||||||
|
.@"*" => .@"*",
|
||||||
|
.@"/" => .@"/",
|
||||||
|
.@"%" => .@"%",
|
||||||
|
.@"&" => .@"&",
|
||||||
|
.@"|" => .@"|",
|
||||||
|
.@"^" => .@"^",
|
||||||
|
.@"<<" => .@"<<",
|
||||||
|
.@">>" => .@">>",
|
||||||
|
.@"==" => .@"==",
|
||||||
|
.@"!=" => .@"!=",
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = module.values.add();
|
||||||
|
value.* = .{
|
||||||
|
.bb = .{
|
||||||
|
.binary = .{
|
||||||
|
.left = left,
|
||||||
|
.right = right,
|
||||||
|
.id = binary_operation_kind,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_unary(noalias module: *Module, value_builder: Value.Builder) *Value {
|
fn rule_before_unary(noalias module: *Module, value_builder: Value.Builder) *Value {
|
||||||
_ = module;
|
assert(value_builder.left == null);
|
||||||
_ = value_builder;
|
const unary_token = value_builder.token;
|
||||||
@trap();
|
const unary_id: Unary.Id = switch (unary_token) {
|
||||||
|
.none => unreachable,
|
||||||
|
.@"-" => .@"-",
|
||||||
|
.@"+" => .@"+",
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const right = module.parse_precedence(value_builder.with_precedence(.prefix).with_token(.none).with_kind(if (unary_id == .@"&") .left else value_builder.kind));
|
||||||
|
|
||||||
|
const value = switch (unary_id) {
|
||||||
|
.@"+" => @trap(),
|
||||||
|
.@"-" => blk: {
|
||||||
|
const value = module.values.add();
|
||||||
|
value.* = .{
|
||||||
|
.bb = .{
|
||||||
|
.unary = .{
|
||||||
|
.id = unary_id,
|
||||||
|
.value = right,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
break :blk value;
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_after_dereference(noalias module: *Module, value_builder: Value.Builder) *Value {
|
fn rule_after_dereference(noalias module: *Module, value_builder: Value.Builder) *Value {
|
||||||
@ -2372,51 +2479,128 @@ pub const Module = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn analyze_value(module: *Module, function: *Global, value: *Value, analysis: ValueAnalysis) void {
|
pub fn analyze_value(module: *Module, function: *Global, value: *Value, analysis: ValueAnalysis) void {
|
||||||
_ = function;
|
assert(value.type == null);
|
||||||
if (analysis.type) |expected_type| {
|
|
||||||
if (value.type) |value_type| {
|
|
||||||
_ = value_type;
|
|
||||||
@trap();
|
|
||||||
} else switch (expected_type.bb) {
|
|
||||||
.integer => |integer| switch (value.bb) {
|
|
||||||
.constant_integer => |constant_integer| switch (constant_integer.signed) {
|
|
||||||
true => {
|
|
||||||
if (!integer.signed) {
|
|
||||||
module.report_error();
|
|
||||||
}
|
|
||||||
@trap();
|
|
||||||
},
|
|
||||||
false => {
|
|
||||||
const type_max = (@as(u64, 1) << @intCast(integer.bit_count)) - 1;
|
|
||||||
if (constant_integer.value > type_max) {
|
|
||||||
module.report_error();
|
|
||||||
}
|
|
||||||
value.type = expected_type;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
else => @trap(),
|
|
||||||
},
|
|
||||||
else => @trap(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
@trap();
|
|
||||||
}
|
|
||||||
|
|
||||||
const value_type = value.type orelse module.report_error();
|
|
||||||
assert(value.llvm == null);
|
assert(value.llvm == null);
|
||||||
|
|
||||||
switch (value.bb) {
|
if (analysis.type) |expected_type| switch (expected_type.bb) {
|
||||||
.constant_integer => |constant_integer| {
|
.integer => |integer| switch (value.bb) {
|
||||||
const llvm_constant = value_type.llvm.handle.?.to_integer().get_constant(constant_integer.value, @intFromBool(constant_integer.signed));
|
.constant_integer => |constant_integer| switch (constant_integer.signed) {
|
||||||
value.llvm = llvm_constant.to_value();
|
true => {
|
||||||
|
if (!integer.signed) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
@trap();
|
||||||
|
},
|
||||||
|
false => {
|
||||||
|
const type_max = (@as(u64, 1) << @intCast(integer.bit_count)) - 1;
|
||||||
|
if (constant_integer.value > type_max) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.unary => |unary| {
|
||||||
|
switch (unary.id) {
|
||||||
|
.@"+" => @trap(),
|
||||||
|
.@"-" => {
|
||||||
|
module.analyze_value(function, unary.value, analysis);
|
||||||
|
if (!unary.value.type.?.is_signed()) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(expected_type == unary.value.type);
|
||||||
|
},
|
||||||
|
.@"&" => @trap(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.binary => |binary| {
|
||||||
|
const is_boolean = switch (binary.id) {
|
||||||
|
.@"==",
|
||||||
|
.@"!=",
|
||||||
|
.@">",
|
||||||
|
.@"<",
|
||||||
|
.@">=",
|
||||||
|
.@"<=",
|
||||||
|
=> true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const boolean_type = module.integer_type(1, false);
|
||||||
|
|
||||||
|
if (is_boolean and expected_type != boolean_type) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.analyze_value(function, binary.left, .{
|
||||||
|
.type = if (is_boolean) null else expected_type,
|
||||||
|
});
|
||||||
|
|
||||||
|
module.analyze_value(function, binary.right, .{
|
||||||
|
.type = binary.left.type,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
},
|
},
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
}
|
};
|
||||||
|
|
||||||
_ = value.llvm orelse module.report_error();
|
const value_type = if (analysis.type) |expected_type| expected_type else switch (value.bb) {
|
||||||
if (value.llvm == null) {
|
else => @trap(),
|
||||||
@trap();
|
};
|
||||||
}
|
|
||||||
|
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(),
|
||||||
|
.unary => |unary| switch (unary.id) {
|
||||||
|
.@"-" => unary.value.negate_llvm(),
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
.binary => |binary| switch (value_type.bb) {
|
||||||
|
.integer => |integer| switch (binary.id) {
|
||||||
|
.@"+" => module.llvm.builder.create_add(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
.@"-" => module.llvm.builder.create_sub(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
.@"*" => module.llvm.builder.create_mul(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
.@"/" => switch (integer.signed) {
|
||||||
|
true => module.llvm.builder.create_sdiv(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
false => module.llvm.builder.create_udiv(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
},
|
||||||
|
.@"%" => switch (integer.signed) {
|
||||||
|
true => module.llvm.builder.create_srem(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
false => module.llvm.builder.create_urem(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
},
|
||||||
|
.@"&" => module.llvm.builder.create_and(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
.@"|" => module.llvm.builder.create_or(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
.@"^" => module.llvm.builder.create_xor(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
.@"<<" => module.llvm.builder.create_shl(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
.@">>" => switch (integer.signed) {
|
||||||
|
true => module.llvm.builder.create_ashr(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
false => module.llvm.builder.create_lshr(binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
},
|
||||||
|
.@"==" => module.llvm.builder.create_integer_compare(.eq, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
.@"!=" => module.llvm.builder.create_integer_compare(.ne, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
.@">" => switch (integer.signed) {
|
||||||
|
true => module.llvm.builder.create_integer_compare(.sgt, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
false => module.llvm.builder.create_integer_compare(.ugt, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
},
|
||||||
|
.@"<" => switch (integer.signed) {
|
||||||
|
true => module.llvm.builder.create_integer_compare(.slt, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
false => module.llvm.builder.create_integer_compare(.ult, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
},
|
||||||
|
.@">=" => switch (integer.signed) {
|
||||||
|
true => module.llvm.builder.create_integer_compare(.sge, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
false => module.llvm.builder.create_integer_compare(.uge, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
},
|
||||||
|
.@"<=" => switch (integer.signed) {
|
||||||
|
true => module.llvm.builder.create_integer_compare(.sle, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
false => module.llvm.builder.create_integer_compare(.ule, binary.left.llvm.?, binary.right.llvm.?),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
value.type = value_type;
|
||||||
|
value.llvm = llvm_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyze_block(module: *Module, function: *Global, block: *LexicalBlock) void {
|
pub fn analyze_block(module: *Module, function: *Global, block: *LexicalBlock) void {
|
||||||
|
38
src/main.zig
38
src/main.zig
@ -127,25 +127,6 @@ pub fn entry_point(arguments: []const [*:0]const u8, environment: [*:null]const
|
|||||||
|
|
||||||
const stop_at_failure = true;
|
const stop_at_failure = true;
|
||||||
|
|
||||||
const names = &[_][]const u8{
|
|
||||||
"minimal",
|
|
||||||
// "comments",
|
|
||||||
// "constant_add",
|
|
||||||
// "constant_and",
|
|
||||||
// "constant_div",
|
|
||||||
// "constant_mul",
|
|
||||||
// "constant_rem",
|
|
||||||
// "constant_or",
|
|
||||||
// "constant_sub",
|
|
||||||
// "constant_xor",
|
|
||||||
// "constant_shift_left",
|
|
||||||
// "constant_shift_right",
|
|
||||||
// "minimal_stack",
|
|
||||||
// "minimal_stack_arithmetic",
|
|
||||||
// "pointer",
|
|
||||||
// "extend",
|
|
||||||
};
|
|
||||||
|
|
||||||
var build_modes: [@typeInfo(BuildMode).@"enum".fields.len]BuildMode = undefined;
|
var build_modes: [@typeInfo(BuildMode).@"enum".fields.len]BuildMode = undefined;
|
||||||
inline for (@typeInfo(BuildMode).@"enum".fields, 0..) |field, field_index| {
|
inline for (@typeInfo(BuildMode).@"enum".fields, 0..) |field, field_index| {
|
||||||
const build_mode = @field(BuildMode, field.name);
|
const build_mode = @field(BuildMode, field.name);
|
||||||
@ -187,3 +168,22 @@ pub fn entry_point(arguments: []const [*:0]const u8, environment: [*:null]const
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const names = &[_][]const u8{
|
||||||
|
"minimal",
|
||||||
|
"comments",
|
||||||
|
"constant_add",
|
||||||
|
"constant_and",
|
||||||
|
"constant_div",
|
||||||
|
"constant_mul",
|
||||||
|
"constant_rem",
|
||||||
|
"constant_or",
|
||||||
|
"constant_sub",
|
||||||
|
"constant_xor",
|
||||||
|
"constant_shift_left",
|
||||||
|
"constant_shift_right",
|
||||||
|
// "minimal_stack",
|
||||||
|
// "minimal_stack_arithmetic",
|
||||||
|
// "pointer",
|
||||||
|
// "extend",
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user