diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 548abebc6f..2051d39a7c 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -6888,13 +6888,148 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, Stage1Air *executable, return nullptr; } +static LLVMValueRef ir_render_soft_f80_float_op(CodeGen *g, Stage1Air *executable, Stage1AirInstFloatOp *instruction) { + ZigType *op_type = instruction->operand->value->type; + uint32_t vector_len = op_type->id == ZigTypeIdVector ? op_type->data.vector.len : 0; + + const char *func_name; + switch (instruction->fn_id) { + case BuiltinFnIdSqrt: + func_name = "__sqrt"; + break; + case BuiltinFnIdSin: + func_name = "__sinx"; + break; + case BuiltinFnIdCos: + func_name = "__cosx"; + break; + case BuiltinFnIdExp: + func_name = "__expx"; + break; + case BuiltinFnIdExp2: + func_name = "__exp2x"; + break; + case BuiltinFnIdLog: + func_name = "__logx"; + break; + case BuiltinFnIdLog2: + func_name = "__log2x"; + break; + case BuiltinFnIdLog10: + func_name = "__log10x"; + break; + case BuiltinFnIdFabs: + func_name = "__fabsx"; + break; + case BuiltinFnIdFloor: + func_name = "__floorx"; + break; + case BuiltinFnIdCeil: + func_name = "__ceilx"; + break; + case BuiltinFnIdTrunc: + func_name = "__truncx"; + break; + case BuiltinFnIdNearbyInt: + func_name = "__nearbyintx"; + break; + case BuiltinFnIdRound: + func_name = "__roundx"; + break; + default: + zig_unreachable(); + } + + + LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, func_name); + if (func_ref == nullptr) { + LLVMTypeRef f80_ref = g->builtin_types.entry_f80->llvm_type; + LLVMTypeRef fn_type = LLVMFunctionType(f80_ref, &f80_ref, 1, false); + func_ref = LLVMAddFunction(g->module, func_name, fn_type); + } + + LLVMValueRef operand = ir_llvm_value(g, instruction->operand); + LLVMValueRef result; + if (vector_len == 0) { + result = LLVMBuildCall(g->builder, func_ref, &operand, 1, ""); + } else { + result = build_alloca(g, instruction->operand->value->type, "", 0); + } + + LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; + for (uint32_t i = 0; i < vector_len; i++) { + LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); + LLVMValueRef param = LLVMBuildExtractElement(g->builder, operand, index_value, ""); + LLVMValueRef call_result = LLVMBuildCall(g->builder, func_ref, ¶m, 1, ""); + LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""), + call_result, index_value, ""); + } + if (vector_len != 0) { + result = LLVMBuildLoad(g->builder, result, ""); + } + return result; +} + static LLVMValueRef ir_render_float_op(CodeGen *g, Stage1Air *executable, Stage1AirInstFloatOp *instruction) { + ZigType *op_type = instruction->operand->value->type; + op_type = op_type->id == ZigTypeIdVector ? op_type->data.vector.elem_type : op_type; + if (op_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) { + return ir_render_soft_f80_float_op(g, executable, instruction); + } LLVMValueRef operand = ir_llvm_value(g, instruction->operand); LLVMValueRef fn_val = get_float_fn(g, instruction->base.value->type, ZigLLVMFnIdFloatOp, instruction->fn_id); return LLVMBuildCall(g->builder, fn_val, &operand, 1, ""); } +static LLVMValueRef ir_render_soft_f80_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction) { + ZigType *op_type = instruction->op1->value->type; + uint32_t vector_len = op_type->id == ZigTypeIdVector ? op_type->data.vector.len : 0; + + const char *func_name = "__fmax"; + LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, func_name); + if (func_ref == nullptr) { + LLVMTypeRef f80_ref = g->builtin_types.entry_f80->llvm_type; + LLVMTypeRef params[3] = { f80_ref, f80_ref, f80_ref }; + LLVMTypeRef fn_type = LLVMFunctionType(f80_ref, params, 3, false); + func_ref = LLVMAddFunction(g->module, func_name, fn_type); + } + + LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); + LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); + LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); + LLVMValueRef result; + if (vector_len == 0) { + LLVMValueRef params[3] = { op1, op2, op3 }; + result = LLVMBuildCall(g->builder, func_ref, params, 3, ""); + } else { + result = build_alloca(g, instruction->op1->value->type, "", 0); + } + + LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type; + for (uint32_t i = 0; i < vector_len; i++) { + LLVMValueRef index_value = LLVMConstInt(usize_ref, i, false); + + LLVMValueRef params[3] = { + LLVMBuildExtractElement(g->builder, op1, index_value, ""), + LLVMBuildExtractElement(g->builder, op2, index_value, ""), + LLVMBuildExtractElement(g->builder, op3, index_value, ""), + }; + LLVMValueRef call_result = LLVMBuildCall(g->builder, func_ref, params, 3, ""); + LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""), + call_result, index_value, ""); + } + if (vector_len != 0) { + result = LLVMBuildLoad(g->builder, result, ""); + } + return result; +} + static LLVMValueRef ir_render_mul_add(CodeGen *g, Stage1Air *executable, Stage1AirInstMulAdd *instruction) { + ZigType *op_type = instruction->op1->value->type; + op_type = op_type->id == ZigTypeIdVector ? op_type->data.vector.elem_type : op_type; + if (op_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) { + return ir_render_soft_f80_mul_add(g, executable, instruction); + } LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); LLVMValueRef op3 = ir_llvm_value(g, instruction->op3);