Assignment operators

This commit is contained in:
David Gonzalez Martin 2025-03-26 18:19:26 +01:00
parent cb12fa62fe
commit 17918ce4e3
6 changed files with 505 additions and 156 deletions

View File

@ -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 {

View File

@ -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;
} }

View File

@ -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,
};
} }
} }

View File

@ -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());
}

View File

@ -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;

View 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);
}