Commit 6e89692d81
Changed files (3)
src
src/codegen.cpp
@@ -2062,6 +2062,78 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
}
}
return true;
+ } else if (abi_class == X64CABIClass_SSE) {
+ // For now only handle structs with only floats/doubles in it.
+ if (ty->id != ZigTypeIdStruct) {
+ if (source_node != nullptr) {
+ give_up_with_c_abi_error(g, source_node);
+ }
+ // otherwise allow codegen code to report a compile error
+ return false;
+ }
+
+ for (uint32_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
+ if (ty->data.structure.fields[i]->type_entry->id != ZigTypeIdFloat) {
+ if (source_node != nullptr) {
+ give_up_with_c_abi_error(g, source_node);
+ }
+ // otherwise allow codegen code to report a compile error
+ return false;
+ }
+ }
+
+ // The SystemV ABI says that we have to setup 1 FP register per f64.
+ // So two f32 can be passed in one f64, but 3 f32 have to be passed in 2 FP registers.
+ // To achieve this with LLVM API, we pass multiple f64 parameters to the LLVM function if
+ // the type is bigger than 8 bytes.
+
+ // Example:
+ // extern struct {
+ // x: f32,
+ // y: f32,
+ // z: f32,
+ // };
+ // const ptr = (*f64)*Struct;
+ // Register 1: ptr.*
+ // Register 2: (ptr + 1).*
+
+ // One floating point register per f64 or 2 f32's
+ size_t number_of_fp_regs = (size_t)ceilf((float)ty_size / (float)8);
+
+ switch (fn_walk->id) {
+ case FnWalkIdAttrs: {
+ fn_walk->data.attrs.gen_i += 1;
+ break;
+ }
+ case FnWalkIdCall: {
+ LLVMValueRef f64_ptr_to_struct = LLVMBuildBitCast(g->builder, val, LLVMPointerType(LLVMDoubleType(), 0), "");
+ for (uint32_t i = 0; i < number_of_fp_regs; i += 1) {
+ LLVMValueRef index = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, i, false);
+ LLVMValueRef indices[] = { index };
+ LLVMValueRef adjusted_ptr_to_struct = LLVMBuildInBoundsGEP(g->builder, f64_ptr_to_struct, indices, 1, "");
+ LLVMValueRef loaded = LLVMBuildLoad(g->builder, adjusted_ptr_to_struct, "");
+ fn_walk->data.call.gen_param_values->append(loaded);
+ }
+ break;
+ }
+ case FnWalkIdTypes: {
+ for (uint32_t i = 0; i < number_of_fp_regs; i += 1) {
+ fn_walk->data.types.gen_param_types->append(get_llvm_type(g, g->builtin_types.entry_f64));
+ fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, g->builtin_types.entry_f64));
+ }
+ break;
+ }
+ case FnWalkIdVars:
+ case FnWalkIdInits: {
+ // TODO: Handle exporting functions
+ if (source_node != nullptr) {
+ give_up_with_c_abi_error(g, source_node);
+ }
+ // otherwise allow codegen code to report a compile error
+ return false;
+ }
+ }
+ return true;
}
}
if (source_node != nullptr) {
test/stage1/c_abi/cfuncs.c
@@ -63,6 +63,20 @@ void zig_split_struct_ints(struct SplitStructInts);
struct BigStruct zig_big_struct_both(struct BigStruct);
+typedef struct Vector3 {
+ float x;
+ float y;
+ float z;
+} Vector3;
+
+typedef struct Vector5 {
+ float x;
+ float y;
+ float z;
+ float w;
+ float q;
+} Vector5;
+
void run_c_tests(void) {
zig_u8(0xff);
zig_u16(0xfffe);
@@ -226,3 +240,17 @@ struct BigStruct c_big_struct_both(struct BigStruct x) {
struct BigStruct y = {10, 11, 12, 13, 14};
return y;
}
+
+void c_small_struct_floats(Vector3 vec) {
+ assert_or_panic(vec.x == 3.0);
+ assert_or_panic(vec.y == 6.0);
+ assert_or_panic(vec.z == 12.0);
+}
+
+void c_big_struct_floats(Vector5 vec) {
+ assert_or_panic(vec.x == 76.0);
+ assert_or_panic(vec.y == -1.0);
+ assert_or_panic(vec.z == -12.0);
+ assert_or_panic(vec.w == 69);
+ assert_or_panic(vec.q == 55);
+}
test/stage1/c_abi/main.zig
@@ -261,3 +261,37 @@ export fn zig_big_struct_both(x: BigStruct) BigStruct {
};
return s;
}
+
+const Vector3 = extern struct {
+ x: f32,
+ y: f32,
+ z: f32,
+};
+extern fn c_small_struct_floats(Vector3) void;
+
+const Vector5 = extern struct {
+ x: f32,
+ y: f32,
+ z: f32,
+ w: f32,
+ q: f32,
+};
+extern fn c_big_struct_floats(Vector5) void;
+
+test "C ABI structs of floats as parameter" {
+ var v3 = Vector3{
+ .x = 3.0,
+ .y = 6.0,
+ .z = 12.0,
+ };
+ c_small_struct_floats(v3);
+
+ var v5 = Vector5{
+ .x = 76.0,
+ .y = -1.0,
+ .z = -12.0,
+ .w = 69.0,
+ .q = 55,
+ };
+ c_big_struct_floats(v5);
+}