mirror of
https://github.com/ziglang/zig.git
synced 2024-11-28 16:12:33 +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;
|
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) {
|
if (source_node != nullptr) {
|
||||||
|
@ -63,6 +63,20 @@ void zig_split_struct_ints(struct SplitStructInts);
|
|||||||
|
|
||||||
struct BigStruct zig_big_struct_both(struct BigStruct);
|
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) {
|
void run_c_tests(void) {
|
||||||
zig_u8(0xff);
|
zig_u8(0xff);
|
||||||
zig_u16(0xfffe);
|
zig_u16(0xfffe);
|
||||||
@ -226,3 +240,17 @@ struct BigStruct c_big_struct_both(struct BigStruct x) {
|
|||||||
struct BigStruct y = {10, 11, 12, 13, 14};
|
struct BigStruct y = {10, 11, 12, 13, 14};
|
||||||
return y;
|
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;
|
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