Merge pull request #160 from birth-software/wrapping-arithmetic
Implement wrapping arithmetic
This commit is contained in:
commit
6fa4c2bda9
@ -3805,10 +3805,16 @@ pub const Instruction = union(enum) {
|
||||
|
||||
const Id = enum {
|
||||
add,
|
||||
wrapping_add,
|
||||
saturated_add,
|
||||
sub,
|
||||
wrapping_sub,
|
||||
saturated_sub,
|
||||
mul,
|
||||
wrapping_mul,
|
||||
saturated_mul,
|
||||
div,
|
||||
mod,
|
||||
mul,
|
||||
sub,
|
||||
bit_and,
|
||||
bit_or,
|
||||
bit_xor,
|
||||
@ -4380,8 +4386,14 @@ pub const IntrinsicId = enum {
|
||||
|
||||
pub const ArithmeticLogicIntegerInstruction = enum {
|
||||
add,
|
||||
wrapping_add,
|
||||
saturated_add,
|
||||
sub,
|
||||
wrapping_sub,
|
||||
saturated_sub,
|
||||
mul,
|
||||
wrapping_mul,
|
||||
saturated_mul,
|
||||
div,
|
||||
mod,
|
||||
bit_and,
|
||||
@ -6728,7 +6740,7 @@ pub const Builder = struct {
|
||||
fn resolveAssignment(builder: *Builder, unit: *Unit, context: *const Context, node_index: Node.Index) !V {
|
||||
const node = unit.getNode(node_index);
|
||||
switch (node.id) {
|
||||
.assign, .add_assign, .sub_assign, .div_assign => {
|
||||
.assign, .add_assign, .sub_assign, .div_assign, .or_assign => {
|
||||
if (unit.getNode(node.left).id == .discard) {
|
||||
_ = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, node.right, .right);
|
||||
return .{
|
||||
@ -6778,6 +6790,7 @@ pub const Builder = struct {
|
||||
.add_assign => .add,
|
||||
.sub_assign => .sub,
|
||||
.div_assign => .div,
|
||||
.or_assign => .bit_or,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
},
|
||||
@ -9992,13 +10005,22 @@ pub const Builder = struct {
|
||||
};
|
||||
}
|
||||
},
|
||||
.add, .sub, .mul, .div, .mod, .bit_and, .bit_or, .bit_xor, .shift_left, .shift_right, .bool_and, .bool_or => block: {
|
||||
.add, .wrapping_add, .saturated_add,
|
||||
.sub, .wrapping_sub, .saturated_sub,
|
||||
.mul, .wrapping_mul, .saturated_mul,
|
||||
.div, .mod, .bit_and, .bit_or, .bit_xor, .shift_left, .shift_right, .bool_and, .bool_or => block: {
|
||||
const left_node_index = node.left;
|
||||
const right_node_index = node.right;
|
||||
const binary_operation_id: ArithmeticLogicIntegerInstruction = switch (node.id) {
|
||||
.add => .add,
|
||||
.wrapping_add => .wrapping_add,
|
||||
.saturated_add => .saturated_add,
|
||||
.sub => .sub,
|
||||
.wrapping_sub => .wrapping_sub,
|
||||
.saturated_sub => .saturated_sub,
|
||||
.mul => .mul,
|
||||
.wrapping_mul => .wrapping_mul,
|
||||
.saturated_mul => .saturated_mul,
|
||||
.div => .div,
|
||||
.mod => .mod,
|
||||
.bit_and => .bit_and,
|
||||
@ -10026,11 +10048,17 @@ pub const Builder = struct {
|
||||
},
|
||||
.type => switch (binary_operation_id) {
|
||||
.add,
|
||||
.wrapping_add,
|
||||
.saturated_add,
|
||||
.sub,
|
||||
.wrapping_sub,
|
||||
.saturated_sub,
|
||||
.bit_and,
|
||||
.bit_xor,
|
||||
.bit_or,
|
||||
.mul,
|
||||
.wrapping_mul,
|
||||
.saturated_mul,
|
||||
.div,
|
||||
.mod,
|
||||
.shift_left,
|
||||
@ -10070,6 +10098,7 @@ pub const Builder = struct {
|
||||
.bit_xor => left ^ right,
|
||||
.shift_left => left << @as(u6, @intCast(right)),
|
||||
.shift_right => left >> @as(u6, @intCast(right)),
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
break :block switch (type_expect) {
|
||||
@ -10141,8 +10170,14 @@ pub const Builder = struct {
|
||||
.bit_xor,
|
||||
.shift_right,
|
||||
.add,
|
||||
.wrapping_add,
|
||||
.saturated_add,
|
||||
.sub,
|
||||
.wrapping_sub,
|
||||
.saturated_sub,
|
||||
.mul,
|
||||
.wrapping_mul,
|
||||
.saturated_mul,
|
||||
.div,
|
||||
.mod,
|
||||
=> left_value.type,
|
||||
@ -10157,10 +10192,16 @@ pub const Builder = struct {
|
||||
.materialized_int => b: {
|
||||
const id: Instruction.IntegerBinaryOperation.Id = switch (binary_operation_id) {
|
||||
.add => .add,
|
||||
.wrapping_add => .wrapping_add,
|
||||
.saturated_add => .saturated_add,
|
||||
.sub => .sub,
|
||||
.wrapping_sub => .wrapping_sub,
|
||||
.saturated_sub => .saturated_sub,
|
||||
.mul => .mul,
|
||||
.wrapping_mul => .wrapping_mul,
|
||||
.saturated_mul => .saturated_mul,
|
||||
.div => .div,
|
||||
.mod => .mod,
|
||||
.mul => .mul,
|
||||
.sub => .sub,
|
||||
.bit_and => .bit_and,
|
||||
.bit_or => .bit_or,
|
||||
.bit_xor => .bit_xor,
|
||||
@ -13776,7 +13817,7 @@ pub const Builder = struct {
|
||||
try builder.insertDebugCheckPoint(unit, context, statement_node.token);
|
||||
|
||||
switch (statement_node.id) {
|
||||
.assign, .add_assign, .sub_assign, .div_assign => {
|
||||
.assign, .add_assign, .sub_assign, .div_assign, .or_assign => {
|
||||
_ = try builder.resolveAssignment(unit, context, statement_node_index);
|
||||
},
|
||||
.if_else => {
|
||||
@ -17349,8 +17390,14 @@ pub const Token = struct {
|
||||
// Binary
|
||||
operator_assign,
|
||||
operator_add,
|
||||
operator_saturated_add,
|
||||
operator_wrapping_add,
|
||||
operator_minus,
|
||||
operator_saturated_sub,
|
||||
operator_wrapping_sub,
|
||||
operator_asterisk,
|
||||
operator_saturated_mul,
|
||||
operator_wrapping_mul,
|
||||
operator_div,
|
||||
operator_mod,
|
||||
operator_bar,
|
||||
@ -17359,8 +17406,14 @@ pub const Token = struct {
|
||||
operator_shift_left,
|
||||
operator_shift_right,
|
||||
operator_add_assign,
|
||||
operator_wrapping_add_assign,
|
||||
operator_saturated_add_assign,
|
||||
operator_sub_assign,
|
||||
operator_wrapping_sub_assign,
|
||||
operator_saturated_sub_assign,
|
||||
operator_mul_assign,
|
||||
operator_wrapping_mul_assign,
|
||||
operator_saturated_mul_assign,
|
||||
operator_div_assign,
|
||||
operator_mod_assign,
|
||||
operator_or_assign,
|
||||
|
@ -2762,14 +2762,20 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
const left = try llvm.emitRightValue(unit, context, binary_operation.left);
|
||||
const right = try llvm.emitRightValue(unit, context, binary_operation.right);
|
||||
assert(left.getType() == right.getType());
|
||||
const no_signed_wrapping = binary_operation.signedness == .signed;
|
||||
const no_unsigned_wrapping = binary_operation.signedness == .unsigned;
|
||||
const no_signed_wrapping = binary_operation.signedness == .signed or switch (binary_operation.id) {
|
||||
.wrapping_add, .wrapping_sub, .wrapping_mul => false,
|
||||
else => true,
|
||||
};
|
||||
const no_unsigned_wrapping = binary_operation.signedness == .unsigned or switch (binary_operation.id) {
|
||||
.wrapping_add, .wrapping_sub, .wrapping_mul => false,
|
||||
else => true,
|
||||
};
|
||||
const name = @tagName(binary_operation.id);
|
||||
const is_exact = false;
|
||||
const instruction = switch (binary_operation.id) {
|
||||
.add => llvm.builder.createAdd(left, right, name.ptr, name.len, no_unsigned_wrapping, no_signed_wrapping) orelse return LLVM.Value.Instruction.Error.add,
|
||||
.mul => llvm.builder.createMultiply(left, right, name.ptr, name.len, no_unsigned_wrapping, no_signed_wrapping) orelse return LLVM.Value.Instruction.Error.multiply,
|
||||
.sub => llvm.builder.createSub(left, right, name.ptr, name.len, no_unsigned_wrapping, no_signed_wrapping) orelse return LLVM.Value.Instruction.Error.add,
|
||||
.add, .wrapping_add => llvm.builder.createAdd(left, right, name.ptr, name.len, no_unsigned_wrapping, no_signed_wrapping) orelse return LLVM.Value.Instruction.Error.add,
|
||||
.sub, .wrapping_sub => llvm.builder.createSub(left, right, name.ptr, name.len, no_unsigned_wrapping, no_signed_wrapping) orelse return LLVM.Value.Instruction.Error.add,
|
||||
.mul, .wrapping_mul => llvm.builder.createMultiply(left, right, name.ptr, name.len, no_unsigned_wrapping, no_signed_wrapping) orelse return LLVM.Value.Instruction.Error.multiply,
|
||||
.div => switch (binary_operation.signedness) {
|
||||
.unsigned => llvm.builder.createUDiv(left, right, name.ptr, name.len, is_exact) orelse unreachable,
|
||||
.signed => llvm.builder.createSDiv(left, right, name.ptr, name.len, is_exact) orelse unreachable,
|
||||
@ -2786,7 +2792,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
.unsigned => llvm.builder.createLogicalShiftRight(left, right, name.ptr, name.len, is_exact) orelse unreachable,
|
||||
.signed => llvm.builder.createArithmeticShiftRight(left, right, name.ptr, name.len, is_exact) orelse unreachable,
|
||||
},
|
||||
//else => |t| @panic(@tagName(t)),
|
||||
else => unreachable,
|
||||
};
|
||||
try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, instruction);
|
||||
},
|
||||
|
@ -313,6 +313,26 @@ pub fn analyze(allocator: *MyAllocator, text: []const u8, token_buffer: *Token.B
|
||||
index += 1;
|
||||
break :b .operator_add_assign;
|
||||
},
|
||||
'|' => b: {
|
||||
index += 1;
|
||||
break :b switch (text[index]) {
|
||||
'=' => assign: {
|
||||
index += 1;
|
||||
break :assign .operator_saturated_add_assign;
|
||||
},
|
||||
else => .operator_saturated_add,
|
||||
};
|
||||
},
|
||||
'%' => b: {
|
||||
index += 1;
|
||||
break :b switch (text[index]) {
|
||||
'=' => assign: {
|
||||
index += 1;
|
||||
break :assign .operator_wrapping_add_assign;
|
||||
},
|
||||
else => .operator_wrapping_add,
|
||||
};
|
||||
},
|
||||
else => .operator_add,
|
||||
};
|
||||
|
||||
@ -325,6 +345,26 @@ pub fn analyze(allocator: *MyAllocator, text: []const u8, token_buffer: *Token.B
|
||||
index += 1;
|
||||
break :b .operator_sub_assign;
|
||||
},
|
||||
'|' => b: {
|
||||
index += 1;
|
||||
break :b switch (text[index]) {
|
||||
'=' => assign: {
|
||||
index += 1;
|
||||
break :assign .operator_saturated_add_assign;
|
||||
},
|
||||
else => .operator_saturated_sub,
|
||||
};
|
||||
},
|
||||
'%' => b: {
|
||||
index += 1;
|
||||
break :b switch (text[index]) {
|
||||
'=' => assign: {
|
||||
index += 1;
|
||||
break :assign .operator_wrapping_sub_assign;
|
||||
},
|
||||
else => .operator_wrapping_sub,
|
||||
};
|
||||
},
|
||||
else => .operator_minus,
|
||||
};
|
||||
|
||||
@ -337,6 +377,26 @@ pub fn analyze(allocator: *MyAllocator, text: []const u8, token_buffer: *Token.B
|
||||
index += 1;
|
||||
break :b .operator_mul_assign;
|
||||
},
|
||||
'|' => b: {
|
||||
index += 1;
|
||||
break :b switch (text[index]) {
|
||||
'=' => assign: {
|
||||
index += 1;
|
||||
break :assign .operator_saturated_mul_assign;
|
||||
},
|
||||
else => .operator_saturated_mul,
|
||||
};
|
||||
},
|
||||
'%' => b: {
|
||||
index += 1;
|
||||
break :b switch (text[index]) {
|
||||
'=' => assign: {
|
||||
index += 1;
|
||||
break :assign .operator_wrapping_mul_assign;
|
||||
},
|
||||
else => .operator_wrapping_mul,
|
||||
};
|
||||
},
|
||||
else => .operator_asterisk,
|
||||
};
|
||||
|
||||
|
@ -206,6 +206,13 @@ pub const Node = struct {
|
||||
slice_metadata,
|
||||
orelse_expression,
|
||||
type,
|
||||
or_assign,
|
||||
wrapping_add,
|
||||
saturated_add,
|
||||
wrapping_sub,
|
||||
saturated_sub,
|
||||
wrapping_mul,
|
||||
saturated_mul,
|
||||
};
|
||||
};
|
||||
|
||||
@ -871,6 +878,7 @@ const Analyzer = struct {
|
||||
.operator_mul_assign => .mul_assign,
|
||||
.operator_div_assign => .div_assign,
|
||||
.operator_mod_assign => .mod_assign,
|
||||
.operator_or_assign => .or_assign,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
analyzer.consumeToken();
|
||||
@ -1052,8 +1060,14 @@ const Analyzer = struct {
|
||||
compare_less_equal,
|
||||
compare_greater_equal,
|
||||
add,
|
||||
wrapping_add,
|
||||
saturated_add,
|
||||
sub,
|
||||
wrapping_sub,
|
||||
saturated_sub,
|
||||
mul,
|
||||
wrapping_mul,
|
||||
saturated_mul,
|
||||
div,
|
||||
mod,
|
||||
bit_and,
|
||||
@ -1075,8 +1089,14 @@ const Analyzer = struct {
|
||||
.compare_less_equal = 30,
|
||||
.compare_greater_equal = 30,
|
||||
.add = 60,
|
||||
.wrapping_add = 60,
|
||||
.saturated_add = 60,
|
||||
.sub = 60,
|
||||
.wrapping_sub = 60,
|
||||
.saturated_sub = 60,
|
||||
.mul = 70,
|
||||
.wrapping_mul = 70,
|
||||
.saturated_mul = 70,
|
||||
.div = 70,
|
||||
.mod = 70,
|
||||
.bit_and = 40,
|
||||
@ -1098,13 +1118,19 @@ const Analyzer = struct {
|
||||
.compare_less_equal = .none,
|
||||
.compare_greater_equal = .none,
|
||||
.add = .left,
|
||||
.wrapping_add = .left,
|
||||
.saturated_add = .left,
|
||||
.sub = .left,
|
||||
.wrapping_sub = .left,
|
||||
.saturated_sub = .left,
|
||||
.bit_and = .left,
|
||||
.bit_xor = .left,
|
||||
.bit_or = .left,
|
||||
.bool_and = .left,
|
||||
.bool_or = .left,
|
||||
.mul = .left,
|
||||
.wrapping_mul = .left,
|
||||
.saturated_mul = .left,
|
||||
.div = .left,
|
||||
.mod = .left,
|
||||
.shift_left = .left,
|
||||
@ -1121,13 +1147,19 @@ const Analyzer = struct {
|
||||
.compare_greater_equal = .compare_greater_equal,
|
||||
.compare_less_equal = .compare_less_equal,
|
||||
.add = .add,
|
||||
.wrapping_add = .wrapping_add,
|
||||
.saturated_add = .saturated_add,
|
||||
.sub = .sub,
|
||||
.wrapping_sub = .wrapping_sub,
|
||||
.saturated_sub = .saturated_sub,
|
||||
.bit_and = .bit_and,
|
||||
.bit_xor = .bit_xor,
|
||||
.bit_or = .bit_or,
|
||||
.bool_and = .bool_and,
|
||||
.bool_or = .bool_or,
|
||||
.mul = .mul,
|
||||
.wrapping_mul = .wrapping_mul,
|
||||
.saturated_mul = .saturated_mul,
|
||||
.div = .div,
|
||||
.mod = .mod,
|
||||
.shift_left = .shift_left,
|
||||
@ -1162,6 +1194,7 @@ const Analyzer = struct {
|
||||
.operator_mul_assign,
|
||||
.operator_div_assign,
|
||||
.operator_mod_assign,
|
||||
.operator_or_assign,
|
||||
.operator_dot,
|
||||
.operator_double_dot,
|
||||
.operator_triple_dot,
|
||||
@ -1183,8 +1216,14 @@ const Analyzer = struct {
|
||||
.operator_compare_less_equal => .compare_less_equal,
|
||||
.operator_compare_greater_equal => .compare_greater_equal,
|
||||
.operator_add => .add,
|
||||
.operator_wrapping_add => .wrapping_add,
|
||||
.operator_saturated_add => .saturated_add,
|
||||
.operator_minus => .sub,
|
||||
.operator_wrapping_sub => .wrapping_sub,
|
||||
.operator_saturated_sub => .saturated_sub,
|
||||
.operator_asterisk => .mul,
|
||||
.operator_wrapping_mul => .wrapping_mul,
|
||||
.operator_saturated_mul => .saturated_mul,
|
||||
.operator_div => .div,
|
||||
.operator_mod => .mod,
|
||||
.operator_ampersand => .bit_and,
|
||||
|
58
src/main.nat
58
src/main.nat
@ -6,6 +6,39 @@ const print = std.print;
|
||||
const print_usize = std.print_usize;
|
||||
const exit = std.os.exit;
|
||||
|
||||
const lex = fn (arena: &Arena, bytes: []const u8) *!void {
|
||||
if (bytes.length >= 0xffffffff) {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const length: u32 = #cast(bytes.length);
|
||||
|
||||
const max_initial_keyword_len: u32 = 8;
|
||||
|
||||
//var index: u32 = 0;
|
||||
//while (index + 64 < length) {
|
||||
// var i = index;
|
||||
// const top = index + max_initial_keyword_len + 1;
|
||||
// var space: u32 = 0;
|
||||
// while (i < top) {
|
||||
// const is_space = bytes[i] == ' ';
|
||||
// space |= #cast(
|
||||
// i += 1;
|
||||
// }
|
||||
|
||||
// if (space == 0) {
|
||||
// unreachable;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
const FileStartToken = enum{
|
||||
"comptime",
|
||||
"test",
|
||||
"const",
|
||||
"var",
|
||||
};
|
||||
|
||||
const ArgumentProcessingError = error{
|
||||
no_arguments,
|
||||
};
|
||||
@ -58,31 +91,6 @@ const FixedKeyword = enum{
|
||||
"continue",
|
||||
};
|
||||
|
||||
const FileStartToken = enum{
|
||||
"comptime",
|
||||
"test",
|
||||
"const",
|
||||
"var",
|
||||
};
|
||||
|
||||
const lex = fn (arena: &Arena, bytes: []const u8) *!void {
|
||||
if (bytes.length >= 0xffffffff) {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const length: u32 = #cast(bytes.length);
|
||||
var i: u32 = 0;
|
||||
|
||||
//var index: u32 = 0;
|
||||
//while (index + 64 < length) {
|
||||
// var i = index;
|
||||
// const top = index + 64;
|
||||
// while (i < top) {
|
||||
// i += 1;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
const get_argument = fn (real_argument: []const u8, wanted_argument: []const u8, command_arguments: []const [&:0]const u8, i_ptr: &usize) ?[]const u8 {
|
||||
const i = i_ptr.@;
|
||||
|
||||
|
12
test/standalone/wrapping_arithmetic/main.nat
Normal file
12
test/standalone/wrapping_arithmetic/main.nat
Normal file
@ -0,0 +1,12 @@
|
||||
const std = #import("std");
|
||||
const expect = std.testing.expect;
|
||||
const main = fn () *!void {
|
||||
var a: u8 = 255;
|
||||
var b: u8 = 1;
|
||||
const result = a +% b;
|
||||
try expect(result == 0);
|
||||
var c: u16 = 0;
|
||||
var d: u16 = 1;
|
||||
const sub_result = c -% d;
|
||||
try expect(sub_result == 65535);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user