| ... | ... | @@ -1598,6 +1598,81 @@ static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType * |
| 1598 | 1598 | return nullptr; |
| 1599 | 1599 | } |
| 1600 | 1600 | |
| 1601 | |
| 1602 | static LLVMValueRef gen_soft_f80_widen_or_shorten(CodeGen *g, ZigType *actual_type, |
| 1603 | ZigType *wanted_type, LLVMValueRef expr_val) |
| 1604 | { |
| 1605 | ZigType *scalar_actual_type = (actual_type->id == ZigTypeIdVector) ? |
| 1606 | actual_type->data.vector.elem_type : actual_type; |
| 1607 | ZigType *scalar_wanted_type = (wanted_type->id == ZigTypeIdVector) ? |
| 1608 | wanted_type->data.vector.elem_type : wanted_type; |
| 1609 | uint64_t actual_bits = scalar_actual_type->data.floating.bit_count; |
| 1610 | uint64_t wanted_bits = scalar_wanted_type->data.floating.bit_count; |
| 1611 | |
| 1612 | |
| 1613 | LLVMTypeRef param_type; |
| 1614 | LLVMTypeRef return_type; |
| 1615 | const char *func_name; |
| 1616 | |
| 1617 | if (actual_bits == wanted_bits) { |
| 1618 | return expr_val; |
| 1619 | } else if (actual_bits == 80) { |
| 1620 | param_type = g->builtin_types.entry_f80->llvm_type; |
| 1621 | switch (wanted_bits) { |
| 1622 | case 16: |
| 1623 | return_type = g->builtin_types.entry_f16->llvm_type; |
| 1624 | func_name = "__truncxfhf2"; |
| 1625 | break; |
| 1626 | case 32: |
| 1627 | return_type = g->builtin_types.entry_f32->llvm_type; |
| 1628 | func_name = "__truncxfff2"; |
| 1629 | break; |
| 1630 | case 64: |
| 1631 | return_type = g->builtin_types.entry_f64->llvm_type; |
| 1632 | func_name = "__truncxfdf2"; |
| 1633 | break; |
| 1634 | case 128: |
| 1635 | return_type = g->builtin_types.entry_f128->llvm_type; |
| 1636 | func_name = "__extendxftf2"; |
| 1637 | break; |
| 1638 | default: |
| 1639 | zig_unreachable(); |
| 1640 | } |
| 1641 | } else if (wanted_bits == 80) { |
| 1642 | return_type = g->builtin_types.entry_f80->llvm_type; |
| 1643 | switch (actual_bits) { |
| 1644 | case 16: |
| 1645 | param_type = g->builtin_types.entry_f16->llvm_type; |
| 1646 | func_name = "__extendhfxf2"; |
| 1647 | break; |
| 1648 | case 32: |
| 1649 | param_type = g->builtin_types.entry_f32->llvm_type; |
| 1650 | func_name = "__extendffxf2"; |
| 1651 | break; |
| 1652 | case 64: |
| 1653 | param_type = g->builtin_types.entry_f64->llvm_type; |
| 1654 | func_name = "__extenddfxf2"; |
| 1655 | break; |
| 1656 | case 128: |
| 1657 | param_type = g->builtin_types.entry_f128->llvm_type; |
| 1658 | func_name = "__trunctfxf2"; |
| 1659 | break; |
| 1660 | default: |
| 1661 | zig_unreachable(); |
| 1662 | } |
| 1663 | } else { |
| 1664 | zig_unreachable(); |
| 1665 | } |
| 1666 | |
| 1667 | LLVMValueRef func_ref = LLVMGetNamedFunction(g->module, func_name); |
| 1668 | if (func_ref == nullptr) { |
| 1669 | LLVMTypeRef fn_type = LLVMFunctionType(return_type, &param_type, 1, false); |
| 1670 | func_ref = LLVMAddFunction(g->module, func_name, fn_type); |
| 1671 | } |
| 1672 | |
| 1673 | return LLVMBuildCall(g->builder, func_ref, &expr_val, 1, ""); |
| 1674 | } |
| 1675 | |
| 1601 | 1676 | static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type, |
| 1602 | 1677 | ZigType *wanted_type, LLVMValueRef expr_val) |
| 1603 | 1678 | { |
| ... | ... | @@ -1612,6 +1687,13 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z |
| 1612 | 1687 | uint64_t actual_bits; |
| 1613 | 1688 | uint64_t wanted_bits; |
| 1614 | 1689 | if (scalar_actual_type->id == ZigTypeIdFloat) { |
| 1690 | |
| 1691 | if ((scalar_actual_type == g->builtin_types.entry_f80 |
| 1692 | || scalar_wanted_type == g->builtin_types.entry_f80) |
| 1693 | && !target_has_f80(g->zig_target)) |
| 1694 | { |
| 1695 | return gen_soft_f80_widen_or_shorten(g, actual_type, wanted_type, expr_val); |
| 1696 | } |
| 1615 | 1697 | actual_bits = scalar_actual_type->data.floating.bit_count; |
| 1616 | 1698 | wanted_bits = scalar_wanted_type->data.floating.bit_count; |
| 1617 | 1699 | } else if (scalar_actual_type->id == ZigTypeIdInt) { |
| ... | ... | @@ -3142,6 +3224,142 @@ static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type |
| 3142 | 3224 | } |
| 3143 | 3225 | } |
| 3144 | 3226 | |
| 3227 | static LLVMValueRef get_soft_f80_bin_op_func(CodeGen *g, const char *name, int param_count, LLVMTypeRef return_type) { |
| 3228 | LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, name); |
| 3229 | if (existing_llvm_fn != nullptr) return existing_llvm_fn; |
| 3230 | |
| 3231 | LLVMTypeRef float_type_ref = g->builtin_types.entry_f80->llvm_type; |
| 3232 | LLVMTypeRef param_types[2] = { float_type_ref, float_type_ref }; |
| 3233 | LLVMTypeRef fn_type = LLVMFunctionType(return_type, param_types, param_count, false); |
| 3234 | return LLVMAddFunction(g->module, name, fn_type); |
| 3235 | } |
| 3236 | |
| 3237 | static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable, |
| 3238 | Stage1AirInstBinOp *bin_op_instruction) |
| 3239 | { |
| 3240 | // TODO support vectors |
| 3241 | IrBinOp op_id = bin_op_instruction->op_id; |
| 3242 | Stage1AirInst *op1 = bin_op_instruction->op1; |
| 3243 | Stage1AirInst *op2 = bin_op_instruction->op2; |
| 3244 | |
| 3245 | LLVMValueRef op1_value = ir_llvm_value(g, op1); |
| 3246 | LLVMValueRef op2_value = ir_llvm_value(g, op2); |
| 3247 | |
| 3248 | bool div_exact_safety_check = false; |
| 3249 | LLVMTypeRef return_type = g->builtin_types.entry_f80->llvm_type; |
| 3250 | int param_count = 2; |
| 3251 | const char *func_name; |
| 3252 | switch (op_id) { |
| 3253 | case IrBinOpInvalid: |
| 3254 | case IrBinOpArrayCat: |
| 3255 | case IrBinOpArrayMult: |
| 3256 | case IrBinOpRemUnspecified: |
| 3257 | case IrBinOpBitShiftLeftLossy: |
| 3258 | case IrBinOpBitShiftLeftExact: |
| 3259 | case IrBinOpBitShiftRightLossy: |
| 3260 | case IrBinOpBitShiftRightExact: |
| 3261 | case IrBinOpBoolOr: |
| 3262 | case IrBinOpBoolAnd: |
| 3263 | case IrBinOpMultWrap: |
| 3264 | case IrBinOpAddWrap: |
| 3265 | case IrBinOpSubWrap: |
| 3266 | case IrBinOpBinOr: |
| 3267 | case IrBinOpBinXor: |
| 3268 | case IrBinOpBinAnd: |
| 3269 | case IrBinOpAddSat: |
| 3270 | case IrBinOpSubSat: |
| 3271 | case IrBinOpMultSat: |
| 3272 | case IrBinOpShlSat: |
| 3273 | zig_unreachable(); |
| 3274 | case IrBinOpCmpEq: |
| 3275 | return_type = g->builtin_types.entry_i32->llvm_type; |
| 3276 | func_name = "__eqxf2"; |
| 3277 | break; |
| 3278 | case IrBinOpCmpNotEq: |
| 3279 | return_type = g->builtin_types.entry_i32->llvm_type; |
| 3280 | func_name = "__nexf2"; |
| 3281 | break; |
| 3282 | case IrBinOpCmpLessOrEq: |
| 3283 | case IrBinOpCmpLessThan: |
| 3284 | return_type = g->builtin_types.entry_i32->llvm_type; |
| 3285 | func_name = "__lexf2"; |
| 3286 | break; |
| 3287 | case IrBinOpCmpGreaterOrEq: |
| 3288 | case IrBinOpCmpGreaterThan: |
| 3289 | return_type = g->builtin_types.entry_i32->llvm_type; |
| 3290 | func_name = "__gexf2"; |
| 3291 | break; |
| 3292 | case IrBinOpMaximum: |
| 3293 | func_name = "__fmaxx"; |
| 3294 | break; |
| 3295 | case IrBinOpMinimum: |
| 3296 | func_name = "__fminx"; |
| 3297 | break; |
| 3298 | case IrBinOpMult: |
| 3299 | func_name = "__mulxf3"; |
| 3300 | break; |
| 3301 | case IrBinOpAdd: |
| 3302 | func_name = "__addxf3"; |
| 3303 | break; |
| 3304 | case IrBinOpSub: |
| 3305 | func_name = "__subxf3"; |
| 3306 | break; |
| 3307 | case IrBinOpDivUnspecified: |
| 3308 | func_name = "__divxf3"; |
| 3309 | break; |
| 3310 | case IrBinOpDivExact: |
| 3311 | func_name = "__divxf3"; |
| 3312 | div_exact_safety_check = bin_op_instruction->safety_check_on && |
| 3313 | ir_want_runtime_safety(g, &bin_op_instruction->base); |
| 3314 | break; |
| 3315 | case IrBinOpDivTrunc: |
| 3316 | param_count = 1; |
| 3317 | func_name = "__truncx"; |
| 3318 | break; |
| 3319 | case IrBinOpDivFloor: |
| 3320 | param_count = 1; |
| 3321 | func_name = "__floorx"; |
| 3322 | break; |
| 3323 | case IrBinOpRemRem: |
| 3324 | param_count = 1; |
| 3325 | func_name = "__remx"; |
| 3326 | break; |
| 3327 | case IrBinOpRemMod: |
| 3328 | param_count = 1; |
| 3329 | func_name = "__modx"; |
| 3330 | break; |
| 3331 | default: |
| 3332 | zig_unreachable(); |
| 3333 | } |
| 3334 | |
| 3335 | LLVMValueRef func_ref = get_soft_f80_bin_op_func(g, func_name, param_count, return_type); |
| 3336 | |
| 3337 | LLVMValueRef params[2] = {op1_value, op2_value}; |
| 3338 | LLVMValueRef result = LLVMBuildCall(g->builder, func_ref, params, param_count, ""); |
| 3339 | |
| 3340 | if (div_exact_safety_check) { |
| 3341 | // Safety check: a / b == floor(a / b) |
| 3342 | func_ref = get_soft_f80_bin_op_func(g, "__floorx", 1, return_type); |
| 3343 | LLVMValueRef floored = LLVMBuildCall(g->builder, func_ref, &result, 1, ""); |
| 3344 | |
| 3345 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); |
| 3346 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); |
| 3347 | |
| 3348 | LLVMValueRef params[2] = {result, floored}; |
| 3349 | func_ref = get_soft_f80_bin_op_func(g, "__eqxf2", 2, g->builtin_types.entry_i32->llvm_type); |
| 3350 | LLVMValueRef ok_bit = LLVMBuildCall(g->builder, func_ref, params, 2, ""); |
| 3351 | |
| 3352 | LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); |
| 3353 | |
| 3354 | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| 3355 | gen_safety_crash(g, PanicMsgIdExactDivisionRemainder); |
| 3356 | |
| 3357 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 3358 | } |
| 3359 | |
| 3360 | return result; |
| 3361 | } |
| 3362 | |
| 3145 | 3363 | static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, |
| 3146 | 3364 | Stage1AirInstBinOp *bin_op_instruction) |
| 3147 | 3365 | { |
| ... | ... | @@ -3151,6 +3369,10 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, |
| 3151 | 3369 | |
| 3152 | 3370 | ZigType *operand_type = op1->value->type; |
| 3153 | 3371 | ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; |
| 3372 | if (scalar_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) { |
| 3373 | return ir_render_soft_f80_bin_op(g, executable, bin_op_instruction); |
| 3374 | } |
| 3375 | |
| 3154 | 3376 | |
| 3155 | 3377 | bool want_runtime_safety = bin_op_instruction->safety_check_on && |
| 3156 | 3378 | ir_want_runtime_safety(g, &bin_op_instruction->base); |
| ... | ... | @@ -3158,7 +3380,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, |
| 3158 | 3380 | LLVMValueRef op1_value = ir_llvm_value(g, op1); |
| 3159 | 3381 | LLVMValueRef op2_value = ir_llvm_value(g, op2); |
| 3160 | 3382 | |
| 3161 | | |
| 3162 | 3383 | switch (op_id) { |
| 3163 | 3384 | case IrBinOpInvalid: |
| 3164 | 3385 | case IrBinOpArrayCat: |
| ... | ... | @@ -5927,7 +6148,7 @@ static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1 |
| 5927 | 6148 | static_assert(PrefetchCacheInstruction == 0, ""); |
| 5928 | 6149 | static_assert(PrefetchCacheData == 1, ""); |
| 5929 | 6150 | assert(instruction->cache == PrefetchCacheData || instruction->cache == PrefetchCacheInstruction); |
| 5930 | | |
| 6151 | |
| 5931 | 6152 | // LLVM fails during codegen of instruction cache prefetchs for these architectures. |
| 5932 | 6153 | // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported by the target. |
| 5933 | 6154 | // To work around this, simply don't emit llvm.prefetch in this case. |
| ... | ... | @@ -8920,8 +9141,19 @@ static void define_builtin_types(CodeGen *g) { |
| 8920 | 9141 | if (target_has_f80(g->zig_target)) { |
| 8921 | 9142 | add_fp_entry(g, "f80", 80, LLVMX86FP80Type(), &g->builtin_types.entry_f80); |
| 8922 | 9143 | } else { |
| 8923 | | // use f128 for correct size and alignment |
| 8924 | | add_fp_entry(g, "f80", 128, LLVMFP128Type(), &g->builtin_types.entry_f80); |
| 9144 | ZigType *entry = new_type_table_entry(ZigTypeIdFloat); |
| 9145 | entry->llvm_type = get_int_type(g, false, 128)->llvm_type; |
| 9146 | entry->size_in_bits = 8 * LLVMStoreSizeOfType(g->target_data_ref, entry->llvm_type); |
| 9147 | entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); |
| 9148 | entry->abi_align = 16; |
| 9149 | buf_init_from_str(&entry->name, "f80"); |
| 9150 | entry->data.floating.bit_count = 80; |
| 9151 | |
| 9152 | entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| 9153 | entry->size_in_bits, ZigLLVMEncoding_DW_ATE_unsigned()); |
| 9154 | |
| 9155 | g->builtin_types.entry_f80 = entry; |
| 9156 | g->primitive_type_table.put(&entry->name, entry); |
| 8925 | 9157 | } |
| 8926 | 9158 | |
| 8927 | 9159 | switch (g->zig_target->arch) { |