void CodeGen::genFloatMath(GenTree *tree, RegSet::RegisterPreference *pref) { assert(tree->OperGet() == GT_INTRINSIC); GenTreePtr op1 = tree->gtOp.gtOp1; // get tree into a register genCodeForTreeFloat(op1, pref); instruction ins; switch (tree->gtIntrinsic.gtIntrinsicId) { case CORINFO_INTRINSIC_Sin: ins = INS_invalid; break; case CORINFO_INTRINSIC_Cos: ins = INS_invalid; break; case CORINFO_INTRINSIC_Sqrt: ins = INS_vsqrt; break; case CORINFO_INTRINSIC_Abs: ins = INS_vabs; break; case CORINFO_INTRINSIC_Round: { regNumber reg = regSet.PickRegFloat(tree->TypeGet(), pref); genMarkTreeInReg(tree, reg); // convert it to a long and back inst_RV_RV(ins_FloatConv(TYP_LONG,tree->TypeGet()), reg, op1->gtRegNum, tree->TypeGet()); inst_RV_RV(ins_FloatConv(tree->TypeGet(), TYP_LONG), reg, reg); genCodeForTreeFloat_DONE(tree, op1->gtRegNum); return; } break; default: unreached(); } if (ins != INS_invalid) { regNumber reg = regSet.PickRegFloat(tree->TypeGet(), pref); genMarkTreeInReg(tree, reg); inst_RV_RV(ins, reg, op1->gtRegNum, tree->TypeGet()); // mark register that holds tree genCodeForTreeFloat_DONE(tree, reg); } else { unreached(); // If unreached is removed, mark register that holds tree // genCodeForTreeFloat_DONE(tree, op1->gtRegNum); } return; }
void CodeGen::genFloatConst(GenTree* tree, RegSet::RegisterPreference* pref) { assert(tree->gtOper == GT_CNS_DBL); var_types type = tree->gtType; double constValue = tree->gtDblCon.gtDconVal; size_t* cv = (size_t*)&constValue; regNumber dst = regSet.PickRegFloat(type, pref); if (type == TYP_FLOAT) { regNumber reg = regSet.rsPickReg(); float f = forceCastToFloat(constValue); genSetRegToIcon(reg, *((int*)(&f))); getEmitter()->emitIns_R_R(INS_vmov_i2f, EA_4BYTE, dst, reg); } else { assert(type == TYP_DOUBLE); regNumber reg1 = regSet.rsPickReg(); regNumber reg2 = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg1)); genSetRegToIcon(reg1, cv[0]); regSet.rsLockReg(genRegMask(reg1)); genSetRegToIcon(reg2, cv[1]); regSet.rsUnlockReg(genRegMask(reg1)); getEmitter()->emitIns_R_R_R(INS_vmov_i2d, EA_8BYTE, dst, reg1, reg2); } genMarkTreeInReg(tree, dst); return; }
void CodeGen::genComputeAddressableFloat(GenTreePtr tree, regMaskTP addrRegInt, regMaskTP addrRegFlt, RegSet::KeepReg keptReg, regMaskTP needReg, RegSet::KeepReg keepReg, bool freeOnly /* = false */) { noway_assert(genStillAddressable(tree)); noway_assert(varTypeIsFloating(tree->TypeGet())); genDoneAddressableFloat(tree, addrRegInt, addrRegFlt, keptReg); regNumber reg; if (tree->gtFlags & GTF_REG_VAL) { reg = tree->gtRegNum; if (freeOnly && !(genRegMaskFloat(reg, tree->TypeGet()) & regSet.RegFreeFloat())) { goto LOAD_REG; } } else { LOAD_REG: RegSet::RegisterPreference pref(needReg, RBM_NONE); reg = regSet.PickRegFloat(tree->TypeGet(), &pref); genLoadFloat(tree, reg); } genMarkTreeInReg(tree, reg); if (keepReg == RegSet::KEEP_REG) { regSet.SetUsedRegFloat(tree, true); } }
void CodeGen::genFloatSimple(GenTree *tree, RegSet::RegisterPreference *pref) { assert(tree->OperKind() & GTK_SMPOP); var_types type = tree->TypeGet(); RegSet::RegisterPreference defaultPref(RBM_ALLFLOAT, RBM_NONE); if (pref == NULL) { pref = &defaultPref; } switch (tree->OperGet()) { // Assignment case GT_ASG: { genFloatAssign(tree); break; } // Arithmetic binops case GT_ADD: case GT_SUB: case GT_MUL: case GT_DIV: { genFloatArith(tree, pref); break; } case GT_NEG: { GenTreePtr op1 = tree->gtOp.gtOp1; // get the tree into a register genCodeForTreeFloat(op1, pref); // change the sign regNumber reg = regSet.PickRegFloat(type, pref); genMarkTreeInReg(tree, reg); inst_RV_RV(ins_MathOp(tree->OperGet(), type), reg, op1->gtRegNum, type); // mark register that holds tree genCodeForTreeFloat_DONE(tree, reg); return; } case GT_IND: { regMaskTP addrReg; // Make sure the address value is 'addressable' */ addrReg = genMakeAddressable(tree, 0, RegSet::FREE_REG); // Load the value onto the FP stack regNumber reg = regSet.PickRegFloat(type, pref); genLoadFloat(tree, reg); genDoneAddressable(tree, addrReg, RegSet::FREE_REG); genCodeForTreeFloat_DONE(tree, reg); break; } case GT_CAST: { genCodeForTreeCastFloat(tree, pref); break; } // Asg-Arithmetic ops case GT_ASG_ADD: case GT_ASG_SUB: case GT_ASG_MUL: case GT_ASG_DIV: { genFloatAsgArith(tree); break; } case GT_INTRINSIC: genFloatMath(tree, pref); break; case GT_RETURN: { GenTreePtr op1 = tree->gtOp.gtOp1; assert(op1); pref->best = (type==TYP_DOUBLE) ? RBM_DOUBLERET : RBM_FLOATRET; // Compute the result genCodeForTreeFloat(op1, pref); inst_RV_TT(ins_FloatConv(tree->TypeGet(), op1->TypeGet()), REG_FLOATRET, op1); if (compiler->info.compIsVarArgs) { if (tree->TypeGet() == TYP_FLOAT) { inst_RV_RV(INS_vmov_f2i, REG_INTRET, REG_FLOATRET, TYP_FLOAT, EA_4BYTE); } else { assert(tree->TypeGet() == TYP_DOUBLE); inst_RV_RV_RV(INS_vmov_d2i, REG_INTRET, REG_NEXT(REG_INTRET), REG_FLOATRET, EA_8BYTE); } } break; } case GT_ARGPLACE: break; case GT_COMMA: { GenTreePtr op1 = tree->gtOp.gtOp1; GenTreePtr op2 = tree->gtGetOp2(); if (tree->gtFlags & GTF_REVERSE_OPS) { genCodeForTreeFloat(op2, pref); regSet.SetUsedRegFloat(op2, true); genEvalSideEffects(op1); regSet.SetUsedRegFloat(op2, false); } else { genEvalSideEffects(op1); genCodeForTreeFloat(op2, pref); } genCodeForTreeFloat_DONE(tree, op2->gtRegNum); break; } case GT_CKFINITE: genFloatCheckFinite(tree, pref); break; default: NYI("Unhandled register FP codegen"); } }