mirror of
https://github.com/ziglang/zig.git
synced 2024-11-28 08:02:32 +00:00
C ABI: Add C support for passing structs of floats to an extern function
Currently this does not handle returning these structs yet. Related: #1481
This commit is contained in:
parent
34101127c6
commit
6e89692d81
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user