mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 05:48:31 +00:00
compiler-rt: add comparison functions for f80
This commit is contained in:
parent
72cef17b1a
commit
9bbd3ab257
@ -54,6 +54,8 @@ comptime {
|
||||
@export(__ledf2, .{ .name = "__ledf2", .linkage = linkage });
|
||||
const __letf2 = @import("compiler_rt/compareXf2.zig").__letf2;
|
||||
@export(__letf2, .{ .name = "__letf2", .linkage = linkage });
|
||||
const __lexf2 = @import("compiler_rt/compareXf2.zig").__lexf2;
|
||||
@export(__lexf2, .{ .name = "__lexf2", .linkage = linkage });
|
||||
|
||||
const __gesf2 = @import("compiler_rt/compareXf2.zig").__gesf2;
|
||||
@export(__gesf2, .{ .name = "__gesf2", .linkage = linkage });
|
||||
@ -61,26 +63,36 @@ comptime {
|
||||
@export(__gedf2, .{ .name = "__gedf2", .linkage = linkage });
|
||||
const __getf2 = @import("compiler_rt/compareXf2.zig").__getf2;
|
||||
@export(__getf2, .{ .name = "__getf2", .linkage = linkage });
|
||||
const __gexf2 = @import("compiler_rt/compareXf2.zig").__gexf2;
|
||||
@export(__gexf2, .{ .name = "__gexf2", .linkage = linkage });
|
||||
|
||||
const __eqsf2 = @import("compiler_rt/compareXf2.zig").__eqsf2;
|
||||
@export(__eqsf2, .{ .name = "__eqsf2", .linkage = linkage });
|
||||
const __eqdf2 = @import("compiler_rt/compareXf2.zig").__eqdf2;
|
||||
@export(__eqdf2, .{ .name = "__eqdf2", .linkage = linkage });
|
||||
const __eqxf2 = @import("compiler_rt/compareXf2.zig").__eqxf2;
|
||||
@export(__eqxf2, .{ .name = "__eqxf2", .linkage = linkage });
|
||||
|
||||
const __ltsf2 = @import("compiler_rt/compareXf2.zig").__ltsf2;
|
||||
@export(__ltsf2, .{ .name = "__ltsf2", .linkage = linkage });
|
||||
const __ltdf2 = @import("compiler_rt/compareXf2.zig").__ltdf2;
|
||||
@export(__ltdf2, .{ .name = "__ltdf2", .linkage = linkage });
|
||||
const __ltxf2 = @import("compiler_rt/compareXf2.zig").__ltxf2;
|
||||
@export(__ltxf2, .{ .name = "__ltxf2", .linkage = linkage });
|
||||
|
||||
const __nesf2 = @import("compiler_rt/compareXf2.zig").__nesf2;
|
||||
@export(__nesf2, .{ .name = "__nesf2", .linkage = linkage });
|
||||
const __nedf2 = @import("compiler_rt/compareXf2.zig").__nedf2;
|
||||
@export(__nedf2, .{ .name = "__nedf2", .linkage = linkage });
|
||||
const __nexf2 = @import("compiler_rt/compareXf2.zig").__nexf2;
|
||||
@export(__nexf2, .{ .name = "__nexf2", .linkage = linkage });
|
||||
|
||||
const __gtsf2 = @import("compiler_rt/compareXf2.zig").__gtsf2;
|
||||
@export(__gtsf2, .{ .name = "__gtsf2", .linkage = linkage });
|
||||
const __gtdf2 = @import("compiler_rt/compareXf2.zig").__gtdf2;
|
||||
@export(__gtdf2, .{ .name = "__gtdf2", .linkage = linkage });
|
||||
const __gtxf2 = @import("compiler_rt/compareXf2.zig").__gtxf2;
|
||||
@export(__gtxf2, .{ .name = "__gtxf2", .linkage = linkage });
|
||||
|
||||
if (!is_test) {
|
||||
@export(__lesf2, .{ .name = "__cmpsf2", .linkage = linkage });
|
||||
|
||||
@ -144,6 +144,73 @@ pub fn __gtdf2(a: f64, b: f64) callconv(.C) i32 {
|
||||
return __gedf2(a, b);
|
||||
}
|
||||
|
||||
// Comparison between f80
|
||||
|
||||
pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT {
|
||||
const a_rep = @ptrCast(*const std.math.F80Repr, &a).*;
|
||||
const b_rep = @ptrCast(*const std.math.F80Repr, &b).*;
|
||||
const sig_bits = std.math.floatMantissaBits(f80);
|
||||
const int_bit = 0x8000000000000000;
|
||||
const sign_bit = 0x8000;
|
||||
const special_exp = 0x7FFF;
|
||||
|
||||
// If either a or b is NaN, they are unordered.
|
||||
if ((a_rep.exp & special_exp == special_exp and a_rep.fraction ^ int_bit != 0) or
|
||||
(b_rep.exp & special_exp == special_exp and b_rep.fraction ^ int_bit != 0))
|
||||
return RT.Unordered;
|
||||
|
||||
// If a and b are both zeros, they are equal.
|
||||
if ((a_rep.fraction | b_rep.fraction) | ((a_rep.exp | b_rep.exp) & special_exp) == 0)
|
||||
return .Equal;
|
||||
|
||||
if (@boolToInt(a_rep.exp == b_rep.exp) & @boolToInt(a_rep.fraction == b_rep.fraction) != 0) {
|
||||
return .Equal;
|
||||
} else if (a_rep.exp & sign_bit != b_rep.exp & sign_bit) {
|
||||
// signs are different
|
||||
if (@bitCast(i16, a_rep.exp) < @bitCast(i16, b_rep.exp)) {
|
||||
return .Less;
|
||||
} else {
|
||||
return .Greater;
|
||||
}
|
||||
} else {
|
||||
const a_fraction = a_rep.fraction | (@as(u80, a_rep.exp) << sig_bits);
|
||||
const b_fraction = b_rep.fraction | (@as(u80, b_rep.exp) << sig_bits);
|
||||
if (a_fraction < b_fraction) {
|
||||
return .Less;
|
||||
} else {
|
||||
return .Greater;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __lexf2(a: f80, b: f80) callconv(.C) i32 {
|
||||
@setRuntimeSafety(builtin.is_test);
|
||||
const float = cmp_f80(LE, a, b);
|
||||
return @bitCast(i32, float);
|
||||
}
|
||||
|
||||
pub fn __gexf2(a: f80, b: f80) callconv(.C) i32 {
|
||||
@setRuntimeSafety(builtin.is_test);
|
||||
const float = cmp_f80(GE, a, b);
|
||||
return @bitCast(i32, float);
|
||||
}
|
||||
|
||||
pub fn __eqxf2(a: f80, b: f80) callconv(.C) i32 {
|
||||
return __lexf2(a, b);
|
||||
}
|
||||
|
||||
pub fn __ltxf2(a: f80, b: f80) callconv(.C) i32 {
|
||||
return __lexf2(a, b);
|
||||
}
|
||||
|
||||
pub fn __nexf2(a: f80, b: f80) callconv(.C) i32 {
|
||||
return __lexf2(a, b);
|
||||
}
|
||||
|
||||
pub fn __gtxf2(a: f80, b: f80) callconv(.C) i32 {
|
||||
return __gexf2(a, b);
|
||||
}
|
||||
|
||||
// Comparison between f128
|
||||
|
||||
pub fn __letf2(a: f128, b: f128) callconv(.C) i32 {
|
||||
|
||||
@ -3234,6 +3234,49 @@ static LLVMValueRef get_soft_f80_bin_op_func(CodeGen *g, const char *name, int p
|
||||
return LLVMAddFunction(g->module, name, fn_type);
|
||||
}
|
||||
|
||||
enum SoftF80Icmp {
|
||||
NONE,
|
||||
EQ_ZERO,
|
||||
NE_ZERO,
|
||||
LE_ZERO,
|
||||
EQ_NEG,
|
||||
GE_ZERO,
|
||||
EQ_ONE,
|
||||
};
|
||||
|
||||
static LLVMValueRef add_f80_icmp(CodeGen *g, LLVMValueRef val, SoftF80Icmp kind) {
|
||||
switch (kind) {
|
||||
case NONE:
|
||||
return val;
|
||||
case EQ_ZERO: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, "");
|
||||
}
|
||||
case NE_ZERO: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntNE, val, zero, "");
|
||||
}
|
||||
case LE_ZERO: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntSLE, val, zero, "");
|
||||
}
|
||||
case EQ_NEG: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, -1, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, "");
|
||||
}
|
||||
case GE_ZERO: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 0, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntSGE, val, zero, "");
|
||||
}
|
||||
case EQ_ONE: {
|
||||
LLVMValueRef zero = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, 1, true);
|
||||
return LLVMBuildICmp(g->builder, LLVMIntEQ, val, zero, "");
|
||||
}
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
Stage1AirInstBinOp *bin_op_instruction)
|
||||
{
|
||||
@ -3249,6 +3292,7 @@ static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
LLVMTypeRef return_type = g->builtin_types.entry_f80->llvm_type;
|
||||
int param_count = 2;
|
||||
const char *func_name;
|
||||
SoftF80Icmp res_icmp = NONE;
|
||||
switch (op_id) {
|
||||
case IrBinOpInvalid:
|
||||
case IrBinOpArrayCat:
|
||||
@ -3274,20 +3318,32 @@ static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
case IrBinOpCmpEq:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__eqxf2";
|
||||
res_icmp = EQ_ZERO;
|
||||
break;
|
||||
case IrBinOpCmpNotEq:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__nexf2";
|
||||
res_icmp = NE_ZERO;
|
||||
break;
|
||||
case IrBinOpCmpLessOrEq:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__lexf2";
|
||||
res_icmp = LE_ZERO;
|
||||
break;
|
||||
case IrBinOpCmpLessThan:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__lexf2";
|
||||
res_icmp = EQ_NEG;
|
||||
break;
|
||||
case IrBinOpCmpGreaterOrEq:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__gexf2";
|
||||
res_icmp = GE_ZERO;
|
||||
break;
|
||||
case IrBinOpCmpGreaterThan:
|
||||
return_type = g->builtin_types.entry_i32->llvm_type;
|
||||
func_name = "__gexf2";
|
||||
res_icmp = EQ_ONE;
|
||||
break;
|
||||
case IrBinOpMaximum:
|
||||
func_name = "__fmaxx";
|
||||
@ -3338,8 +3394,11 @@ static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
if (vector_len == 0) {
|
||||
LLVMValueRef params[2] = {op1_value, op2_value};
|
||||
result = LLVMBuildCall(g->builder, func_ref, params, param_count, "");
|
||||
result = add_f80_icmp(g, result, res_icmp);
|
||||
} else {
|
||||
result = build_alloca(g, op1->value->type, "", 0);
|
||||
ZigType *alloca_ty = op1->value->type;
|
||||
if (res_icmp != NONE) alloca_ty = get_vector_type(g, vector_len, g->builtin_types.entry_bool);
|
||||
result = build_alloca(g, alloca_ty, "", 0);
|
||||
}
|
||||
|
||||
LLVMTypeRef usize_ref = g->builtin_types.entry_usize->llvm_type;
|
||||
@ -3350,6 +3409,7 @@ static LLVMValueRef ir_render_soft_f80_bin_op(CodeGen *g, Stage1Air *executable,
|
||||
LLVMBuildExtractElement(g->builder, op2_value, index_value, ""),
|
||||
};
|
||||
LLVMValueRef call_result = LLVMBuildCall(g->builder, func_ref, params, param_count, "");
|
||||
call_result = add_f80_icmp(g, call_result, res_icmp);
|
||||
LLVMBuildInsertElement(g->builder, LLVMBuildLoad(g->builder, result, ""),
|
||||
call_result, index_value, "");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user