authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-01-19 21:16:23+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-28 11:45:04-07:00
log8e9fd042b8a56fc4bb8eeae3878b095af96eb1a6
tree2a9c5999caaf44fcec886d979a07495aa93df2dd
parent67d04a988a06f52f4abca848f3579a8037070afe

stage1: emit calls to compiler-rt for f80 on unsupported targets


1 files changed, 236 insertions(+), 4 deletions(-)

src/stage1/codegen.cpp+236-4
......@@ -1598,6 +1598,81 @@ static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *
15981598 return nullptr;
15991599}
16001600
1601
1602static 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
16011676static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type,
16021677 ZigType *wanted_type, LLVMValueRef expr_val)
16031678{
......@@ -1612,6 +1687,13 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
16121687 uint64_t actual_bits;
16131688 uint64_t wanted_bits;
16141689 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 }
16151697 actual_bits = scalar_actual_type->data.floating.bit_count;
16161698 wanted_bits = scalar_wanted_type->data.floating.bit_count;
16171699 } 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
31423224 }
31433225}
31443226
3227static 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
3237static 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
31453363static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
31463364 Stage1AirInstBinOp *bin_op_instruction)
31473365{
......@@ -3151,6 +3369,10 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
31513369
31523370 ZigType *operand_type = op1->value->type;
31533371 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
31543376
31553377 bool want_runtime_safety = bin_op_instruction->safety_check_on &&
31563378 ir_want_runtime_safety(g, &bin_op_instruction->base);
......@@ -3158,7 +3380,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
31583380 LLVMValueRef op1_value = ir_llvm_value(g, op1);
31593381 LLVMValueRef op2_value = ir_llvm_value(g, op2);
31603382
3161
31623383 switch (op_id) {
31633384 case IrBinOpInvalid:
31643385 case IrBinOpArrayCat:
......@@ -5927,7 +6148,7 @@ static LLVMValueRef ir_render_prefetch(CodeGen *g, Stage1Air *executable, Stage1
59276148 static_assert(PrefetchCacheInstruction == 0, "");
59286149 static_assert(PrefetchCacheData == 1, "");
59296150 assert(instruction->cache == PrefetchCacheData || instruction->cache == PrefetchCacheInstruction);
5930
6151
59316152 // LLVM fails during codegen of instruction cache prefetchs for these architectures.
59326153 // This is an LLVM bug as the prefetch intrinsic should be a noop if not supported by the target.
59336154 // To work around this, simply don't emit llvm.prefetch in this case.
......@@ -8920,8 +9141,19 @@ static void define_builtin_types(CodeGen *g) {
89209141 if (target_has_f80(g->zig_target)) {
89219142 add_fp_entry(g, "f80", 80, LLVMX86FP80Type(), &g->builtin_types.entry_f80);
89229143 } 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);
89259157 }
89269158
89279159 switch (g->zig_target->arch) {