Assignment operators
This commit is contained in:
parent
cb12fa62fe
commit
17918ce4e3
@ -1054,6 +1054,7 @@ pub const Constant = opaque {
|
|||||||
|
|
||||||
pub const get_sign_extended_value = api.LLVMConstIntGetSExtValue;
|
pub const get_sign_extended_value = api.LLVMConstIntGetSExtValue;
|
||||||
pub const get_zero_extended_value = api.LLVMConstIntGetZExtValue;
|
pub const get_zero_extended_value = api.LLVMConstIntGetZExtValue;
|
||||||
|
pub const negate = api.LLVMConstNeg;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Argument = opaque {
|
pub const Argument = opaque {
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
[extern] memcmp = fn [cc(c)] (a: &u8, b: &u8, byte_count: u64) s32;
|
||||||
|
|
||||||
|
string_no_match = #integer_max(u64);
|
||||||
|
|
||||||
c_string_length = fn (c_string: &u8) u64
|
c_string_length = fn (c_string: &u8) u64
|
||||||
{
|
{
|
||||||
>it = c_string;
|
>it = c_string;
|
||||||
@ -16,6 +20,35 @@ c_string_to_slice = fn (c_string: &u8) []u8
|
|||||||
return #slice(c_string, length);
|
return #slice(c_string, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string_equal = fn(a: []u8, b: []u8) u1
|
||||||
|
{
|
||||||
|
>result: #ReturnType() = 0;
|
||||||
|
|
||||||
|
if (a.length == b.length)
|
||||||
|
{
|
||||||
|
result = memcmp(a.pointer, b.pointer, a.length) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
string_last_character = fn(string: []u8, character: u8) u64
|
||||||
|
{
|
||||||
|
>i = string.length;
|
||||||
|
|
||||||
|
while (i > 0)
|
||||||
|
{
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
if (string[i] == character)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string_no_match;
|
||||||
|
}
|
||||||
|
|
||||||
OS_Linux_PROT = bits u32
|
OS_Linux_PROT = bits u32
|
||||||
{
|
{
|
||||||
read: u1,
|
read: u1,
|
||||||
@ -207,6 +240,17 @@ global_state_initialize = fn () void
|
|||||||
|
|
||||||
>relative_file_path = c_string_to_slice(relative_file_path_pointer);
|
>relative_file_path = c_string_to_slice(relative_file_path_pointer);
|
||||||
|
|
||||||
|
if (relative_file_path.length < 5)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
>extension_start = string_last_character(relative_file_path, '.');
|
||||||
|
if (extension_start == string_no_match)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
global_state_initialize();
|
global_state_initialize();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1103,6 +1103,13 @@ const Module = struct {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn negate_value_llvm(noalias module: *Module, value: *Value) *llvm.Value {
|
||||||
|
_ = module;
|
||||||
|
return switch (value.is_constant()) {
|
||||||
|
true => value.llvm.to_constant().negate().to_value(),
|
||||||
|
false => @trap(),
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const AttributeContainerType = enum {
|
const AttributeContainerType = enum {
|
||||||
@ -1817,12 +1824,16 @@ const Converter = struct {
|
|||||||
false => absolute_value,
|
false => absolute_value,
|
||||||
};
|
};
|
||||||
|
|
||||||
const integer_type = expected_type.llvm.handle.to_integer();
|
const integer_type = switch (expected_type.bb) {
|
||||||
const llvm_integer_value = integer_type.get_constant(value, @intFromBool(expected_type.bb.integer.signed));
|
.integer => expected_type,
|
||||||
|
.pointer => module.integer_type(64, false),
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
const llvm_integer_value = integer_type.llvm.handle.to_integer().get_constant(value, @intFromBool(integer_type.bb.integer.signed));
|
||||||
const integer_value = module.values.add();
|
const integer_value = module.values.add();
|
||||||
integer_value.* = .{
|
integer_value.* = .{
|
||||||
.llvm = llvm_integer_value.to_value(),
|
.llvm = llvm_integer_value.to_value(),
|
||||||
.type = expected_type,
|
.type = integer_type,
|
||||||
.bb = .{
|
.bb = .{
|
||||||
.constant_integer = .{
|
.constant_integer = .{
|
||||||
.value = absolute_value,
|
.value = absolute_value,
|
||||||
@ -2563,44 +2574,222 @@ const Converter = struct {
|
|||||||
|
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
|
|
||||||
switch (converter.content[converter.offset]) {
|
if (converter.consume_character_if_match(';')) {
|
||||||
'=' => {
|
const is_noreturn = v.type.bb == .noreturn;
|
||||||
// const left = v;
|
const is_valid = v.type.bb == .void or is_noreturn;
|
||||||
converter.expect_character('=');
|
if (!is_valid) {
|
||||||
|
converter.report_error();
|
||||||
|
}
|
||||||
|
|
||||||
converter.skip_space();
|
if (is_noreturn) {
|
||||||
|
_ = module.llvm.builder.create_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
const left = v;
|
require_semicolon = false;
|
||||||
if (left.type.bb != .pointer) {
|
} else {
|
||||||
converter.report_error();
|
const left = v;
|
||||||
}
|
if (left.type.bb != .pointer) {
|
||||||
const store_alignment = left.type.bb.pointer.alignment;
|
converter.report_error();
|
||||||
const store_type = left.type.bb.pointer.type;
|
}
|
||||||
const right = converter.parse_value(module, store_type, .value);
|
const store_alignment = left.type.bb.pointer.alignment;
|
||||||
|
const store_type = left.type.bb.pointer.type;
|
||||||
|
|
||||||
switch (store_type.get_evaluation_kind()) {
|
const AssignmentOperator = enum {
|
||||||
.aggregate => {
|
plain,
|
||||||
if (left.type.bb.pointer.type != right.type) {
|
pointer_add,
|
||||||
converter.report_error();
|
pointer_sub,
|
||||||
}
|
integer_add,
|
||||||
assert(right.lvalue);
|
integer_sub,
|
||||||
_ = module.llvm.builder.create_memcpy(left.llvm, left.type.bb.pointer.alignment, right.llvm, right.type.get_byte_alignment(), module.integer_type(64, false).llvm.handle.to_integer().get_constant(right.type.get_byte_size(), @intFromBool(false)).to_value());
|
integer_mul,
|
||||||
|
integer_udiv,
|
||||||
|
integer_sdiv,
|
||||||
|
integer_urem,
|
||||||
|
integer_srem,
|
||||||
|
shl,
|
||||||
|
ashr,
|
||||||
|
lshr,
|
||||||
|
@"and",
|
||||||
|
@"or",
|
||||||
|
xor,
|
||||||
|
};
|
||||||
|
|
||||||
|
const assignment_operator: AssignmentOperator = switch (converter.content[converter.offset]) {
|
||||||
|
'=' => .plain,
|
||||||
|
'+' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => switch (store_type.bb) {
|
||||||
|
.integer => .integer_add,
|
||||||
|
.pointer => .pointer_add,
|
||||||
|
else => @trap(),
|
||||||
},
|
},
|
||||||
else => _ = module.create_store(.{ .source_value = right.llvm, .destination_value = left.llvm, .source_type = store_type, .destination_type = store_type, .alignment = store_alignment }),
|
else => @trap(),
|
||||||
}
|
},
|
||||||
},
|
'-' => switch (converter.content[converter.offset + 1]) {
|
||||||
';' => {
|
'=' => switch (store_type.bb) {
|
||||||
const is_noreturn = v.type.bb == .noreturn;
|
.integer => .integer_sub,
|
||||||
const is_valid = v.type.bb == .void or is_noreturn;
|
.pointer => .pointer_sub,
|
||||||
if (!is_valid) {
|
else => @trap(),
|
||||||
converter.report_error();
|
},
|
||||||
}
|
else => @trap(),
|
||||||
|
},
|
||||||
|
'*' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => switch (store_type.bb) {
|
||||||
|
.integer => .integer_mul,
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
'/' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => switch (store_type.bb) {
|
||||||
|
.integer => |integer| switch (integer.signed) {
|
||||||
|
true => .integer_sdiv,
|
||||||
|
false => .integer_udiv,
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
'%' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => switch (store_type.bb) {
|
||||||
|
.integer => |integer| switch (integer.signed) {
|
||||||
|
true => .integer_srem,
|
||||||
|
false => .integer_urem,
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
'&' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => switch (store_type.bb) {
|
||||||
|
.integer => .@"and",
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
'|' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => switch (store_type.bb) {
|
||||||
|
.integer => .@"or",
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
'^' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => switch (store_type.bb) {
|
||||||
|
.integer => .xor,
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
'<' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'<' => switch (converter.content[converter.offset + 2]) {
|
||||||
|
'=' => switch (store_type.bb) {
|
||||||
|
.integer => .shl,
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
'>' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'>' => switch (converter.content[converter.offset + 2]) {
|
||||||
|
'=' => switch (store_type.bb) {
|
||||||
|
.integer => |integer| switch (integer.signed) {
|
||||||
|
true => .ashr,
|
||||||
|
false => .lshr,
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
|
||||||
if (is_noreturn) {
|
converter.offset += switch (assignment_operator) {
|
||||||
_ = module.llvm.builder.create_unreachable();
|
.plain,
|
||||||
}
|
=> 1,
|
||||||
},
|
.pointer_sub,
|
||||||
else => @trap(),
|
.pointer_add,
|
||||||
|
.integer_sub,
|
||||||
|
.integer_add,
|
||||||
|
.integer_mul,
|
||||||
|
.integer_udiv,
|
||||||
|
.integer_sdiv,
|
||||||
|
.integer_urem,
|
||||||
|
.integer_srem,
|
||||||
|
.@"and",
|
||||||
|
.@"or",
|
||||||
|
.xor,
|
||||||
|
=> 2,
|
||||||
|
.shl,
|
||||||
|
.ashr,
|
||||||
|
.lshr,
|
||||||
|
=> 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const right_side = converter.parse_value(module, store_type, .value);
|
||||||
|
const right_llvm = right_side.llvm;
|
||||||
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
const right = switch (assignment_operator) {
|
||||||
|
.plain => right_side,
|
||||||
|
else => |op| b: {
|
||||||
|
const left_load = module.create_load(.{ .type = store_type, .value = left.llvm });
|
||||||
|
const result = module.values.add();
|
||||||
|
const llvm_value = switch (op) {
|
||||||
|
.plain => unreachable,
|
||||||
|
.pointer_add => switch (right_side.type.bb) {
|
||||||
|
.integer => module.llvm.builder.create_gep(.{
|
||||||
|
.type = store_type.bb.pointer.type.llvm.handle,
|
||||||
|
.aggregate = left_load,
|
||||||
|
.indices = &.{right_llvm},
|
||||||
|
}),
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
.pointer_sub => switch (right_side.type.bb) {
|
||||||
|
.integer => module.llvm.builder.create_gep(.{
|
||||||
|
.type = store_type.bb.pointer.type.llvm.handle,
|
||||||
|
.aggregate = left_load,
|
||||||
|
.indices = &.{module.negate_value_llvm(right_side)},
|
||||||
|
}),
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
.integer_add => module.llvm.builder.create_add(left_load, right_llvm),
|
||||||
|
.integer_sub => module.llvm.builder.create_sub(left_load, right_llvm),
|
||||||
|
.integer_mul => module.llvm.builder.create_mul(left_load, right_llvm),
|
||||||
|
.integer_udiv => module.llvm.builder.create_udiv(left_load, right_llvm),
|
||||||
|
.integer_sdiv => module.llvm.builder.create_udiv(left_load, right_llvm),
|
||||||
|
.integer_urem => module.llvm.builder.create_urem(left_load, right_llvm),
|
||||||
|
.integer_srem => module.llvm.builder.create_urem(left_load, right_llvm),
|
||||||
|
.lshr => module.llvm.builder.create_lshr(left_load, right_llvm),
|
||||||
|
.ashr => module.llvm.builder.create_ashr(left_load, right_llvm),
|
||||||
|
.shl => module.llvm.builder.create_shl(left_load, right_llvm),
|
||||||
|
.@"and" => module.llvm.builder.create_and(left_load, right_llvm),
|
||||||
|
.@"or" => module.llvm.builder.create_or(left_load, right_llvm),
|
||||||
|
.xor => module.llvm.builder.create_xor(left_load, right_llvm),
|
||||||
|
};
|
||||||
|
result.* = .{
|
||||||
|
.llvm = llvm_value,
|
||||||
|
.type = store_type,
|
||||||
|
.bb = .instruction,
|
||||||
|
.lvalue = false,
|
||||||
|
.dereference_to_assign = false,
|
||||||
|
};
|
||||||
|
break :b result;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (store_type.get_evaluation_kind()) {
|
||||||
|
.aggregate => {
|
||||||
|
if (store_type != right.type) {
|
||||||
|
converter.report_error();
|
||||||
|
}
|
||||||
|
assert(right.lvalue);
|
||||||
|
_ = module.llvm.builder.create_memcpy(left.llvm, store_alignment, right.llvm, right.type.get_byte_alignment(), module.integer_type(64, false).llvm.handle.to_integer().get_constant(right.type.get_byte_size(), @intFromBool(false)).to_value());
|
||||||
|
},
|
||||||
|
else => _ = module.create_store(.{ .source_value = right.llvm, .destination_value = left.llvm, .source_type = store_type, .destination_type = store_type, .alignment = store_alignment }),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2634,13 +2823,31 @@ const Converter = struct {
|
|||||||
xor,
|
xor,
|
||||||
integer_compare_equal,
|
integer_compare_equal,
|
||||||
integer_compare_not_equal,
|
integer_compare_not_equal,
|
||||||
|
integer_compare_unsigned_greater_than,
|
||||||
|
integer_compare_unsigned_greater_equal,
|
||||||
|
integer_compare_unsigned_less_than,
|
||||||
|
integer_compare_unsigned_less_equal,
|
||||||
|
integer_compare_signed_greater_than,
|
||||||
|
integer_compare_signed_greater_equal,
|
||||||
|
integer_compare_signed_less_than,
|
||||||
|
integer_compare_signed_less_equal,
|
||||||
pointer_add,
|
pointer_add,
|
||||||
|
|
||||||
pub fn to_int_predicate(expression_state: ExpressionState) llvm.IntPredicate {
|
pub fn to_int_predicate(expression_state: ExpressionState) llvm.IntPredicate {
|
||||||
return switch (expression_state) {
|
return switch (expression_state) {
|
||||||
.integer_compare_not_equal => .ne,
|
.integer_compare_not_equal => .ne,
|
||||||
.integer_compare_equal => .eq,
|
.integer_compare_equal => .eq,
|
||||||
else => @trap(),
|
|
||||||
|
.integer_compare_unsigned_greater_than => .ugt,
|
||||||
|
.integer_compare_unsigned_greater_equal => .uge,
|
||||||
|
.integer_compare_unsigned_less_than => .ult,
|
||||||
|
.integer_compare_unsigned_less_equal => .ule,
|
||||||
|
|
||||||
|
.integer_compare_signed_greater_than => .sgt,
|
||||||
|
.integer_compare_signed_greater_equal => .sge,
|
||||||
|
.integer_compare_signed_less_than => .slt,
|
||||||
|
.integer_compare_signed_less_equal => .sle,
|
||||||
|
else => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2706,7 +2913,17 @@ const Converter = struct {
|
|||||||
.@"and" => module.llvm.builder.create_and(left, right),
|
.@"and" => module.llvm.builder.create_and(left, right),
|
||||||
.@"or" => module.llvm.builder.create_or(left, right),
|
.@"or" => module.llvm.builder.create_or(left, right),
|
||||||
.xor => module.llvm.builder.create_xor(left, right),
|
.xor => module.llvm.builder.create_xor(left, right),
|
||||||
.integer_compare_equal, .integer_compare_not_equal => |icmp| module.llvm.builder.create_compare(icmp.to_int_predicate(), left, right),
|
.integer_compare_equal,
|
||||||
|
.integer_compare_not_equal,
|
||||||
|
.integer_compare_unsigned_greater_than,
|
||||||
|
.integer_compare_unsigned_greater_equal,
|
||||||
|
.integer_compare_unsigned_less_than,
|
||||||
|
.integer_compare_unsigned_less_equal,
|
||||||
|
.integer_compare_signed_greater_than,
|
||||||
|
.integer_compare_signed_greater_equal,
|
||||||
|
.integer_compare_signed_less_than,
|
||||||
|
.integer_compare_signed_less_equal,
|
||||||
|
=> |icmp| module.llvm.builder.create_compare(icmp.to_int_predicate(), left, right),
|
||||||
.pointer_add => module.llvm.builder.create_gep(.{
|
.pointer_add => module.llvm.builder.create_gep(.{
|
||||||
.type = next_ty.bb.pointer.type.llvm.handle,
|
.type = next_ty.bb.pointer.type.llvm.handle,
|
||||||
.aggregate = left,
|
.aggregate = left,
|
||||||
@ -2723,7 +2940,17 @@ const Converter = struct {
|
|||||||
.llvm = llvm_value,
|
.llvm = llvm_value,
|
||||||
.type = switch (value_state) {
|
.type = switch (value_state) {
|
||||||
.none => unreachable,
|
.none => unreachable,
|
||||||
.integer_compare_equal, .integer_compare_not_equal => module.integer_type(1, false),
|
.integer_compare_equal,
|
||||||
|
.integer_compare_not_equal,
|
||||||
|
.integer_compare_unsigned_greater_than,
|
||||||
|
.integer_compare_unsigned_greater_equal,
|
||||||
|
.integer_compare_unsigned_less_than,
|
||||||
|
.integer_compare_unsigned_less_equal,
|
||||||
|
.integer_compare_signed_greater_than,
|
||||||
|
.integer_compare_signed_greater_equal,
|
||||||
|
.integer_compare_signed_less_than,
|
||||||
|
.integer_compare_signed_less_equal,
|
||||||
|
=> module.integer_type(1, false),
|
||||||
.integer_sub,
|
.integer_sub,
|
||||||
.integer_add,
|
.integer_add,
|
||||||
.integer_mul,
|
.integer_mul,
|
||||||
@ -2748,107 +2975,150 @@ const Converter = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ch = converter.content[converter.offset];
|
const ch = converter.content[converter.offset];
|
||||||
value_state = switch (ch) {
|
// If an assignment operator (it being simple or compound, like +=, -=, &=, etc.) is found, then we break
|
||||||
',', ';', right_parenthesis, right_bracket, right_brace => break previous_value.?,
|
const new_value_state: ExpressionState = switch (ch) {
|
||||||
|
',', ';', right_parenthesis, right_bracket, right_brace => .none,
|
||||||
'=' => switch (converter.content[converter.offset + 1]) {
|
'=' => switch (converter.content[converter.offset + 1]) {
|
||||||
'=' => blk: {
|
'=' => .integer_compare_equal,
|
||||||
converter.offset += 2;
|
else => .none,
|
||||||
break :blk .integer_compare_equal;
|
|
||||||
},
|
|
||||||
else => break previous_value.?,
|
|
||||||
},
|
},
|
||||||
'-' => blk: {
|
'-' => switch (converter.content[converter.offset + 1]) {
|
||||||
converter.offset += 1;
|
'=' => .none,
|
||||||
break :blk .integer_sub;
|
else => .integer_sub,
|
||||||
},
|
},
|
||||||
'+' => blk: {
|
'+' => switch (converter.content[converter.offset + 1]) {
|
||||||
converter.offset += 1;
|
'=' => .none,
|
||||||
break :blk switch (next_ty.bb) {
|
else => switch (next_ty.bb) {
|
||||||
.integer => .integer_add,
|
.integer => .integer_add,
|
||||||
.pointer => .pointer_add,
|
.pointer => .pointer_add,
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
};
|
},
|
||||||
},
|
},
|
||||||
'*' => blk: {
|
'*' => switch (converter.content[converter.offset + 1]) {
|
||||||
converter.offset += 1;
|
'=' => .none,
|
||||||
break :blk .integer_mul;
|
else => switch (next_ty.bb) {
|
||||||
|
.integer => .integer_mul,
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'/' => blk: {
|
'/' => switch (converter.content[converter.offset + 1]) {
|
||||||
converter.offset += 1;
|
'=' => .none,
|
||||||
const ty = iterative_expected_type orelse unreachable;
|
else => switch (next_ty.bb) {
|
||||||
break :blk switch (ty.bb) {
|
|
||||||
.integer => |int| switch (int.signed) {
|
.integer => |int| switch (int.signed) {
|
||||||
true => .integer_sdiv,
|
true => .integer_sdiv,
|
||||||
false => .integer_udiv,
|
false => .integer_udiv,
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => @trap(),
|
||||||
};
|
},
|
||||||
},
|
},
|
||||||
'%' => blk: {
|
'%' => switch (converter.content[converter.offset + 1]) {
|
||||||
converter.offset += 1;
|
'=' => .none,
|
||||||
const ty = iterative_expected_type orelse unreachable;
|
else => switch (next_ty.bb) {
|
||||||
break :blk switch (ty.bb) {
|
|
||||||
.integer => |int| switch (int.signed) {
|
.integer => |int| switch (int.signed) {
|
||||||
true => .integer_srem,
|
true => .integer_srem,
|
||||||
false => .integer_urem,
|
false => .integer_urem,
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => @trap(),
|
||||||
};
|
},
|
||||||
},
|
},
|
||||||
'<' => blk: {
|
'<' => switch (converter.content[converter.offset + 1]) {
|
||||||
converter.offset += 1;
|
'<' => switch (converter.content[converter.offset + 2]) {
|
||||||
|
'=' => .none,
|
||||||
break :blk switch (converter.content[converter.offset]) {
|
else => .shl,
|
||||||
'<' => b: {
|
},
|
||||||
converter.offset += 1;
|
'=' => switch (next_ty.bb) {
|
||||||
break :b .shl;
|
.integer => |int| switch (int.signed) {
|
||||||
|
true => .integer_compare_signed_less_equal,
|
||||||
|
false => .integer_compare_unsigned_less_equal,
|
||||||
},
|
},
|
||||||
else => os.abort(),
|
else => @trap(),
|
||||||
};
|
},
|
||||||
},
|
else => switch (next_ty.bb) {
|
||||||
'>' => blk: {
|
.integer => |int| switch (int.signed) {
|
||||||
converter.offset += 1;
|
true => .integer_compare_signed_less_than,
|
||||||
|
false => .integer_compare_unsigned_less_than,
|
||||||
break :blk switch (converter.content[converter.offset]) {
|
|
||||||
'>' => b: {
|
|
||||||
converter.offset += 1;
|
|
||||||
const ty = iterative_expected_type orelse unreachable;
|
|
||||||
break :b switch (ty.bb) {
|
|
||||||
.integer => |int| switch (int.signed) {
|
|
||||||
true => .ashr,
|
|
||||||
false => .lshr,
|
|
||||||
},
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
else => os.abort(),
|
else => @trap(),
|
||||||
};
|
},
|
||||||
},
|
},
|
||||||
'&' => blk: {
|
'>' => switch (converter.content[converter.offset + 1]) {
|
||||||
converter.offset += 1;
|
'>' => switch (converter.content[converter.offset + 2]) {
|
||||||
break :blk .@"and";
|
'=' => .none,
|
||||||
},
|
else => switch (next_ty.bb) {
|
||||||
'|' => blk: {
|
.integer => |integer| switch (integer.signed) {
|
||||||
converter.offset += 1;
|
true => .ashr,
|
||||||
break :blk .@"or";
|
false => .lshr,
|
||||||
},
|
},
|
||||||
'^' => blk: {
|
else => @trap(),
|
||||||
converter.offset += 1;
|
|
||||||
break :blk .xor;
|
|
||||||
},
|
|
||||||
'!' => blk: {
|
|
||||||
converter.offset += 1;
|
|
||||||
break :blk switch (converter.content[converter.offset]) {
|
|
||||||
'=' => b: {
|
|
||||||
converter.offset += 1;
|
|
||||||
break :b .integer_compare_not_equal;
|
|
||||||
},
|
},
|
||||||
else => os.abort(),
|
},
|
||||||
};
|
'=' => switch (next_ty.bb) {
|
||||||
|
.integer => |int| switch (int.signed) {
|
||||||
|
true => .integer_compare_signed_greater_equal,
|
||||||
|
false => .integer_compare_unsigned_greater_equal,
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => switch (next_ty.bb) {
|
||||||
|
.integer => |int| switch (int.signed) {
|
||||||
|
true => .integer_compare_signed_greater_than,
|
||||||
|
false => .integer_compare_unsigned_greater_than,
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
else => os.abort(),
|
'&' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => .none,
|
||||||
|
else => .@"and",
|
||||||
|
},
|
||||||
|
'|' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => .none,
|
||||||
|
else => .@"or",
|
||||||
|
},
|
||||||
|
'^' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => .none,
|
||||||
|
else => .xor,
|
||||||
|
},
|
||||||
|
'!' => switch (converter.content[converter.offset + 1]) {
|
||||||
|
'=' => switch (next_ty.bb) {
|
||||||
|
.integer, .pointer => .integer_compare_not_equal,
|
||||||
|
else => @trap(),
|
||||||
|
},
|
||||||
|
else => converter.report_error(),
|
||||||
|
},
|
||||||
|
else => converter.report_error(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
converter.offset += switch (new_value_state) {
|
||||||
|
.none => break previous_value.?,
|
||||||
|
.pointer_add,
|
||||||
|
.integer_sub,
|
||||||
|
.integer_add,
|
||||||
|
.integer_mul,
|
||||||
|
.integer_udiv,
|
||||||
|
.integer_sdiv,
|
||||||
|
.integer_urem,
|
||||||
|
.integer_srem,
|
||||||
|
.integer_compare_unsigned_greater_than,
|
||||||
|
.integer_compare_unsigned_greater_equal,
|
||||||
|
.integer_compare_unsigned_less_than,
|
||||||
|
.integer_compare_unsigned_less_equal,
|
||||||
|
.integer_compare_signed_greater_than,
|
||||||
|
.integer_compare_signed_greater_equal,
|
||||||
|
.integer_compare_signed_less_than,
|
||||||
|
.integer_compare_signed_less_equal,
|
||||||
|
.@"and",
|
||||||
|
.@"or",
|
||||||
|
.xor,
|
||||||
|
=> 1,
|
||||||
|
.integer_compare_equal,
|
||||||
|
.integer_compare_not_equal,
|
||||||
|
.ashr,
|
||||||
|
.lshr,
|
||||||
|
.shl,
|
||||||
|
=> 2,
|
||||||
|
};
|
||||||
|
value_state = new_value_state;
|
||||||
converter.skip_space();
|
converter.skip_space();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4963,7 +5233,6 @@ pub const Abi = struct {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
// .anonymous_struct => unreachable,
|
|
||||||
else => return false,
|
else => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5172,7 +5441,6 @@ pub const Abi = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var high: ?*Type = null;
|
var high: ?*Type = null;
|
||||||
_ = &high;
|
|
||||||
|
|
||||||
switch (classes[1]) {
|
switch (classes[1]) {
|
||||||
.none => {},
|
.none => {},
|
||||||
@ -6271,49 +6539,45 @@ pub noinline fn convert(arena: *Arena, options: ConvertOptions) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!global_keyword) {
|
if (!global_keyword) {
|
||||||
if (global_type) |expected_type| {
|
const value = converter.parse_value(module, global_type, .value);
|
||||||
const value = converter.parse_value(module, expected_type, .value);
|
const expected_type = global_type orelse value.type;
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
converter.skip_space();
|
converter.expect_character(';');
|
||||||
|
|
||||||
converter.expect_character(';');
|
const global_variable = module.llvm.handle.create_global_variable(.{
|
||||||
|
.linkage = switch (is_export) {
|
||||||
|
true => .ExternalLinkage,
|
||||||
|
false => .InternalLinkage,
|
||||||
|
},
|
||||||
|
.name = global_name,
|
||||||
|
.initial_value = value.llvm.to_constant(),
|
||||||
|
.type = expected_type.llvm.handle,
|
||||||
|
});
|
||||||
|
global_variable.to_value().set_alignment(@intCast(expected_type.get_byte_alignment()));
|
||||||
|
|
||||||
const global_variable = module.llvm.handle.create_global_variable(.{
|
if (module.llvm.di_builder) |di_builder| {
|
||||||
.linkage = switch (is_export) {
|
const linkage_name = global_name;
|
||||||
true => .ExternalLinkage,
|
const local_to_unit = !(is_export or is_extern);
|
||||||
false => .InternalLinkage,
|
const alignment = 0; // TODO
|
||||||
},
|
const global_variable_expression = di_builder.create_global_variable(module.llvm.global_scope, global_name, linkage_name, module.llvm.file, global_line, expected_type.llvm.debug, local_to_unit, di_builder.null_expression(), alignment);
|
||||||
.name = global_name,
|
global_variable.add_debug_info(global_variable_expression);
|
||||||
.initial_value = value.llvm.to_constant(),
|
|
||||||
.type = expected_type.llvm.handle,
|
|
||||||
});
|
|
||||||
global_variable.to_value().set_alignment(@intCast(expected_type.get_byte_alignment()));
|
|
||||||
|
|
||||||
if (module.llvm.di_builder) |di_builder| {
|
|
||||||
const linkage_name = global_name;
|
|
||||||
const local_to_unit = !(is_export or is_extern);
|
|
||||||
const alignment = 0; // TODO
|
|
||||||
const global_variable_expression = di_builder.create_global_variable(module.llvm.global_scope, global_name, linkage_name, module.llvm.file, global_line, expected_type.llvm.debug, local_to_unit, di_builder.null_expression(), alignment);
|
|
||||||
global_variable.add_debug_info(global_variable_expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
const global_value = module.values.add();
|
|
||||||
global_value.* = .{
|
|
||||||
.llvm = global_variable.to_value(),
|
|
||||||
.type = module.get_pointer_type(.{ .type = expected_type }),
|
|
||||||
.bb = .global,
|
|
||||||
.lvalue = true,
|
|
||||||
.dereference_to_assign = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const global = module.globals.add();
|
|
||||||
global.* = .{
|
|
||||||
.name = global_name,
|
|
||||||
.value = global_value,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
converter.report_error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const global_value = module.values.add();
|
||||||
|
global_value.* = .{
|
||||||
|
.llvm = global_variable.to_value(),
|
||||||
|
.type = module.get_pointer_type(.{ .type = expected_type }),
|
||||||
|
.bb = .global,
|
||||||
|
.lvalue = true,
|
||||||
|
.dereference_to_assign = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const global = module.globals.add();
|
||||||
|
global.* = .{
|
||||||
|
.name = global_name,
|
||||||
|
.value = global_value,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,3 +451,7 @@ test "basic_while" {
|
|||||||
test "c_string_to_slice" {
|
test "c_string_to_slice" {
|
||||||
try invsrc(@src());
|
try invsrc(@src());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "assignment_operators" {
|
||||||
|
try invsrc(@src());
|
||||||
|
}
|
||||||
|
@ -187,6 +187,7 @@ pub extern fn llvm_integer_type_get_bit_count(integer_type: *llvm.Type.Integer)
|
|||||||
|
|
||||||
// VALUES
|
// VALUES
|
||||||
pub extern fn LLVMGetPoison(type: *llvm.Type) *llvm.Value;
|
pub extern fn LLVMGetPoison(type: *llvm.Type) *llvm.Value;
|
||||||
|
pub extern fn LLVMConstNeg(constant: *llvm.Constant) *llvm.Constant;
|
||||||
pub extern fn LLVMConstNull(type: *llvm.Type) *llvm.Constant;
|
pub extern fn LLVMConstNull(type: *llvm.Type) *llvm.Constant;
|
||||||
pub extern fn LLVMConstInt(type: *llvm.Type.Integer, value: c_ulonglong, sign_extend: Bool) *llvm.Constant.Integer;
|
pub extern fn LLVMConstInt(type: *llvm.Type.Integer, value: c_ulonglong, sign_extend: Bool) *llvm.Constant.Integer;
|
||||||
pub extern fn LLVMConstIntGetZExtValue(constant: *llvm.Constant) u64;
|
pub extern fn LLVMConstIntGetZExtValue(constant: *llvm.Constant) u64;
|
||||||
|
35
tests/assignment_operators.bbb
Normal file
35
tests/assignment_operators.bbb
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
unsigned = fn(n: s32) s32
|
||||||
|
{
|
||||||
|
>result: u32 = #extend(n);
|
||||||
|
result >>= 1;
|
||||||
|
result <<= 1;
|
||||||
|
result ^= 1;
|
||||||
|
result |= 1;
|
||||||
|
result &= 1;
|
||||||
|
result += 1;
|
||||||
|
result -= 1;
|
||||||
|
result /= 1;
|
||||||
|
result %= 1;
|
||||||
|
result *= 0;
|
||||||
|
|
||||||
|
return #extend(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>result: s32 = 0;
|
||||||
|
>pointer = &result;
|
||||||
|
pointer -= 1;
|
||||||
|
pointer += 1;
|
||||||
|
result >>= 1;
|
||||||
|
result <<= 1;
|
||||||
|
result ^= 1;
|
||||||
|
result |= 1;
|
||||||
|
result &= 1;
|
||||||
|
result += 1;
|
||||||
|
result -= 1;
|
||||||
|
result /= 1;
|
||||||
|
result %= 1;
|
||||||
|
result *= 0;
|
||||||
|
return unsigned(result);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user