sdl phase 2
This commit is contained in:
111
src/codegen.zig
111
src/codegen.zig
@@ -1280,6 +1280,9 @@ pub const CodeGen = struct {
|
||||
try param_llvm_types.append(self.allocator, c.LLVMPointerTypeInContext(self.context, 0));
|
||||
} else if (is_foreign and sx_ty.isStruct()) {
|
||||
try param_llvm_types.append(self.allocator, self.getForeignParamABIType(sx_ty));
|
||||
} else if (is_foreign and sx_ty.isArray()) {
|
||||
// [N]T → pointer in C ABI (C arrays decay to pointers)
|
||||
try param_llvm_types.append(self.allocator, c.LLVMPointerTypeInContext(self.context, 0));
|
||||
} else {
|
||||
try param_llvm_types.append(self.allocator, self.typeToLLVM(sx_ty));
|
||||
}
|
||||
@@ -1329,7 +1332,7 @@ pub const CodeGen = struct {
|
||||
if (first == .f32 or first == .f64) {
|
||||
var all_same = true;
|
||||
for (field_types[1..]) |ft| {
|
||||
if (!std.meta.eql(ft, first)) {
|
||||
if (!ft.eql(first)) {
|
||||
all_same = false;
|
||||
break;
|
||||
}
|
||||
@@ -2554,6 +2557,17 @@ pub const CodeGen = struct {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// struct.field[i] = val — GEP through struct to array field, then index
|
||||
if (ie.object.data == .field_access) {
|
||||
const field_ptr = try self.genAddressOf(ie.object);
|
||||
const idx = try self.genExpr(ie.index);
|
||||
const val = try self.genExpr(asgn.value);
|
||||
const zero = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), 0, 0);
|
||||
var indices = [_]c.LLVMValueRef{ zero, idx };
|
||||
const gep_ptr = c.LLVMBuildGEP2(self.builder, self.typeToLLVM(obj_ty), field_ptr, &indices, 2, "field_arridx");
|
||||
_ = c.LLVMBuildStore(self.builder, val, gep_ptr);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (obj_ty.isSlice()) {
|
||||
const slice_info = obj_ty.slice_type;
|
||||
@@ -2891,6 +2905,16 @@ pub const CodeGen = struct {
|
||||
const idx = self.findFieldIndex(info, fa.field) orelse return self.emitErrorFmt("no field '{s}' in struct '{s}'", .{ fa.field, sname });
|
||||
return c.LLVMBuildStructGEP2(self.builder, info.llvm_type, entry.ptr, @intCast(idx), "addr_field");
|
||||
}
|
||||
// &p.field where p is *Struct — auto-deref through pointer
|
||||
if (entry.ty.isPointer()) {
|
||||
const pointee_name = entry.ty.pointer_type.pointee_name;
|
||||
if (self.struct_types.get(pointee_name)) |info| {
|
||||
const loaded_ptr = c.LLVMBuildLoad2(self.builder,
|
||||
c.LLVMPointerTypeInContext(self.context, 0), entry.ptr, "ptr_load");
|
||||
const idx = self.findFieldIndex(info, fa.field) orelse return self.emitErrorFmt("no field '{s}' in struct '{s}'", .{ fa.field, pointee_name });
|
||||
return c.LLVMBuildStructGEP2(self.builder, info.llvm_type, loaded_ptr, @intCast(idx), "addr_pfield");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3364,6 +3388,9 @@ pub const CodeGen = struct {
|
||||
break :blk entry.ptr;
|
||||
}
|
||||
}
|
||||
if (node.data == .field_access) {
|
||||
break :blk try self.genAddressOf(node);
|
||||
}
|
||||
// Fallback: generate the expression and hope it returns a pointer
|
||||
break :blk try self.genExpr(node);
|
||||
};
|
||||
@@ -3382,6 +3409,42 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Array to many-pointer coercion: [N]T → [*]T
|
||||
if (target_ty.isManyPointer()) {
|
||||
const src_ty = self.inferType(node);
|
||||
if (src_ty.isArray()) {
|
||||
const arr_info = src_ty.array_type;
|
||||
if (std.mem.eql(u8, arr_info.element_name, target_ty.many_pointer_type.element_name)) {
|
||||
const arr_alloca = blk: {
|
||||
if (node.data == .identifier) {
|
||||
if (self.named_values.get(node.data.identifier.name)) |entry| {
|
||||
break :blk entry.ptr;
|
||||
}
|
||||
}
|
||||
if (node.data == .field_access) {
|
||||
break :blk try self.genAddressOf(node);
|
||||
}
|
||||
break :blk try self.genExpr(node);
|
||||
};
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
const zero = c.LLVMConstInt(i64_ty, 0, 0);
|
||||
var indices = [_]c.LLVMValueRef{ zero, zero };
|
||||
return c.LLVMBuildGEP2(self.builder, self.typeToLLVM(src_ty), arr_alloca, &indices, 2, "arr_decay");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Slice to many-pointer coercion: []T → [*]T (extract .ptr from fat pointer)
|
||||
if (target_ty.isManyPointer()) {
|
||||
const src_ty = self.inferType(node);
|
||||
if (src_ty.isSlice()) {
|
||||
if (std.mem.eql(u8, src_ty.slice_type.element_name, target_ty.many_pointer_type.element_name)) {
|
||||
const slice_val = try self.genExpr(node);
|
||||
return c.LLVMBuildExtractValue(self.builder, slice_val, 0, "slice_decay");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implicit address-of: passing T where *T is expected → auto &
|
||||
if (target_ty.isPointer()) {
|
||||
const src_ty = self.inferType(node);
|
||||
@@ -3390,6 +3453,8 @@ pub const CodeGen = struct {
|
||||
std.mem.eql(u8, src_ty.struct_type, pointee_name) or
|
||||
(if (self.type_aliases.get(src_ty.struct_type)) |alias| std.mem.eql(u8, alias, pointee_name) else false) or
|
||||
(if (self.type_aliases.get(pointee_name)) |alias| std.mem.eql(u8, alias, src_ty.struct_type) else false)
|
||||
else if (Type.fromName(pointee_name)) |pointee_ty|
|
||||
src_ty.eql(pointee_ty)
|
||||
else
|
||||
false;
|
||||
if (src_matches) {
|
||||
@@ -3442,7 +3507,7 @@ pub const CodeGen = struct {
|
||||
/// Convert an LLVM value from src_ty to target_ty, emitting appropriate casts.
|
||||
fn convertValue(self: *CodeGen, val: c.LLVMValueRef, src_ty: Type, target_ty: Type) c.LLVMValueRef {
|
||||
// Same type → return as-is
|
||||
if (std.meta.eql(src_ty, target_ty)) return val;
|
||||
if (src_ty.eql(target_ty)) return val;
|
||||
|
||||
// string <-> []u8: identical LLVM type {ptr, i64}, no conversion needed
|
||||
if ((src_ty == .string_type and target_ty.isSlice() and
|
||||
@@ -3574,6 +3639,16 @@ pub const CodeGen = struct {
|
||||
return c.LLVMBuildIntToPtr(self.builder, val, c.LLVMPointerTypeInContext(self.context, 0), "inttoptr");
|
||||
}
|
||||
|
||||
// Slice/string → pointer: extract .ptr from fat pointer
|
||||
if ((src_ty.isSlice() or src_ty == .string_type) and (target_ty.isPointer() or target_ty.isManyPointer())) {
|
||||
return c.LLVMBuildExtractValue(self.builder, val, 0, "slice_to_ptr");
|
||||
}
|
||||
|
||||
// *[N]T → [*]T: pointer to array decays to many-pointer (both opaque ptrs, no-op)
|
||||
if (src_ty.isPointer() and target_ty.isManyPointer()) {
|
||||
return val;
|
||||
}
|
||||
|
||||
// Pointer → function_type or function_type → pointer: both are opaque pointers, no-op
|
||||
if ((src_ty.isPointer() or src_ty.isManyPointer()) and target_ty.isFunctionType()) {
|
||||
return val;
|
||||
@@ -4170,11 +4245,11 @@ pub const CodeGen = struct {
|
||||
return c.LLVMBuildExtractElement(self.builder, vec_val, idx, "vidx");
|
||||
}
|
||||
if (obj_ty.isArray()) {
|
||||
// Array index: load from GEP
|
||||
const arr_info = obj_ty.array_type;
|
||||
const elem_ty = Type.fromName(arr_info.element_name) orelse return self.emitErrorFmt("unknown array element type '{s}'", .{arr_info.element_name});
|
||||
// Array index via identifier: load from GEP
|
||||
if (ie.object.data == .identifier) {
|
||||
if (self.named_values.get(ie.object.data.identifier.name)) |entry| {
|
||||
const arr_info = obj_ty.array_type;
|
||||
const elem_ty = Type.fromName(arr_info.element_name) orelse return self.emitErrorFmt("unknown array element type '{s}'", .{arr_info.element_name});
|
||||
const idx = try self.genExpr(ie.index);
|
||||
const zero = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), 0, 0);
|
||||
var indices = [_]c.LLVMValueRef{ zero, idx };
|
||||
@@ -4182,6 +4257,15 @@ pub const CodeGen = struct {
|
||||
return c.LLVMBuildLoad2(self.builder, self.typeToLLVM(elem_ty), gep, "arrval");
|
||||
}
|
||||
}
|
||||
// Array index via field access: GEP through struct field
|
||||
if (ie.object.data == .field_access) {
|
||||
const field_ptr = try self.genAddressOf(ie.object);
|
||||
const idx = try self.genExpr(ie.index);
|
||||
const zero = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), 0, 0);
|
||||
var indices = [_]c.LLVMValueRef{ zero, idx };
|
||||
const gep = c.LLVMBuildGEP2(self.builder, self.typeToLLVM(obj_ty), field_ptr, &indices, 2, "field_arridx");
|
||||
return c.LLVMBuildLoad2(self.builder, self.typeToLLVM(elem_ty), gep, "field_arrval");
|
||||
}
|
||||
}
|
||||
if (obj_ty == .string_type) {
|
||||
// String indexing: extract ptr from slice, GEP + load u8
|
||||
@@ -4730,9 +4814,11 @@ pub const CodeGen = struct {
|
||||
const fn_ptr = c.LLVMBuildLoad2(self.builder, ptr_ty, entry.ptr, "fn_ptr");
|
||||
|
||||
// Build LLVM function type from FunctionTypeInfo
|
||||
const ptr_ty_llvm = c.LLVMPointerTypeInContext(self.context, 0);
|
||||
var param_llvm_types: [64]c.LLVMTypeRef = undefined;
|
||||
for (fti.param_types, 0..) |pt, i| {
|
||||
param_llvm_types[i] = self.typeToLLVM(pt);
|
||||
// [N]T and [:0]T params are pointers at the ABI level
|
||||
param_llvm_types[i] = if (pt.isArray() or pt == .string_type) ptr_ty_llvm else self.typeToLLVM(pt);
|
||||
}
|
||||
const ret_llvm = self.typeToLLVM(fti.return_type.*);
|
||||
const fn_type = c.LLVMFunctionType(
|
||||
@@ -4746,7 +4832,18 @@ pub const CodeGen = struct {
|
||||
var arg_vals = std.ArrayList(c.LLVMValueRef).empty;
|
||||
for (call_node.args, 0..) |arg, i| {
|
||||
if (i < fti.param_types.len) {
|
||||
try arg_vals.append(self.allocator, try self.genExprAsType(arg, fti.param_types[i]));
|
||||
const pt = fti.param_types[i];
|
||||
// [N]T params: pass pointer via array decay
|
||||
if (pt.isArray()) {
|
||||
const decay_target: Type = .{ .many_pointer_type = .{ .element_name = pt.array_type.element_name } };
|
||||
try arg_vals.append(self.allocator, try self.genExprAsType(arg, decay_target));
|
||||
} else if (pt == .string_type) {
|
||||
// [:0]u8 params: extract .ptr from fat pointer
|
||||
const val = try self.genExprAsType(arg, pt);
|
||||
try arg_vals.append(self.allocator, c.LLVMBuildExtractValue(self.builder, val, 0, "str_ptr"));
|
||||
} else {
|
||||
try arg_vals.append(self.allocator, try self.genExprAsType(arg, pt));
|
||||
}
|
||||
} else {
|
||||
try arg_vals.append(self.allocator, try self.genExpr(arg));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user