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,
|
||||
};
|
||||
|
||||
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 {
|
||||
bb: union(enum) {
|
||||
function: Function,
|
||||
constant_integer: ConstantInteger,
|
||||
unary: Unary,
|
||||
binary: Binary,
|
||||
},
|
||||
type: ?*Type = 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 {
|
||||
buffer: lib.VirtualBuffer(Value),
|
||||
pub fn initialize() Buffer {
|
||||
@ -441,12 +493,6 @@ pub const Value = struct {
|
||||
v.kind = kind;
|
||||
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;
|
||||
}
|
||||
|
||||
@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.?;
|
||||
@ -1526,15 +1575,73 @@ pub const Module = struct {
|
||||
}
|
||||
|
||||
fn rule_after_binary(noalias module: *Module, value_builder: Value.Builder) *Value {
|
||||
_ = module;
|
||||
_ = value_builder;
|
||||
@trap();
|
||||
const binary_operator_token = value_builder.token;
|
||||
const binary_operator_token_precedence = rules[@intFromEnum(binary_operator_token)].precedence;
|
||||
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 {
|
||||
_ = module;
|
||||
_ = value_builder;
|
||||
@trap();
|
||||
assert(value_builder.left == null);
|
||||
const unary_token = value_builder.token;
|
||||
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 {
|
||||
@ -2372,51 +2479,128 @@ pub const Module = struct {
|
||||
};
|
||||
|
||||
pub fn analyze_value(module: *Module, function: *Global, value: *Value, analysis: ValueAnalysis) void {
|
||||
_ = function;
|
||||
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.type == null);
|
||||
assert(value.llvm == null);
|
||||
|
||||
switch (value.bb) {
|
||||
.constant_integer => |constant_integer| {
|
||||
const llvm_constant = value_type.llvm.handle.?.to_integer().get_constant(constant_integer.value, @intFromBool(constant_integer.signed));
|
||||
value.llvm = llvm_constant.to_value();
|
||||
if (analysis.type) |expected_type| 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();
|
||||
}
|
||||
},
|
||||
},
|
||||
.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(),
|
||||
}
|
||||
};
|
||||
|
||||
_ = value.llvm orelse module.report_error();
|
||||
if (value.llvm == null) {
|
||||
@trap();
|
||||
}
|
||||
const value_type = if (analysis.type) |expected_type| expected_type else switch (value.bb) {
|
||||
else => @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 {
|
||||
|
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 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;
|
||||
inline for (@typeInfo(BuildMode).@"enum".fields, 0..) |field, field_index| {
|
||||
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