Compare commits

..

1 Commits

Author SHA1 Message Date
408d53a6f9 String to enum
All checks were successful
CI / ci (ReleaseFast, ubuntu-latest) (pull_request) Successful in 2m3s
CI / ci (ReleaseSmall, ubuntu-latest) (pull_request) Successful in 2m3s
CI / ci (ReleaseSafe, ubuntu-latest) (pull_request) Successful in 2m7s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 3m12s
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 2m2s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 2m0s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 2m7s
CI / ci (Debug, ubuntu-latest) (push) Successful in 3m10s
2025-04-17 12:05:02 -06:00

View File

@ -242,8 +242,7 @@ pub const Type = struct {
const Kind = enum {
abi,
storage,
loose,
memory,
};
const LLVM = struct {
@ -282,6 +281,13 @@ pub const Type = struct {
};
}
pub fn get_llvm(ty: *Type, kind: Kind) *llvm.Type {
return switch (kind) {
.abi => ty.llvm.abi.?,
.memory => ty.llvm.memory.?,
};
}
fn resolve(ty: *Type, module: *Module) void {
if (ty.llvm.abi == null) {
const abi_type = switch (ty.bb) {
@ -3896,7 +3902,7 @@ pub const Module = struct {
.intrinsic => |intrinsic| switch (intrinsic) {
.va_arg => |va_arg| {
const raw_va_list_type = module.get_va_list_type();
module.emit_value(function, va_arg.list);
module.emit_value(function, va_arg.list, .memory);
const uint64 = module.integer_type(64, false);
uint64.resolve(module);
const va_list = module.llvm.builder.create_gep(.{
@ -4112,7 +4118,7 @@ pub const Module = struct {
const coerce_to_type = argument_abi.get_coerce_to_type();
coerce_to_type.resolve(module);
if (coerce_to_type.bb != .structure and semantic_argument_type.is_abi_equal(coerce_to_type, module) and argument_abi.attributes.direct.offset == 0) {
module.emit_value(function, semantic_argument_value);
module.emit_value(function, semantic_argument_value, .memory);
var v = switch (argument_abi.semantic_type.get_evaluation_kind()) {
.aggregate => @trap(),
else => semantic_argument_value,
@ -4162,7 +4168,7 @@ pub const Module = struct {
module.analyze_value_type(function, src, .{});
}
}
module.emit_value(function, semantic_argument_value);
module.emit_value(function, semantic_argument_value, .memory);
const destination_size = coerce_to_type.get_byte_size();
const source_size = argument_abi.semantic_type.get_byte_size();
@ -4246,7 +4252,7 @@ pub const Module = struct {
src.kind = .left;
module.analyze_value_type(function, src, .{});
}
module.emit_value(function, src);
module.emit_value(function, src, .memory);
assert(src.type.?.bb == .pointer);
const source_type = src.type.?.bb.pointer.type;
@ -4281,7 +4287,7 @@ pub const Module = struct {
@trap();
} else if (abi_argument_type.bb == .pointer and abi_argument_type.bb.pointer.type == semantic_argument_value.type) switch (semantic_argument_value.is_constant()) {
true => {
module.emit_value(function, semantic_argument_value);
module.emit_value(function, semantic_argument_value, .memory);
const global_variable = module.llvm.module.create_global_variable(.{
.linkage = .InternalLinkage,
.name = "conststruct", // TODO: format properly
@ -4300,7 +4306,7 @@ pub const Module = struct {
const pointer_type = module.get_pointer_type(.{ .type = semantic_argument_value.type.? });
semantic_argument_value.type = null;
semantic_argument_value.kind = .left;
module.analyze(function, semantic_argument_value, .{ .type = pointer_type });
module.analyze(function, semantic_argument_value, .{ .type = pointer_type }, .memory);
llvm_abi_argument_value_buffer[abi_argument_count] = semantic_argument_value.llvm.?;
abi_argument_count += 1;
break :indirect;
@ -4925,7 +4931,7 @@ pub const Module = struct {
}
},
.global => {
module.analyze(null, global.variable.initial_value, .{ .type = global.variable.type });
module.analyze(null, global.variable.initial_value, .{ .type = global.variable.type }, .memory);
if (global.variable.type == null) {
global.variable.type = global.variable.initial_value.type;
@ -5077,9 +5083,9 @@ pub const Module = struct {
type: ?*Type = null,
};
pub fn analyze(module: *Module, function: ?*Global, value: *Value, analysis: ValueAnalysis) void {
pub fn analyze(module: *Module, function: ?*Global, value: *Value, analysis: ValueAnalysis, type_kind: Type.Kind) void {
module.analyze_value_type(function, value, analysis);
module.emit_value(function, value);
module.emit_value(function, value, type_kind);
}
pub fn analyze_value_type(module: *Module, function: ?*Global, value: *Value, analysis: ValueAnalysis) void {
@ -5969,15 +5975,15 @@ pub const Module = struct {
const value_type = value.type.?;
switch (value.bb) {
.slice_expression => |slice_expression| {
module.emit_value(function, slice_expression.array_like);
module.emit_value(function, slice_expression.array_like, .memory);
switch (slice_expression.array_like.type.?.bb) {
.pointer => |pointer| switch (slice_expression.array_like.kind) {
.left => @trap(),
.right => {
const start = slice_expression.start;
module.emit_value(function, start);
module.emit_value(function, start, .memory);
const end = slice_expression.end orelse module.report_error();
module.emit_value(function, end);
module.emit_value(function, end, .memory);
const slice_pointer = module.llvm.builder.create_gep(.{
.type = pointer.type.llvm.memory.?,
.aggregate = slice_expression.array_like.llvm.?,
@ -6002,7 +6008,7 @@ pub const Module = struct {
// TODO: consider if we should emit an error here or it be a NOP
module.report_error();
} else {
module.emit_value(function, slice_expression.start);
module.emit_value(function, slice_expression.start, .memory);
const old_slice_pointer = module.llvm.builder.create_extract_value(slice_expression.array_like.llvm.?, 0);
const old_slice_length = module.llvm.builder.create_extract_value(slice_expression.array_like.llvm.?, 1);
const slice_pointer = module.llvm.builder.create_gep(.{
@ -6023,34 +6029,34 @@ pub const Module = struct {
}
}
pub fn emit_value(module: *Module, function: ?*Global, value: *Value) void {
pub fn emit_value(module: *Module, function: ?*Global, value: *Value, type_kind: Type.Kind) void {
const value_type = value.type orelse unreachable;
assert(value.llvm == null);
value_type.resolve(module);
const llvm_value: *llvm.Value = switch (value.bb) {
.constant_integer => |constant_integer| value_type.llvm.abi.?.to_integer().get_constant(constant_integer.value, @intFromBool(constant_integer.signed)).to_value(),
.constant_integer => |constant_integer| value_type.get_llvm(type_kind).to_integer().get_constant(constant_integer.value, @intFromBool(constant_integer.signed)).to_value(),
.unary => |unary| switch (unary.id) {
.@"-" => blk: {
const unary_value = unary.value.llvm orelse b: {
module.emit_value(function, unary.value);
module.emit_value(function, unary.value, type_kind);
break :b unary.value.llvm orelse unreachable;
};
break :blk module.negate_llvm_value(unary_value, unary.value.is_constant());
},
.@"&" => blk: {
assert(value_type == unary.value.type);
module.emit_value(function, unary.value);
module.emit_value(function, unary.value, type_kind);
break :blk unary.value.llvm orelse unreachable;
},
.@"!" => switch (unary.value.type == value_type) {
true => b: {
module.emit_value(function, unary.value);
module.emit_value(function, unary.value, type_kind);
break :b module.llvm.builder.create_not(unary.value.llvm.?);
},
false => switch (unary.value.type.?.bb) {
.pointer => b: {
module.emit_value(function, unary.value);
module.emit_value(function, unary.value, type_kind);
break :b module.llvm.builder.create_integer_compare(.eq, unary.value.llvm.?, unary.value.type.?.llvm.abi.?.get_zero().to_value());
},
else => @trap(),
@ -6060,11 +6066,11 @@ pub const Module = struct {
},
.binary => |binary| blk: {
const left = if (binary.left.llvm) |left_llvm| left_llvm else b: {
module.emit_value(function, binary.left);
module.emit_value(function, binary.left, .abi);
break :b binary.left.llvm orelse unreachable;
};
const right = if (binary.right.llvm) |right_llvm| right_llvm else b: {
module.emit_value(function, binary.right);
module.emit_value(function, binary.right, .abi);
break :b binary.right.llvm orelse unreachable;
};
const result = switch (value_type.bb) {
@ -6176,7 +6182,7 @@ pub const Module = struct {
},
.extend => |extended_value| blk: {
if (extended_value.llvm == null) {
module.emit_value(function, extended_value);
module.emit_value(function, extended_value, type_kind);
}
const llvm_value = extended_value.llvm orelse unreachable;
const destination_type = value_type.llvm.abi.?;
@ -6194,20 +6200,20 @@ pub const Module = struct {
break :blk constant_integer.to_value();
},
.int_from_enum => |enum_value| blk: {
module.emit_value(function, enum_value);
module.emit_value(function, enum_value, type_kind);
break :blk enum_value.llvm.?;
},
.int_from_pointer => |pointer_value| blk: {
module.emit_value(function, pointer_value);
module.emit_value(function, pointer_value, type_kind);
const int = module.llvm.builder.create_ptr_to_int(pointer_value.llvm.?, value_type.llvm.abi.?);
break :blk int;
},
.pointer_cast => |pointer_value| blk: {
module.emit_value(function, pointer_value);
module.emit_value(function, pointer_value, type_kind);
break :blk pointer_value.llvm.?;
},
.select => |select| blk: {
module.emit_value(function, select.condition);
module.emit_value(function, select.condition, type_kind);
const condition = switch (select.condition.type.?.bb) {
.integer => |integer| switch (integer.bit_count) {
1 => select.condition.llvm.?,
@ -6215,13 +6221,13 @@ pub const Module = struct {
},
else => @trap(),
};
module.emit_value(function, select.true_value);
module.emit_value(function, select.false_value);
module.emit_value(function, select.true_value, type_kind);
module.emit_value(function, select.false_value, type_kind);
const result = module.llvm.builder.create_select(condition, select.true_value.llvm.?, select.false_value.llvm.?);
break :blk result;
},
.string_to_enum => |string_to_enum| blk: {
module.emit_value(function, string_to_enum.string_value);
module.emit_value(function, string_to_enum.string_value, type_kind);
const s2e = string_to_enum.enum_type.bb.enumerator.string_to_enum orelse unreachable;
const first_field = module.llvm.builder.create_extract_value(string_to_enum.string_value.llvm.?, 0);
const second_field = module.llvm.builder.create_extract_value(string_to_enum.string_value.llvm.?, 1);
@ -6244,7 +6250,7 @@ pub const Module = struct {
},
.truncate => |value_to_truncate| blk: {
if (value_to_truncate.llvm == null) {
module.emit_value(function, value_to_truncate);
module.emit_value(function, value_to_truncate, type_kind);
}
const llvm_value = value_to_truncate.llvm orelse unreachable;
const truncate = module.llvm.builder.create_truncate(llvm_value, value_type.llvm.abi.?);
@ -6252,7 +6258,7 @@ pub const Module = struct {
},
.va_arg => module.emit_va_arg(function.?, value, null, null),
.va_end => |va_list| blk: {
module.emit_value(function, va_list);
module.emit_value(function, va_list, .memory);
const intrinsic_id = module.llvm.intrinsic_table.va_end;
const argument_types: []const *llvm.Type = &.{module.llvm.pointer_type};
@ -6265,7 +6271,7 @@ pub const Module = struct {
else => @trap(),
},
.dereference => |dereferenceable_value| blk: {
module.emit_value(function, dereferenceable_value);
module.emit_value(function, dereferenceable_value, .memory);
const result = switch (value.kind) {
.left => @trap(),
.right => module.create_load(.{
@ -6283,7 +6289,7 @@ pub const Module = struct {
const element_count = array_initialization.values.len;
const llvm_values = llvm_value_buffer[0..element_count];
for (array_initialization.values, llvm_values) |v, *llvm_value| {
module.emit_value(function, v);
module.emit_value(function, v, .memory);
llvm_value.* = v.llvm.?.to_constant();
}
value_type.bb.array.element_type.resolve(module);
@ -6296,8 +6302,8 @@ pub const Module = struct {
.left => switch (array_expression.array_like.type.?.bb) {
.pointer => |pointer| switch (pointer.type.bb) {
.array => |array| blk: {
module.emit_value(function, array_expression.array_like);
module.emit_value(function, array_expression.index);
module.emit_value(function, array_expression.array_like, .memory);
module.emit_value(function, array_expression.index, .memory);
const uint64 = module.integer_type(64, false);
uint64.resolve(module);
const zero_index = uint64.llvm.abi.?.to_integer().get_constant(0, @intFromBool(false)).to_value();
@ -6316,8 +6322,8 @@ pub const Module = struct {
},
.structure => |structure| blk: {
assert(structure.is_slice);
module.emit_value(function, array_expression.array_like);
module.emit_value(function, array_expression.index);
module.emit_value(function, array_expression.array_like, .memory);
module.emit_value(function, array_expression.index, .memory);
const pointer_type = structure.fields[0].type;
const element_type = pointer_type.bb.pointer.type;
const pointer_load = module.create_load(.{ .type = structure.fields[0].type, .value = array_expression.array_like.llvm.? });
@ -6336,8 +6342,8 @@ pub const Module = struct {
};
},
.pointer => |real_pointer| blk: {
module.emit_value(function, array_expression.array_like);
module.emit_value(function, array_expression.index);
module.emit_value(function, array_expression.array_like, .memory);
module.emit_value(function, array_expression.index, .memory);
// TODO: consider not emitting the and doing straight GEP?
const pointer_load = module.create_load(.{ .type = pointer.type, .value = array_expression.array_like.llvm.? });
const element_type = real_pointer.type;
@ -6360,8 +6366,8 @@ pub const Module = struct {
},
.right => switch (array_expression.array_like.type.?.bb) {
.pointer => |pointer| blk: {
module.emit_value(function, array_expression.array_like);
module.emit_value(function, array_expression.index);
module.emit_value(function, array_expression.array_like, .memory);
module.emit_value(function, array_expression.index, .memory);
const gep = module.llvm.builder.create_gep(.{
.type = pointer.type.llvm.memory.?,
.aggregate = array_expression.array_like.llvm.?,
@ -6376,8 +6382,8 @@ pub const Module = struct {
},
.structure => |structure| switch (structure.is_slice) {
true => blk: {
module.emit_value(function, array_expression.array_like);
module.emit_value(function, array_expression.index);
module.emit_value(function, array_expression.array_like, .memory);
module.emit_value(function, array_expression.index, .memory);
const pointer_extract = module.llvm.builder.create_extract_value(array_expression.array_like.llvm.?, 0);
const element_type = structure.fields[0].type.bb.pointer.type;
const gep = module.llvm.builder.create_gep(.{
@ -6403,11 +6409,11 @@ pub const Module = struct {
break field.value;
}
} else module.report_error();
const llvm_value = value_type.llvm.abi.?.to_integer().get_constant(enum_int_value, @intFromBool(false));
const llvm_value = value_type.get_llvm(type_kind).to_integer().get_constant(enum_int_value, @intFromBool(false));
break :blk llvm_value.to_value();
},
.field_access => |field_access| blk: {
module.emit_value(function, field_access.aggregate);
module.emit_value(function, field_access.aggregate, .memory);
const field_name = field_access.field;
switch (field_access.aggregate.kind) {
.left => switch (field_access.aggregate.type.?.bb) {
@ -6487,7 +6493,7 @@ pub const Module = struct {
}
} else unreachable;
const field = &bits.fields[declaration_index];
module.emit_value(function, field_value);
module.emit_value(function, field_value, .memory);
const extended = module.llvm.builder.create_zero_extend(field_value.llvm.?, llvm_type);
const shl = module.llvm.builder.create_shl(extended, llvm_type.to_integer().get_constant(field.bit_offset, 0).to_value());
const or_value = module.llvm.builder.create_or(result, shl);
@ -6500,8 +6506,9 @@ pub const Module = struct {
true => blk: {
var constant_buffer: [64]*llvm.Constant = undefined;
const constants = constant_buffer[0..structure.fields.len];
for (aggregate_initialization.values, constants[0..aggregate_initialization.values.len]) |field_value, *constant| {
module.emit_value(function, field_value);
module.emit_value(function, field_value, .memory);
constant.* = field_value.llvm.?.to_constant();
}
@ -6512,7 +6519,7 @@ pub const Module = struct {
for (constants[aggregate_initialization.values.len..], structure.fields[aggregate_initialization.values.len..]) |*constant, *field| {
field.type.resolve(module);
constant.* = field.type.llvm.abi.?.get_zero();
constant.* = field.type.llvm.memory.?.get_zero();
}
}
const constant_struct = value_type.llvm.abi.?.to_struct().get_constant(constants);
@ -6614,7 +6621,7 @@ pub const Module = struct {
const return_value = rv orelse module.report_error();
module.analyze(function, return_value, .{
.type = return_abi.semantic_type,
});
}, .memory);
if (module.has_debug_info) {
module.llvm.builder.set_current_debug_location(last_statement_debug_location);
@ -6717,7 +6724,7 @@ pub const Module = struct {
module.emit_assignment(function, local.variable.storage.?.llvm.?, local.variable.storage.?.type.?, local.variable.initial_value);
},
.assignment => |assignment| {
module.analyze(function, assignment.left, .{});
module.analyze(function, assignment.left, .{}, .memory);
switch (assignment.kind) {
.@"=" => {
module.analyze_value_type(function, assignment.right, .{ .type = assignment.left.type.?.bb.pointer.type });
@ -6728,7 +6735,7 @@ pub const Module = struct {
const element_type = pointer_type.type;
assert(element_type.get_evaluation_kind() == .scalar);
const load = module.create_load(.{ .type = element_type, .value = assignment.left.llvm.?, .alignment = pointer_type.alignment });
module.analyze(function, assignment.right, .{ .type = element_type });
module.analyze(function, assignment.right, .{ .type = element_type }, .memory);
const a = load;
const b = assignment.right.llvm.?;
const right = switch (kind) {
@ -6804,14 +6811,14 @@ pub const Module = struct {
}
},
.expression => |expression_value| {
module.analyze(function, expression_value, .{});
module.analyze(function, expression_value, .{}, .memory);
},
.@"if" => |if_statement| {
const taken_block = module.llvm.context.create_basic_block("if.true", llvm_function);
const not_taken_block = module.llvm.context.create_basic_block("if.false", llvm_function);
const exit_block = module.llvm.context.create_basic_block("if.end", null);
module.analyze(function, if_statement.condition, .{});
module.analyze(function, if_statement.condition, .{}, .memory);
const llvm_condition = switch (if_statement.condition.type.?.bb) {
.integer => |integer| if (integer.bit_count != 1) module.llvm.builder.create_integer_compare(.ne, if_statement.condition.llvm.?, if_statement.condition.type.?.llvm.abi.?.get_zero().to_value()) else if_statement.condition.llvm.?,
.pointer => module.llvm.builder.create_integer_compare(.ne, if_statement.condition.llvm.?, if_statement.condition.type.?.llvm.abi.?.get_zero().to_value()),
@ -6875,7 +6882,7 @@ pub const Module = struct {
_ = module.llvm.builder.create_branch(loop_entry_block);
module.llvm.builder.position_at_end(loop_entry_block);
module.analyze(function, while_loop.condition, .{});
module.analyze(function, while_loop.condition, .{}, .abi);
const boolean_type = module.integer_type(1, false);
const condition_value = switch (while_loop.condition.type == boolean_type) {
@ -6914,7 +6921,7 @@ pub const Module = struct {
const exit_block = module.llvm.context.create_basic_block("exit_block", llvm_function);
current_function.exit_block = exit_block;
module.analyze(function, switch_statement.discriminant, .{});
module.analyze(function, switch_statement.discriminant, .{}, .abi);
const switch_discriminant_type = switch_statement.discriminant.type.?;
switch (switch_discriminant_type.bb) {
@ -6932,7 +6939,7 @@ pub const Module = struct {
else_clause_index = clause_index;
} else {
for (clause.values) |v| {
module.analyze(function, v, .{ .type = switch_discriminant_type });
module.analyze(function, v, .{ .type = switch_discriminant_type }, .abi);
if (!v.is_constant()) {
module.report_error();
}
@ -6990,7 +6997,7 @@ pub const Module = struct {
switch (value_type.get_evaluation_kind()) {
.scalar => {
module.emit_value(function, right);
module.emit_value(function, right, .memory);
_ = module.create_store(.{
.source_value = right.llvm.?,
.destination_value = left_llvm,
@ -7001,7 +7008,7 @@ pub const Module = struct {
.aggregate => switch (right.bb) {
.array_initialization => |array_initialization| switch (array_initialization.is_constant) {
true => {
module.emit_value(function, right);
module.emit_value(function, right, .memory);
const global_variable = module.llvm.module.create_global_variable(.{
.linkage = .InternalLinkage,
.name = "constarray", // TODO: format properly
@ -7020,7 +7027,7 @@ pub const Module = struct {
},
.aggregate_initialization => |aggregate_initialization| switch (aggregate_initialization.is_constant) {
true => {
module.emit_value(function, right);
module.emit_value(function, right, .memory);
const global_variable = module.llvm.module.create_global_variable(.{
.linkage = .InternalLinkage,
.name = "conststruct", // TODO: format properly
@ -7126,7 +7133,7 @@ pub const Module = struct {
},
.intrinsic => |intrinsic| switch (intrinsic) {
.string_to_enum => |string_to_enum| {
module.emit_value(function, string_to_enum.string_value);
module.emit_value(function, string_to_enum.string_value, .memory);
const s2e = string_to_enum.enum_type.bb.enumerator.string_to_enum orelse unreachable;
const first_field = module.llvm.builder.create_extract_value(string_to_enum.string_value.llvm.?, 0);
const second_field = module.llvm.builder.create_extract_value(string_to_enum.string_value.llvm.?, 1);