{
MonoInst *ins = NULL;
int opcode = 0;
+ // Convert Math and MathF methods into LLVM intrinsics, e.g. MathF.Sin -> @llvm.sin.f32
+ if (in_corlib && !strcmp (m_class_get_name (cmethod->klass), "MathF") && cfg->r4fp) {
+ // (float)
+ if (fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R4) {
+ if (!strcmp (cmethod->name, "Ceiling")) {
+ opcode = OP_CEILF;
+ } else if (!strcmp (cmethod->name, "Cos")) {
+ opcode = OP_COSF;
+ } else if (!strcmp (cmethod->name, "Exp")) {
+ opcode = OP_EXPF;
+ } else if (!strcmp (cmethod->name, "Floor")) {
+ opcode = OP_FLOORF;
+ } else if (!strcmp (cmethod->name, "Log2")) {
+ opcode = OP_LOG2F;
+ } else if (!strcmp (cmethod->name, "Log10")) {
+ opcode = OP_LOG10F;
+ } else if (!strcmp (cmethod->name, "Sin")) {
+ opcode = OP_SINF;
+ } else if (!strcmp (cmethod->name, "Sqrt")) {
+ opcode = OP_SQRTF;
+ } else if (!strcmp (cmethod->name, "Truncate")) {
+ opcode = OP_TRUNCF;
+ }
+ }
+ // (float, float)
+ if (fsig->param_count == 2 && fsig->params [0]->type == MONO_TYPE_R4 && fsig->params [1]->type == MONO_TYPE_R4) {
+ if (!strcmp (cmethod->name, "Pow")) {
+ opcode = OP_RPOW;
+ } else if (!strcmp (cmethod->name, "CopySign")) {
+ opcode = OP_RCOPYSIGN;
+ }
+ }
+ // (float, float, float)
+ if (fsig->param_count == 3 && fsig->params [0]->type == MONO_TYPE_R4 && fsig->params [1]->type == MONO_TYPE_R4 && fsig->params [2]->type == MONO_TYPE_R4) {
+ if (!strcmp (cmethod->name, "FusedMultiplyAdd")) {
+ opcode = OP_FMAF;
+ }
+ }
- if (in_corlib && !strcmp (m_class_get_name (cmethod->klass), "MathF") && fsig->param_count && fsig->params [0]->type == MONO_TYPE_R4 && cfg->r4fp) {
- if (!strcmp (cmethod->name, "Sin"))
- opcode = OP_SINF;
- else if (!strcmp (cmethod->name, "Cos"))
- opcode = OP_COSF;
- else if (!strcmp (cmethod->name, "Abs"))
- opcode = OP_ABSF;
- else if (!strcmp (cmethod->name, "Sqrt"))
- opcode = OP_SQRTF;
- else if (!strcmp (cmethod->name, "Floor"))
- opcode = OP_FLOORF;
- else if (!strcmp (cmethod->name, "Ceiling"))
- opcode = OP_CEILF;
- else if (!strcmp (cmethod->name, "FusedMultiplyAdd"))
- opcode = OP_FMAF;
- else if (!strcmp (cmethod->name, "Pow"))
- opcode = OP_RPOW;
- if (opcode && fsig->param_count > 0) {
+ if (opcode) {
MONO_INST_NEW (cfg, ins, opcode);
ins->type = STACK_R8;
ins->dreg = mono_alloc_dreg (cfg, (MonoStackType)ins->type);
ins->sreg1 = args [0]->dreg;
- if (fsig->param_count > 1) { // POW
+ if (fsig->param_count > 1) {
ins->sreg2 = args [1]->dreg;
}
- if (fsig->param_count > 2) { // FMA
+ if (fsig->param_count > 2) {
ins->sreg3 = args [2]->dreg;
}
g_assert (fsig->param_count <= 3);
MONO_ADD_INS (cfg->cbb, ins);
}
}
- /* The LLVM backend supports these intrinsics */
+
if (cmethod->klass == mono_class_try_get_math_class ()) {
- if (strcmp (cmethod->name, "Sin") == 0) {
- opcode = OP_SIN;
- } else if (strcmp (cmethod->name, "Cos") == 0) {
- opcode = OP_COS;
- } else if (strcmp (cmethod->name, "Sqrt") == 0) {
- opcode = OP_SQRT;
- } else if (strcmp (cmethod->name, "Floor") == 0) {
- opcode = OP_FLOOR;
- } else if (strcmp (cmethod->name, "Ceiling") == 0) {
- opcode = OP_CEIL;
- } else if (strcmp (cmethod->name, "FusedMultiplyAdd") == 0) {
- opcode = OP_FMA;
- } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
- opcode = OP_ABS;
+ // (double)
+ if (fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R8) {
+ if (!strcmp (cmethod->name, "Abs")) {
+ opcode = OP_ABS;
+ } else if (!strcmp (cmethod->name, "Ceiling")) {
+ opcode = OP_CEIL;
+ } else if (!strcmp (cmethod->name, "Cos")) {
+ opcode = OP_COS;
+ } else if (!strcmp (cmethod->name, "Exp")) {
+ opcode = OP_EXP;
+ } else if (!strcmp (cmethod->name, "Floor")) {
+ opcode = OP_FLOOR;
+ } else if (!strcmp (cmethod->name, "Log")) {
+ opcode = OP_LOG;
+ } else if (!strcmp (cmethod->name, "Log2")) {
+ opcode = OP_LOG2;
+ } else if (!strcmp (cmethod->name, "Log10")) {
+ opcode = OP_LOG10;
+ } else if (!strcmp (cmethod->name, "Sin")) {
+ opcode = OP_SIN;
+ } else if (!strcmp (cmethod->name, "Sqrt")) {
+ opcode = OP_SQRT;
+ } else if (!strcmp (cmethod->name, "Truncate")) {
+ opcode = OP_TRUNC;
+ }
+ }
+ // (double, double)
+ if (fsig->param_count == 2 && fsig->params [0]->type == MONO_TYPE_R8 && fsig->params [1]->type == MONO_TYPE_R8) {
+ // Max and Min can only be optimized in fast math mode
+ if (!strcmp (cmethod->name, "Max") && mono_use_fast_math) {
+ opcode = OP_FMAX;
+ } else if (!strcmp (cmethod->name, "Min") && mono_use_fast_math) {
+ opcode = OP_FMIN;
+ } else if (!strcmp (cmethod->name, "Pow")) {
+ opcode = OP_FPOW;
+ } else if (!strcmp (cmethod->name, "CopySign")) {
+ opcode = OP_FCOPYSIGN;
+ }
+ }
+ // (double, double, double)
+ if (fsig->param_count == 3 && fsig->params [0]->type == MONO_TYPE_R8 && fsig->params [1]->type == MONO_TYPE_R8 && fsig->params [2]->type == MONO_TYPE_R8) {
+ if (!strcmp (cmethod->name, "FusedMultiplyAdd")) {
+ opcode = OP_FMA;
+ }
}
- // Max and Min can only be optimized in fast math mode
- else if (strcmp (cmethod->name, "Max") == 0 && mono_use_fast_math && fsig->params [0]->type == MONO_TYPE_R8) {
- opcode = OP_FMAX;
- } else if (strcmp (cmethod->name, "Min") == 0 && mono_use_fast_math && fsig->params [0]->type == MONO_TYPE_R8) {
- opcode = OP_FMIN;
+
+ // Math also contains overloads for floats (MathF inlines them)
+ // (float)
+ if (fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R4) {
+ if (!strcmp (cmethod->name, "Abs")) {
+ opcode = OP_ABSF;
+ }
}
- // Math.Max/Min also have float overloads (MathF.Max/Min just redirect to them)
- else if (strcmp (cmethod->name, "Max") == 0 && mono_use_fast_math && fsig->params [0]->type == MONO_TYPE_R4) {
- opcode = OP_RMAX;
- } else if (strcmp (cmethod->name, "Min") == 0 && mono_use_fast_math && fsig->params [0]->type == MONO_TYPE_R4) {
- opcode = OP_RMIN;
- } else if (strcmp (cmethod->name, "Pow") == 0) {
- opcode = OP_FPOW;
+ // (float, float)
+ if (fsig->param_count == 2 && fsig->params [0]->type == MONO_TYPE_R4 && fsig->params [1]->type == MONO_TYPE_R4) {
+ if (!strcmp (cmethod->name, "Max") && mono_use_fast_math) {
+ opcode = OP_RMAX;
+ } else if (!strcmp (cmethod->name, "Min") && mono_use_fast_math) {
+ opcode = OP_RMIN;
+ } else if (!strcmp (cmethod->name, "Pow")) {
+ opcode = OP_RPOW;
+ }
}
if (opcode && fsig->param_count > 0) {
ins->type = STACK_R8;
ins->dreg = mono_alloc_dreg (cfg, (MonoStackType)ins->type);
ins->sreg1 = args [0]->dreg;
- if (fsig->param_count > 1) { // POW, MIN, MAX
+ if (fsig->param_count > 1) {
ins->sreg2 = args [1]->dreg;
}
- if (fsig->param_count > 2) { // FMA
+ if (fsig->param_count > 2) {
ins->sreg3 = args [2]->dreg;
}
g_assert (fsig->param_count <= 3);
INTRINS_FMAF,
INTRINS_POW,
INTRINS_POWF,
+ INTRINS_EXP,
+ INTRINS_EXPF,
+ INTRINS_LOG,
+ INTRINS_LOG2,
+ INTRINS_LOG2F,
+ INTRINS_LOG10,
+ INTRINS_LOG10F,
+ INTRINS_TRUNC,
+ INTRINS_TRUNCF,
+ INTRINS_COPYSIGN,
+ INTRINS_COPYSIGNF,
INTRINS_EXPECT_I8,
INTRINS_EXPECT_I1,
INTRINS_CTPOP_I32,
values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_SINF), args, 1, dname);
break;
}
+ case OP_EXP: {
+ LLVMValueRef args [1];
+
+ args [0] = convert (ctx, lhs, LLVMDoubleType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_EXP), args, 1, dname);
+ break;
+ }
+ case OP_EXPF: {
+ LLVMValueRef args [1];
+
+ args [0] = convert (ctx, lhs, LLVMFloatType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_EXPF), args, 1, dname);
+ break;
+ }
+ case OP_LOG2: {
+ LLVMValueRef args [1];
+
+ args [0] = convert (ctx, lhs, LLVMDoubleType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_LOG2), args, 1, dname);
+ break;
+ }
+ case OP_LOG2F: {
+ LLVMValueRef args [1];
+
+ args [0] = convert (ctx, lhs, LLVMFloatType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_LOG2F), args, 1, dname);
+ break;
+ }
+ case OP_LOG10: {
+ LLVMValueRef args [1];
+
+ args [0] = convert (ctx, lhs, LLVMDoubleType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_LOG10), args, 1, dname);
+ break;
+ }
+ case OP_LOG10F: {
+ LLVMValueRef args [1];
+
+ args [0] = convert (ctx, lhs, LLVMFloatType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_LOG10F), args, 1, dname);
+ break;
+ }
+ case OP_LOG: {
+ LLVMValueRef args [1];
+
+ args [0] = convert (ctx, lhs, LLVMDoubleType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_LOG), args, 1, dname);
+ break;
+ }
+ case OP_TRUNC: {
+ LLVMValueRef args [1];
+
+ args [0] = convert (ctx, lhs, LLVMDoubleType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_TRUNC), args, 1, dname);
+ break;
+ }
+ case OP_TRUNCF: {
+ LLVMValueRef args [1];
+
+ args [0] = convert (ctx, lhs, LLVMFloatType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_TRUNCF), args, 1, dname);
+ break;
+ }
case OP_COS: {
LLVMValueRef args [1];
values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_POW), args, 2, dname);
break;
}
+ case OP_FCOPYSIGN: {
+ LLVMValueRef args [2];
+
+ args [0] = convert (ctx, lhs, LLVMDoubleType ());
+ args [1] = convert (ctx, rhs, LLVMDoubleType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_COPYSIGN), args, 2, dname);
+ break;
+ }
+ case OP_RCOPYSIGN: {
+ LLVMValueRef args [2];
+
+ args [0] = convert (ctx, lhs, LLVMFloatType ());
+ args [1] = convert (ctx, rhs, LLVMFloatType ());
+ values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_COPYSIGNF), args, 2, dname);
+ break;
+ }
case OP_IMIN:
case OP_LMIN:
{INTRINS_SQRTF, "llvm.sqrt.f32"},
{INTRINS_POWF, "llvm.pow.f32"},
{INTRINS_POW, "llvm.pow.f64"},
+ {INTRINS_EXP, "llvm.exp.f64"},
+ {INTRINS_EXPF, "llvm.exp.f32"},
+ {INTRINS_LOG, "llvm.log.f64"},
+ {INTRINS_LOG2, "llvm.log2.f64"},
+ {INTRINS_LOG2F, "llvm.log2.f32"},
+ {INTRINS_LOG10, "llvm.log10.f64"},
+ {INTRINS_LOG10F, "llvm.log10.f32"},
+ {INTRINS_TRUNC, "llvm.trunc.f64"},
+ {INTRINS_TRUNCF, "llvm.trunc.f32"},
+ {INTRINS_COPYSIGN, "llvm.copysign.f64"},
+ {INTRINS_COPYSIGNF, "llvm.copysign.f32"},
{INTRINS_EXPECT_I8, "llvm.expect.i8"},
{INTRINS_EXPECT_I1, "llvm.expect.i1"},
{INTRINS_CTPOP_I32, "llvm.ctpop.i32"},
AddFunc (module, name, LLVMFloatType (), params, 3);
break;
}
+ case INTRINS_EXP:
+ case INTRINS_LOG:
+ case INTRINS_LOG2:
+ case INTRINS_LOG10:
+ case INTRINS_TRUNC:
case INTRINS_SIN:
case INTRINS_COS:
case INTRINS_SQRT:
case INTRINS_FLOOR:
case INTRINS_CEIL:
case INTRINS_FABS: {
- LLVMTypeRef params [] = { LLVMDoubleType () };
-
- AddFunc (module, name, LLVMDoubleType (), params, 1);
+ AddFunc1 (module, name, LLVMDoubleType (), LLVMDoubleType ());
break;
}
+ case INTRINS_EXPF:
+ case INTRINS_LOG2F:
+ case INTRINS_LOG10F:
+ case INTRINS_TRUNCF:
case INTRINS_SINF:
case INTRINS_COSF:
case INTRINS_SQRTF:
case INTRINS_FLOORF:
case INTRINS_CEILF:
case INTRINS_ABSF: {
- LLVMTypeRef params [] = { LLVMFloatType () };
-
- AddFunc (module, name, LLVMFloatType (), params, 1);
+ AddFunc1 (module, name, LLVMFloatType (), LLVMFloatType ());
break;
}
+ case INTRINS_COPYSIGNF:
case INTRINS_POWF:
AddFunc2 (module, name, LLVMFloatType (), LLVMFloatType (), LLVMFloatType ());
break;
+ case INTRINS_COPYSIGN:
case INTRINS_POW:
AddFunc2 (module, name, LLVMDoubleType (), LLVMDoubleType (), LLVMDoubleType ());
break;
MINI_OP(OP_FMAX, "fmax", FREG, FREG, FREG)
MINI_OP(OP_FMIN, "fmin", FREG, FREG, FREG)
MINI_OP(OP_FPOW, "fpow", FREG, FREG, FREG)
+MINI_OP(OP_RCOPYSIGN,"rcopysign", FREG, FREG, FREG)
+MINI_OP(OP_FCOPYSIGN,"fcopysign", FREG, FREG, FREG)
/* opcodes most architecture have */
MINI_OP(OP_ADC, "adc", IREG, IREG, IREG)
MINI_OP3(OP_FMA, "fma", FREG, FREG, FREG, FREG)
MINI_OP(OP_SINF, "sinf", FREG, FREG, NONE)
MINI_OP(OP_COSF, "cosf", FREG, FREG, NONE)
+MINI_OP(OP_EXPF, "expf", FREG, FREG, NONE)
+MINI_OP(OP_EXP, "exp", FREG, FREG, NONE)
+MINI_OP(OP_LOG, "log", FREG, FREG, NONE)
+MINI_OP(OP_LOG2, "log2", FREG, FREG, NONE)
+MINI_OP(OP_LOG2F, "log2f", FREG, FREG, NONE)
+MINI_OP(OP_LOG10, "log10", FREG, FREG, NONE)
+MINI_OP(OP_LOG10F, "log10f", FREG, FREG, NONE)
+MINI_OP(OP_TRUNC, "trunc", FREG, FREG, NONE)
+MINI_OP(OP_TRUNCF, "truncf", FREG, FREG, NONE)
MINI_OP(OP_ABSF, "absf", FREG, FREG, NONE)
MINI_OP(OP_SQRTF, "sqrtf", FREG, FREG, NONE)
MINI_OP(OP_CEILF, "ceilf", FREG, FREG, NONE)