C string to slice and C split struct ints
All checks were successful
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 1m25s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 1m23s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 1m30s
CI / ci (Debug, ubuntu-latest) (push) Successful in 2m20s

This commit is contained in:
David Gonzalez Martin 2025-04-13 16:45:47 -06:00
parent a4ec4c9488
commit 1d8157dd9e
2 changed files with 148 additions and 84 deletions

View File

@ -5066,12 +5066,22 @@ pub const Module = struct {
// Overwrite side of the expression
array_expression.array_like.kind = .left;
module.analyze_value_type(function, array_expression.array_like, .{});
const element_type = switch (array_expression.array_like.type.?.bb) {
const element_type = switch (array_expression.array_like.kind) {
.left => switch (array_expression.array_like.type.?.bb) {
.pointer => |pointer| switch (pointer.type.bb) {
.array => |array| array.element_type,
.structure => |structure| {
if (!structure.is_slice) {
module.report_error();
}
@trap();
},
.pointer => |p| p.type,
else => @trap(),
},
else => module.report_error(),
},
.right => @trap(),
};
switch (value.kind) {
.left => @trap(),
@ -5179,6 +5189,35 @@ pub const Module = struct {
}
},
.zero => {},
.slice_expression => |slice_expression| {
module.analyze_value_type(function, slice_expression.array_like, .{});
const sliceable_type = slice_expression.array_like.type.?;
const element_type = switch (sliceable_type.bb) {
.pointer => |pointer| pointer.type,
.structure => |structure| b: {
if (!structure.is_slice) {
module.report_error();
}
break :b structure.fields[0].type.bb.pointer.type;
},
else => @trap(),
};
const index_type = module.integer_type(64, false);
module.analyze_value_type(function, slice_expression.start, .{ .type = index_type });
if (slice_expression.start.type.?.bb != .integer) {
module.report_error();
}
if (slice_expression.end) |end| {
module.analyze_value_type(function, end, .{ .type = index_type });
if (end.type.?.bb != .integer) {
module.report_error();
}
}
const slice_type = module.get_slice_type(.{ .type = element_type });
if (slice_type != expected_type) {
module.report_error();
}
},
else => @trap(),
};
@ -5410,6 +5449,64 @@ pub const Module = struct {
value.type = value_type;
}
pub fn emit_slice_expression(module: *Module, function: ?*Global, value: *Value) struct { *llvm.Value, *llvm.Value } {
const value_type = value.type.?;
switch (value.bb) {
.slice_expression => |slice_expression| {
module.emit_value(function, slice_expression.array_like);
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);
const end = slice_expression.end orelse module.report_error();
module.emit_value(function, end);
const slice_pointer = module.llvm.builder.create_gep(.{
.type = pointer.type.llvm.handle.?,
.aggregate = slice_expression.array_like.llvm.?,
.indices = &.{ start.llvm.? },
});
const slice_length = module.llvm.builder.create_sub(end.llvm.?, start.llvm.?);
return .{ slice_pointer, slice_length };
},
},
.structure => |structure| switch (slice_expression.array_like.kind) {
.left => @trap(),
.right => {
assert(structure.is_slice);
const slice_pointer_type = value_type.bb.structure.fields[0].type;
const slice_element_type = slice_pointer_type.bb.pointer.type;
const is_start_zero = slice_expression.start.bb == .constant_integer and slice_expression.start.bb.constant_integer.value == 0;
if (slice_expression.end) |end| {
_ = end;
@trap();
} else {
if (is_start_zero) {
// 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);
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(.{
.type = slice_element_type.llvm.handle.?,
.aggregate = old_slice_pointer,
.indices = &.{ slice_expression.start.llvm.? },
});
const slice_length = module.llvm.builder.create_sub(old_slice_length, slice_expression.start.llvm.?);
return .{ slice_pointer, slice_length };
}
}
},
},
else => @trap(),
}
},
else => unreachable,
}
}
pub fn emit_value(module: *Module, function: ?*Global, value: *Value) void {
const value_type = value.type orelse unreachable;
assert(value.llvm == null);
@ -5706,6 +5803,25 @@ pub const Module = struct {
}),
};
},
.pointer => |real_pointer| blk: {
module.emit_value(function, array_expression.array_like);
module.emit_value(function, array_expression.index);
// 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;
const gep = module.llvm.builder.create_gep(.{
.type = element_type.llvm.handle.?,
.aggregate = pointer_load,
.indices = &.{array_expression.index.llvm.?},
});
break :blk switch (value.kind) {
.left => gep,
.right => module.create_load(.{
.type = element_type,
.value = gep,
}),
};
},
else => @trap(),
},
else => unreachable,
@ -5863,6 +5979,15 @@ pub const Module = struct {
module.llvm.builder.clear_insertion_position();
break :b unreachable_value;
},
.slice_expression => blk: {
assert(value.kind == .right);
const slice_values = module.emit_slice_expression(function, value);
const slice_poison = value_type.resolve(module).handle.get_poison();
const slice_pointer = module.llvm.builder.create_insert_value(slice_poison, slice_values[0], 0);
const slice_length = module.llvm.builder.create_insert_value(slice_pointer, slice_values[1], 1);
const slice_value = slice_length;
break :blk slice_value;
},
else => @trap(),
};
@ -6375,85 +6500,22 @@ pub const Module = struct {
// }
},
.slice_expression => |slice_expression| {
module.emit_value(function, slice_expression.array_like);
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);
const end = slice_expression.end orelse module.report_error();
module.emit_value(function, end);
const slice_pointer = module.llvm.builder.create_gep(.{
.type = pointer.type.llvm.handle.?,
.aggregate = slice_expression.array_like.llvm.?,
.indices = &.{ start.llvm.? },
});
_ = module.create_store(.{
.source_value = slice_pointer,
.destination_value = left.llvm.?,
.source_type = pointer.type,
.destination_type = pointer.type,
.alignment = pointer.alignment,
});
const slice_length = module.llvm.builder.create_sub(end.llvm.?, start.llvm.?);
const slice_length_destination = module.llvm.builder.create_struct_gep(value_type.llvm.handle.?.to_struct(), left.llvm.?, 1);
_ = module.create_store(.{
.source_value = slice_length,
.destination_value = slice_length_destination,
.source_type = slice_expression.start.type.?,
.destination_type = slice_expression.start.type.?,
});
},
},
.structure => |structure| switch (slice_expression.array_like.kind) {
.left => @trap(),
.right => {
assert(structure.is_slice);
const slice_values = module.emit_slice_expression(function, right);
const slice_pointer_type = value_type.bb.structure.fields[0].type;
const slice_element_type = slice_pointer_type.bb.pointer.type;
const is_start_zero = slice_expression.start.bb == .constant_integer and slice_expression.start.bb.constant_integer.value == 0;
if (slice_expression.end) |end| {
_ = end;
@trap();
} else {
if (is_start_zero) {
// TODO: consider if we should emit an error here or it be a NOP
_ = module.create_store(.{
.source_value = slice_expression.array_like.llvm.?,
.destination_value = left.llvm.?,
.source_type = value_type,
.destination_type = value_type,
});
} else {
module.emit_value(function, slice_expression.start);
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(.{
.type = slice_element_type.llvm.handle.?,
.aggregate = old_slice_pointer,
.indices = &.{ slice_expression.start.llvm.? },
});
_ = module.create_store(.{
.source_value = slice_pointer,
.source_value = slice_values[0],
.destination_value = left.llvm.?,
.source_type = slice_pointer_type,
.destination_type = slice_pointer_type,
.alignment = pointer_type.bb.pointer.alignment,
});
const slice_length = module.llvm.builder.create_sub(old_slice_length, slice_expression.start.llvm.?);
const slice_length_destination = module.llvm.builder.create_struct_gep(value_type.llvm.handle.?.to_struct(), left.llvm.?, 1);
_ = module.create_store(.{
.source_value = slice_length,
.source_value = slice_values[1],
.destination_value = slice_length_destination,
.source_type = slice_expression.start.type.?,
.destination_type = slice_expression.start.type.?,
});
}
}
},
},
else => @trap(),
}
},
.zero => {
_ = module.llvm.builder.create_memset(left.llvm.?, module.integer_type(8, false).resolve(module).handle.get_zero().to_value(), module.integer_type(64, false).resolve(module).handle.to_integer().get_constant(value_type.get_byte_size(), 0).to_value(), pointer_type.bb.pointer.alignment);

View File

@ -241,4 +241,6 @@ const names = &[_][]const u8{
"c_abi1",
"c_med_struct_ints",
"c_ret_struct_array",
"c_split_struct_ints",
"c_string_to_slice",
};