authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-01-19 23:05:35+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-28 11:45:04-07:00
logf8b204bb189125e85a7f14f08c4bab60a462e76e
tree1a395152c1ca74f501d6633840878308f7dcba1b
parent0f3bd2afa320252d4f0ece627917feaade734064

stage1: call compiler-rt for math builtins on f80 on unsupported targets


1 files changed, 135 insertions(+), 0 deletions(-)

src/stage1/codegen.cpp+135
......@@ -6888,13 +6888,148 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, Stage1Air *executable,
68886888 return nullptr;
68896889}
68906890
6891static 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
68916973static 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 }
68926979 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
68936980 LLVMValueRef fn_val = get_float_fn(g, instruction->base.value->type, ZigLLVMFnIdFloatOp, instruction->fn_id);
68946981 return LLVMBuildCall(g->builder, fn_val, &operand, 1, "");
68956982}
68966983
6984static 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
68977027static 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 }
68987033 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
68997034 LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
69007035 LLVMValueRef op3 = ir_llvm_value(g, instruction->op3);