| ... | @@ -6888,13 +6888,148 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, Stage1Air *executable, | ... | @@ -6888,13 +6888,148 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, Stage1Air *executable, |
| 6888 | return nullptr; | 6888 | return nullptr; |
| 6889 | } | 6889 | } |
| 6890 | | 6890 | |
| | 6891 | static LLVMValueRef ir_render_soft_f80_float_op(CodeGen *g, Stage1Air *executable, Stage1AirInstFloatOp *instruction) { |
| | 6892 | ZigType *op_type = instruction->operand->value->type; |
| | 6893 | uint32_t vector_len = op_type->id == ZigTypeIdVector ? op_type->data.vector.len : 0; |
| | 6894 | |
| | 6895 | const char *func_name; |
| | 6896 | switch (instruction->fn_id) { |
| | 6897 | case BuiltinFnIdSqrt: |
| | 6898 | func_name = "__sqrt"; |
| | 6899 | break; |
| | 6900 | case BuiltinFnIdSin: |
| | 6901 | func_name = "__sinx"; |
| | 6902 | break; |
| | 6903 | case BuiltinFnIdCos: |
| | 6904 | func_name = "__cosx"; |
| | 6905 | break; |
| | 6906 | case BuiltinFnIdExp: |
| | 6907 | func_name = "__expx"; |
| | 6908 | break; |
| | 6909 | case BuiltinFnIdExp2: |
| | 6910 | func_name = "__exp2x"; |
| | 6911 | break; |
| | 6912 | case BuiltinFnIdLog: |
| | 6913 | func_name = "__logx"; |
| | 6914 | break; |
| | 6915 | case BuiltinFnIdLog2: |
| | 6916 | func_name = "__log2x"; |
| | 6917 | break; |
| | 6918 | case BuiltinFnIdLog10: |
| | 6919 | func_name = "__log10x"; |
| | 6920 | break; |
| | 6921 | case BuiltinFnIdFabs: |
| | 6922 | func_name = "__fabsx"; |
| | 6923 | break; |
| | 6924 | case BuiltinFnIdFloor: |
| | 6925 | func_name = "__floorx"; |
| | 6926 | break; |
| | 6927 | case BuiltinFnIdCeil: |
| | 6928 | func_name = "__ceilx"; |
| | 6929 | break; |
| | 6930 | case BuiltinFnIdTrunc: |
| | 6931 | func_name = "__truncx"; |
| | 6932 | break; |
| | 6933 | case BuiltinFnIdNearbyInt: |
| | 6934 | func_name = "__nearbyintx"; |
| | 6935 | break; |
| | 6936 | case BuiltinFnIdRound: |
| | 6937 | func_name = "__roundx"; |
| | 6938 | break; |
| | 6939 | default: |
| | 6940 | zig_unreachable(); |
| | 6941 | } |
| | 6942 | |
| | 6943 | |
| | 6944 | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, func_name); |
| | 6945 | if (func_ref == nullptr) { |
| | 6946 | LLVMTypeRef f80_ref = g->builtin_types.entry_f80->llvm_type; |
| | 6947 | LLVMTypeRef fn_type = LLVMFunctionType(f80_ref, &f80_ref, 1, false); |
| | 6948 | func_ref = LLVMAddFunction(g->module, func_name, fn_type); |
| | 6949 | } |
| | 6950 | |
| | 6951 | LLVMValueRef operand = ir_llvm_value(g, instruction->operand); |
| | 6952 | LLVMValueRef result; |
| | 6953 | if (vector_len == 0) { |
| | 6954 | result = LLVMBuildCall(g->builder, func_ref, &operand, 1, ""); |
| | 6955 | } else { |
| | 6956 | result = build_alloca(g, instruction->operand->value->type, "", 0); |
| | 6957 | } |
| | 6958 | |
| | 6959 | LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; |
| | 6960 | for (uint32_t i = 0; i < vector_len; i++) { |
| | 6961 | LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); |
| | 6962 | LLVMValueRef param = LLVMBuildExtractElement(g->builder, operand, index_value, ""); |
| | 6963 | LLVMValueRef call_result = LLVMBuildCall(g->builder, func_ref, &param, 1, ""); |
| | 6964 | LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""), |
| | 6965 | call_result, index_value, ""); |
| | 6966 | } |
| | 6967 | if (vector_len != 0) { |
| | 6968 | result = LLVMBuildLoad(g->builder, result, ""); |
| | 6969 | } |
| | 6970 | return result; |
| | 6971 | } |
| | 6972 | |
| 6891 | static LLVMValueRef ir_render_float_op(CodeGen *g, Stage1Air *executable, Stage1AirInstFloatOp *instruction) { | 6973 | static LLVMValueRef ir_render_float_op(CodeGen *g, Stage1Air *executable, Stage1AirInstFloatOp *instruction) { |
| | 6974 | ZigType *op_type = instruction->operand->value->type; |
| | 6975 | op_type = op_type->id == ZigTypeIdVector ? op_type->data.vector.elem_type : op_type; |
| | 6976 | if (op_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) { |
| | 6977 | return ir_render_soft_f80_float_op(g, executable, instruction); |
| | 6978 | } |
| 6892 | LLVMValueRef operand = ir_llvm_value(g, instruction->operand); | 6979 | LLVMValueRef operand = ir_llvm_value(g, instruction->operand); |
| 6893 | LLVMValueRef fn_val = get_float_fn(g, instruction->base.value->type, ZigLLVMFnIdFloatOp, instruction->fn_id); | 6980 | LLVMValueRef fn_val = get_float_fn(g, instruction->base.value->type, ZigLLVMFnIdFloatOp, instruction->fn_id); |
| 6894 | return LLVMBuildCall(g->builder, fn_val, &operand, 1, ""); | 6981 | return LLVMBuildCall(g->builder, fn_val, &operand, 1, ""); |
| 6895 | } | 6982 | } |
| 6896 | | 6983 | |
| | 6984 | static LLVMValueRef ir_render_soft_f80_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction) { |
| | 6985 | ZigType *op_type = instruction->op1->value->type; |
| | 6986 | uint32_t vector_len = op_type->id == ZigTypeIdVector ? op_type->data.vector.len : 0; |
| | 6987 | |
| | 6988 | const char *func_name = "__fmax"; |
| | 6989 | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, func_name); |
| | 6990 | if (func_ref == nullptr) { |
| | 6991 | LLVMTypeRef f80_ref = g->builtin_types.entry_f80->llvm_type; |
| | 6992 | LLVMTypeRef params[3] = { f80_ref, f80_ref, f80_ref }; |
| | 6993 | LLVMTypeRef fn_type = LLVMFunctionType(f80_ref, params, 3, false); |
| | 6994 | func_ref = LLVMAddFunction(g->module, func_name, fn_type); |
| | 6995 | } |
| | 6996 | |
| | 6997 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); |
| | 6998 | LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); |
| | 6999 | LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); |
| | 7000 | LLVMValueRef result; |
| | 7001 | if (vector_len == 0) { |
| | 7002 | LLVMValueRef params[3] = { op1, op2, op3 }; |
| | 7003 | result = LLVMBuildCall(g->builder, func_ref, params, 3, ""); |
| | 7004 | } else { |
| | 7005 | result = build_alloca(g, instruction->op1->value->type, "", 0); |
| | 7006 | } |
| | 7007 | |
| | 7008 | LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; |
| | 7009 | for (uint32_t i = 0; i < vector_len; i++) { |
| | 7010 | LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); |
| | 7011 | |
| | 7012 | LLVMValueRef params[3] = { |
| | 7013 | LLVMBuildExtractElement(g->builder, op1, index_value, ""), |
| | 7014 | LLVMBuildExtractElement(g->builder, op2, index_value, ""), |
| | 7015 | LLVMBuildExtractElement(g->builder, op3, index_value, ""), |
| | 7016 | }; |
| | 7017 | LLVMValueRef call_result = LLVMBuildCall(g->builder, func_ref, params, 3, ""); |
| | 7018 | LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""), |
| | 7019 | call_result, index_value, ""); |
| | 7020 | } |
| | 7021 | if (vector_len != 0) { |
| | 7022 | result = LLVMBuildLoad(g->builder, result, ""); |
| | 7023 | } |
| | 7024 | return result; |
| | 7025 | } |
| | 7026 | |
| 6897 | static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction) { | 7027 | static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction) { |
| | 7028 | ZigType *op_type = instruction->op1->value->type; |
| | 7029 | op_type = op_type->id == ZigTypeIdVector ? op_type->data.vector.elem_type : op_type; |
| | 7030 | if (op_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) { |
| | 7031 | return ir_render_soft_f80_mul_add(g, executable, instruction); |
| | 7032 | } |
| 6898 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); | 7033 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); |
| 6899 | LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); | 7034 | LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); |
| 6900 | LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); | 7035 | LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); |