| ... | ... | @@ -2062,6 +2062,78 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 2062 | 2062 | } |
| 2063 | 2063 | } |
| 2064 | 2064 | return true; |
| 2065 | } else if (abi_class == X64CABIClass_SSE) { |
| 2066 | // For now only handle structs with only floats/doubles in it. |
| 2067 | if (ty->id != ZigTypeIdStruct) { |
| 2068 | if (source_node != nullptr) { |
| 2069 | give_up_with_c_abi_error(g, source_node); |
| 2070 | } |
| 2071 | // otherwise allow codegen code to report a compile error |
| 2072 | return false; |
| 2073 | } |
| 2074 | |
| 2075 | for (uint32_t i = 0; i < ty->data.structure.src_field_count; i += 1) { |
| 2076 | if (ty->data.structure.fields[i]->type_entry->id != ZigTypeIdFloat) { |
| 2077 | if (source_node != nullptr) { |
| 2078 | give_up_with_c_abi_error(g, source_node); |
| 2079 | } |
| 2080 | // otherwise allow codegen code to report a compile error |
| 2081 | return false; |
| 2082 | } |
| 2083 | } |
| 2084 | |
| 2085 | // The SystemV ABI says that we have to setup 1 FP register per f64. |
| 2086 | // So two f32 can be passed in one f64, but 3 f32 have to be passed in 2 FP registers. |
| 2087 | // To achieve this with LLVM API, we pass multiple f64 parameters to the LLVM function if |
| 2088 | // the type is bigger than 8 bytes. |
| 2089 | |
| 2090 | // Example: |
| 2091 | // extern struct { |
| 2092 | // x: f32, |
| 2093 | // y: f32, |
| 2094 | // z: f32, |
| 2095 | // }; |
| 2096 | // const ptr = (*f64)*Struct; |
| 2097 | // Register 1: ptr.* |
| 2098 | // Register 2: (ptr + 1).* |
| 2099 | |
| 2100 | // One floating point register per f64 or 2 f32's |
| 2101 | size_t number_of_fp_regs = (size_t)ceilf((float)ty_size / (float)8); |
| 2102 | |
| 2103 | switch (fn_walk->id) { |
| 2104 | case FnWalkIdAttrs: { |
| 2105 | fn_walk->data.attrs.gen_i += 1; |
| 2106 | break; |
| 2107 | } |
| 2108 | case FnWalkIdCall: { |
| 2109 | LLVMValueRef f64_ptr_to_struct = LLVMBuildBitCast(g->builder, val, LLVMPointerType(LLVMDoubleType(), 0), ""); |
| 2110 | for (uint32_t i = 0; i < number_of_fp_regs; i += 1) { |
| 2111 | LLVMValueRef index = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, i, false); |
| 2112 | LLVMValueRef indices[] = { index }; |
| 2113 | LLVMValueRef adjusted_ptr_to_struct = LLVMBuildInBoundsGEP(g->builder, f64_ptr_to_struct, indices, 1, ""); |
| 2114 | LLVMValueRef loaded = LLVMBuildLoad(g->builder, adjusted_ptr_to_struct, ""); |
| 2115 | fn_walk->data.call.gen_param_values->append(loaded); |
| 2116 | } |
| 2117 | break; |
| 2118 | } |
| 2119 | case FnWalkIdTypes: { |
| 2120 | for (uint32_t i = 0; i < number_of_fp_regs; i += 1) { |
| 2121 | fn_walk->data.types.gen_param_types->append(get_llvm_type(g, g->builtin_types.entry_f64)); |
| 2122 | fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, g->builtin_types.entry_f64)); |
| 2123 | } |
| 2124 | break; |
| 2125 | } |
| 2126 | case FnWalkIdVars: |
| 2127 | case FnWalkIdInits: { |
| 2128 | // TODO: Handle exporting functions |
| 2129 | if (source_node != nullptr) { |
| 2130 | give_up_with_c_abi_error(g, source_node); |
| 2131 | } |
| 2132 | // otherwise allow codegen code to report a compile error |
| 2133 | return false; |
| 2134 | } |
| 2135 | } |
| 2136 | return true; |
| 2065 | 2137 | } |
| 2066 | 2138 | } |
| 2067 | 2139 | if (source_node != nullptr) { |