diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 70432157420ff..b180058c371c6 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3694,7 +3694,7 @@ class Compiler static void impBashVarAddrsToI(GenTree* tree1, GenTree* tree2 = nullptr); - GenTree* impImplicitIorI4Cast(GenTree* tree, var_types dstTyp); + GenTree* impImplicitIorI4Cast(GenTree* tree, var_types dstTyp, bool zeroExtend = false); GenTree* impImplicitR4orR8Cast(GenTree* tree, var_types dstTyp); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 41f60a4301bb8..7792cf0150cab 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -10378,7 +10378,7 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, _In_ _In_opt_ } /* Print the node ID */ - printTreeID(tree); + printTreeID(JitConfig.JitDumpTreeIDs() ? tree : nullptr); printf(" "); if (tree->gtOper >= GT_COUNT) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index cd021ab658977..984e6aee79ca4 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -2690,27 +2690,32 @@ void Compiler::impBashVarAddrsToI(GenTree* tree1, GenTree* tree2) * turned into explicit casts here. * We also allow an implicit conversion of a ldnull into a TYP_I_IMPL(0) */ - -GenTree* Compiler::impImplicitIorI4Cast(GenTree* tree, var_types dstTyp) +GenTree* Compiler::impImplicitIorI4Cast(GenTree* tree, var_types dstTyp, bool zeroExtend) { - var_types currType = genActualType(tree->gtType); + var_types currType = genActualType(tree); var_types wantedType = genActualType(dstTyp); if (wantedType != currType) { // Automatic upcast for a GT_CNS_INT into TYP_I_IMPL - if ((tree->OperGet() == GT_CNS_INT) && varTypeIsI(dstTyp)) + if (tree->IsCnsIntOrI() && varTypeIsI(dstTyp)) { - if (!varTypeIsI(tree->gtType) || ((tree->gtType == TYP_REF) && (tree->AsIntCon()->gtIconVal == 0))) + if ((currType == TYP_REF) && (tree->AsIntCon()->IconValue() == 0)) + { + tree->gtType = TYP_I_IMPL; + } +#ifdef TARGET_64BIT + else if (currType == TYP_INT) { tree->gtType = TYP_I_IMPL; } +#endif // TARGET_64BIT } #ifdef TARGET_64BIT else if (varTypeIsI(wantedType) && (currType == TYP_INT)) { // Note that this allows TYP_INT to be cast to a TYP_I_IMPL when wantedType is a TYP_BYREF or TYP_REF - tree = gtNewCastNode(TYP_I_IMPL, tree, false, TYP_I_IMPL); + tree = gtNewCastNode(TYP_I_IMPL, tree, zeroExtend, TYP_I_IMPL); } else if ((wantedType == TYP_INT) && varTypeIsI(currType)) { @@ -2724,7 +2729,7 @@ GenTree* Compiler::impImplicitIorI4Cast(GenTree* tree, var_types dstTyp) } /***************************************************************************** - * TYP_FLOAT and TYP_DOUBLE can be used almost interchangeably in some cases, + * TYP_FLOAT and TYP_DOUBLE can be used almost interchangeably in most cases, * but we want to make that an explicit cast in our trees, so any implicit casts * that exist in the IL are turned into explicit casts here. */ @@ -5481,6 +5486,7 @@ void Compiler::impValidateMemoryAccessOpcode(const BYTE* codeAddr, const BYTE* c /***************************************************************************** * Determine the result type of an arithmetic operation * On 64-bit inserts upcasts when native int is mixed with int32 + * Also inserts upcasts to double when float and double are mixed. */ var_types Compiler::impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTree** pOp1, GenTree** pOp2) { @@ -5488,18 +5494,17 @@ var_types Compiler::impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTr GenTree* op1 = *pOp1; GenTree* op2 = *pOp2; - // Arithmetic operations are generally only allowed with - // primitive types, but certain operations are allowed - // with byrefs - - if ((oper == GT_SUB) && (genActualType(op1->TypeGet()) == TYP_BYREF || genActualType(op2->TypeGet()) == TYP_BYREF)) + // Arithmetic operations are generally only allowed with primitive types, but certain operations are allowed + // with byrefs. + // + if ((oper == GT_SUB) && (op1->TypeIs(TYP_BYREF) || op2->TypeIs(TYP_BYREF))) { - if ((genActualType(op1->TypeGet()) == TYP_BYREF) && (genActualType(op2->TypeGet()) == TYP_BYREF)) + if (op1->TypeIs(TYP_BYREF) && op2->TypeIs(TYP_BYREF)) { // byref1-byref2 => gives a native int type = TYP_I_IMPL; } - else if (genActualTypeIsIntOrI(op1->TypeGet()) && (genActualType(op2->TypeGet()) == TYP_BYREF)) + else if (genActualTypeIsIntOrI(op1) && op2->TypeIs(TYP_BYREF)) { // [native] int - byref => gives a native int @@ -5519,87 +5524,64 @@ var_types Compiler::impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTr // So here we decide to make the resulting type to be a native int. CLANG_FORMAT_COMMENT_ANCHOR; -#ifdef TARGET_64BIT - if (genActualType(op1->TypeGet()) != TYP_I_IMPL) - { - // insert an explicit upcast - op1 = *pOp1 = gtNewCastNode(TYP_I_IMPL, op1, fUnsigned, fUnsigned ? TYP_U_IMPL : TYP_I_IMPL); - } -#endif // TARGET_64BIT + // Insert an explicit upcast if needed. + op1 = *pOp1 = impImplicitIorI4Cast(op1, TYP_I_IMPL, fUnsigned); type = TYP_I_IMPL; } else { // byref - [native] int => gives a byref - assert(genActualType(op1->TypeGet()) == TYP_BYREF && genActualTypeIsIntOrI(op2->TypeGet())); + assert(op1->TypeIs(TYP_BYREF) && genActualTypeIsIntOrI(op2)); -#ifdef TARGET_64BIT - if ((genActualType(op2->TypeGet()) != TYP_I_IMPL)) - { - // insert an explicit upcast - op2 = *pOp2 = gtNewCastNode(TYP_I_IMPL, op2, fUnsigned, fUnsigned ? TYP_U_IMPL : TYP_I_IMPL); - } -#endif // TARGET_64BIT + // Insert an explicit upcast if needed. + op2 = *pOp2 = impImplicitIorI4Cast(op2, TYP_I_IMPL, fUnsigned); type = TYP_BYREF; } } - else if ((oper == GT_ADD) && - (genActualType(op1->TypeGet()) == TYP_BYREF || genActualType(op2->TypeGet()) == TYP_BYREF)) + else if ((oper == GT_ADD) && (op1->TypeIs(TYP_BYREF) || op2->TypeIs(TYP_BYREF))) { // byref + [native] int => gives a byref // (or) // [native] int + byref => gives a byref - // only one can be a byref : byref op byref not allowed - assert(genActualType(op1->TypeGet()) != TYP_BYREF || genActualType(op2->TypeGet()) != TYP_BYREF); - assert(genActualTypeIsIntOrI(op1->TypeGet()) || genActualTypeIsIntOrI(op2->TypeGet())); + // Only one can be a byref : byref op byref not allowed. + assert(op1->TypeIs(TYP_BYREF) || op2->TypeIs(TYP_BYREF)); + assert(genActualTypeIsIntOrI(op1) || genActualTypeIsIntOrI(op2)); -#ifdef TARGET_64BIT - if (genActualType(op2->TypeGet()) == TYP_BYREF) - { - if (genActualType(op1->TypeGet()) != TYP_I_IMPL) - { - // insert an explicit upcast - op1 = *pOp1 = gtNewCastNode(TYP_I_IMPL, op1, fUnsigned, fUnsigned ? TYP_U_IMPL : TYP_I_IMPL); - } - } - else if (genActualType(op2->TypeGet()) != TYP_I_IMPL) - { - // insert an explicit upcast - op2 = *pOp2 = gtNewCastNode(TYP_I_IMPL, op2, fUnsigned, fUnsigned ? TYP_U_IMPL : TYP_I_IMPL); - } -#endif // TARGET_64BIT + // Insert explicit upcasts if needed. + op1 = *pOp1 = impImplicitIorI4Cast(op1, TYP_I_IMPL, fUnsigned); + op2 = *pOp2 = impImplicitIorI4Cast(op2, TYP_I_IMPL, fUnsigned); type = TYP_BYREF; } #ifdef TARGET_64BIT - else if (genActualType(op1->TypeGet()) == TYP_I_IMPL || genActualType(op2->TypeGet()) == TYP_I_IMPL) + else if ((genActualType(op1) == TYP_I_IMPL) || (genActualType(op2) == TYP_I_IMPL)) { - assert(!varTypeIsFloating(op1->gtType) && !varTypeIsFloating(op2->gtType)); + assert(!varTypeIsFloating(op1) && !varTypeIsFloating(op2)); // int + long => gives long // long + int => gives long - // we get this because in the IL the long isn't Int64, it's just IntPtr - - if (genActualType(op1->TypeGet()) != TYP_I_IMPL) + // We get this because in the IL the long isn't Int64, it's just IntPtr. + // Insert explicit upcasts if needed. + if (genActualType(op1) != TYP_I_IMPL) { // insert an explicit upcast - op1 = *pOp1 = gtNewCastNode(TYP_I_IMPL, op1, fUnsigned, fUnsigned ? TYP_U_IMPL : TYP_I_IMPL); + op1 = *pOp1 = gtNewCastNode(TYP_I_IMPL, op1, fUnsigned, TYP_I_IMPL); } - else if (genActualType(op2->TypeGet()) != TYP_I_IMPL) + else if (genActualType(op2) != TYP_I_IMPL) { // insert an explicit upcast - op2 = *pOp2 = gtNewCastNode(TYP_I_IMPL, op2, fUnsigned, fUnsigned ? TYP_U_IMPL : TYP_I_IMPL); + op2 = *pOp2 = gtNewCastNode(TYP_I_IMPL, op2, fUnsigned, TYP_I_IMPL); } type = TYP_I_IMPL; } #else // 32-bit TARGET - else if (genActualType(op1->TypeGet()) == TYP_LONG || genActualType(op2->TypeGet()) == TYP_LONG) + else if ((genActualType(op1) == TYP_LONG) || (genActualType(op2) == TYP_LONG)) { - assert(!varTypeIsFloating(op1->gtType) && !varTypeIsFloating(op2->gtType)); + assert(!varTypeIsFloating(op1) && !varTypeIsFloating(op2)); // int + long => gives long // long + int => gives long @@ -5610,23 +5592,22 @@ var_types Compiler::impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTr else { // int + int => gives an int - assert(genActualType(op1->TypeGet()) != TYP_BYREF && genActualType(op2->TypeGet()) != TYP_BYREF); + assert((genActualType(op1) != TYP_BYREF) && (genActualType(op2) != TYP_BYREF)); + assert((genActualType(op1) == genActualType(op2)) || (varTypeIsFloating(op1) && varTypeIsFloating(op2))); - assert(genActualType(op1->TypeGet()) == genActualType(op2->TypeGet()) || - (varTypeIsFloating(op1->gtType) && varTypeIsFloating(op2->gtType))); + type = genActualType(op1); - type = genActualType(op1->gtType); - - // If both operands are TYP_FLOAT, then leave it as TYP_FLOAT. - // Otherwise, turn floats into doubles - if ((type == TYP_FLOAT) && (genActualType(op2->gtType) != TYP_FLOAT)) + // If both operands are TYP_FLOAT, then leave it as TYP_FLOAT. Otherwise, turn floats into doubles + if (varTypeIsFloating(type) && (op2->TypeGet() != type)) { - assert(genActualType(op2->gtType) == TYP_DOUBLE); + op1 = *pOp1 = impImplicitR4orR8Cast(op1, TYP_DOUBLE); + op2 = *pOp2 = impImplicitR4orR8Cast(op2, TYP_DOUBLE); + type = TYP_DOUBLE; } } - assert(type == TYP_BYREF || type == TYP_DOUBLE || type == TYP_FLOAT || type == TYP_LONG || type == TYP_INT); + assert(TypeIs(type, TYP_BYREF, TYP_DOUBLE, TYP_FLOAT, TYP_LONG, TYP_INT)); return type; } @@ -6808,23 +6789,15 @@ void Compiler::impImportBlockCode(BasicBlock* block) tiRetVal = se.seTypeInfo; } -#ifdef FEATURE_SIMD - if (varTypeIsSIMD(lclTyp) && (lclTyp != op1->TypeGet())) + // TODO-ADDR: delete once all RET_EXPRs are typed properly. + if (varTypeIsSIMD(lclTyp)) { - assert(op1->TypeGet() == TYP_STRUCT); op1->gtType = lclTyp; } -#endif // FEATURE_SIMD + // Note this will downcast TYP_I_IMPL into a 32-bit Int on 64 bit (for x86 JIT compatibility). op1 = impImplicitIorI4Cast(op1, lclTyp); - -#ifdef TARGET_64BIT - // Downcast the TYP_I_IMPL into a 32-bit Int for x86 JIT compatibility - if (varTypeIsI(op1->TypeGet()) && (genActualType(lclTyp) == TYP_INT)) - { - op1 = gtNewCastNode(TYP_INT, op1, false, TYP_INT); - } -#endif // TARGET_64BIT + op1 = impImplicitR4orR8Cast(op1, lclTyp); // We had better assign it a value of the correct type assertImp( @@ -6835,21 +6808,11 @@ void Compiler::impImportBlockCode(BasicBlock* block) (varTypeIsFloating(lclTyp) && varTypeIsFloating(op1->TypeGet())) || ((genActualType(lclTyp) == TYP_BYREF) && genActualType(op1->TypeGet()) == TYP_REF)); - /* If op1 is "&var" then its type is the transient "*" and it can - be used either as TYP_BYREF or TYP_I_IMPL */ - - if (op1->IsLocalAddrExpr() != nullptr) + // If op1 is "&var" then its type is the transient "*" and it can + // be used either as BYREF or TYP_I_IMPL. + if (genActualType(lclTyp) == TYP_I_IMPL) { - assertImp(genActualType(lclTyp) == TYP_I_IMPL || lclTyp == TYP_BYREF); - - /* When "&var" is created, we assume it is a byref. If it is - being assigned to a TYP_I_IMPL var, change the type to - prevent unnecessary GC info */ - - if (genActualType(lclTyp) == TYP_I_IMPL) - { - op1->gtType = TYP_I_IMPL; - } + impBashVarAddrsToI(op1); } // If this is a local and the local is a ref type, see @@ -6898,15 +6861,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) impSpillSideEffects(false, CHECK_SPILL_ALL DEBUGARG("Spill before store to pinned local")); } - // We can generate an assignment to a TYP_FLOAT from a TYP_DOUBLE - // We insert a cast to the dest 'op2' type - // - if ((op1->TypeGet() != op2->TypeGet()) && varTypeIsFloating(op1->gtType) && - varTypeIsFloating(op2->gtType)) - { - op1 = gtNewCastNode(op2->TypeGet(), op1, false, op2->TypeGet()); - } - if (varTypeIsStruct(lclTyp)) { op1 = impAssignStruct(op2, op1, CHECK_SPILL_ALL); @@ -7169,25 +7123,11 @@ void Compiler::impImportBlockCode(BasicBlock* block) GenTree* index = impPopStack().val; GenTree* arr = impPopStack().val; -#ifdef TARGET_64BIT // The CLI Spec allows an array to be indexed by either an int32 or a native int. // The array helper takes a native int for array length. // So if we have an int, explicitly extend it to be a native int. - if (genActualType(index->TypeGet()) != TYP_I_IMPL) - { - if (index->IsIntegralConst()) - { - index->gtType = TYP_I_IMPL; - } - else - { - bool isUnsigned = false; - index = gtNewCastNode(TYP_I_IMPL, index, isUnsigned, TYP_I_IMPL); - } - } -#endif // TARGET_64BIT - - op1 = gtNewHelperCallNode(CORINFO_HELP_LDELEMA_REF, TYP_BYREF, arr, index, type); + index = impImplicitIorI4Cast(index, TYP_I_IMPL); + op1 = gtNewHelperCallNode(CORINFO_HELP_LDELEMA_REF, TYP_BYREF, arr, index, type); impPushOnStack(op1, tiRetVal); } break; @@ -7305,27 +7245,14 @@ void Compiler::impImportBlockCode(BasicBlock* block) } } + // Else call a helper function to do the assignment impPopStack(3); -// Else call a helper function to do the assignment -#ifdef TARGET_64BIT // The CLI Spec allows an array to be indexed by either an int32 or a native int. // The array helper takes a native int for array length. // So if we have an int, explicitly extend it to be a native int. - if (genActualType(index->TypeGet()) != TYP_I_IMPL) - { - if (index->IsIntegralConst()) - { - index->gtType = TYP_I_IMPL; - } - else - { - bool isUnsigned = false; - index = gtNewCastNode(TYP_I_IMPL, index, isUnsigned, TYP_I_IMPL); - } - } -#endif // TARGET_64BIT - op1 = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST, TYP_VOID, array, index, value); + index = impImplicitIorI4Cast(index, TYP_I_IMPL); + op1 = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST, TYP_VOID, array, index, value); goto SPILL_APPEND; } @@ -7524,22 +7451,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) } } - // We can generate a TYP_FLOAT operation that has a TYP_DOUBLE operand - // - if (varTypeIsFloating(type) && varTypeIsFloating(op1->gtType) && varTypeIsFloating(op2->gtType)) - { - if (op1->TypeGet() != type) - { - // We insert a cast of op1 to 'type' - op1 = gtNewCastNode(type, op1, false, type); - } - if (op2->TypeGet() != type) - { - // We insert a cast of op2 to 'type' - op2 = gtNewCastNode(type, op2, false, type); - } - } - if (callNode) { /* These operators can later be transformed into 'GT_CALL' */ @@ -7809,15 +7720,13 @@ void Compiler::impImportBlockCode(BasicBlock* block) } #ifdef TARGET_64BIT - // TODO-Casts: create a helper that upcasts int32 -> native int when necessary. - // See also identical code in impGetByRefResultType and STSFLD import. - if (varTypeIsI(op1) && (genActualType(op2) == TYP_INT)) + if (varTypeIsI(op1) && genActualTypeIsInt(op2)) { - op2 = gtNewCastNode(TYP_I_IMPL, op2, uns, TYP_I_IMPL); + op2 = impImplicitIorI4Cast(op2, TYP_I_IMPL); } - else if (varTypeIsI(op2) && (genActualType(op1) == TYP_INT)) + else if (varTypeIsI(op2) && genActualTypeIsInt(op1)) { - op1 = gtNewCastNode(TYP_I_IMPL, op1, uns, TYP_I_IMPL); + op1 = impImplicitIorI4Cast(op1, TYP_I_IMPL); } #endif // TARGET_64BIT @@ -7909,19 +7818,19 @@ void Compiler::impImportBlockCode(BasicBlock* block) op1 = impPopStack().val; #ifdef TARGET_64BIT - if ((op1->TypeGet() == TYP_I_IMPL) && (genActualType(op2->TypeGet()) == TYP_INT)) + // TODO-Review: this differs in the extending behavior from plain relop import. Why? + if (op1->TypeIs(TYP_I_IMPL) && genActualTypeIsInt(op2)) { - op2 = gtNewCastNode(TYP_I_IMPL, op2, uns, uns ? TYP_U_IMPL : TYP_I_IMPL); + op2 = impImplicitIorI4Cast(op2, TYP_I_IMPL, uns); } - else if ((op2->TypeGet() == TYP_I_IMPL) && (genActualType(op1->TypeGet()) == TYP_INT)) + else if (op2->TypeIs(TYP_I_IMPL) && genActualTypeIsInt(op1)) { - op1 = gtNewCastNode(TYP_I_IMPL, op1, uns, uns ? TYP_U_IMPL : TYP_I_IMPL); + op1 = impImplicitIorI4Cast(op1, TYP_I_IMPL, uns); } #endif // TARGET_64BIT - assertImp(genActualType(op1->TypeGet()) == genActualType(op2->TypeGet()) || - (varTypeIsI(op1->TypeGet()) && varTypeIsI(op2->TypeGet())) || - (varTypeIsFloating(op1->gtType) && varTypeIsFloating(op2->gtType))); + assertImp((genActualType(op1) == genActualType(op2)) || (varTypeIsI(op1) && varTypeIsI(op2)) || + (varTypeIsFloating(op1) && varTypeIsFloating(op2))); if (opts.OptimizationEnabled() && (block->bbJumpDest == block->bbNext)) { @@ -7949,33 +7858,16 @@ void Compiler::impImportBlockCode(BasicBlock* block) break; } - // We can generate an compare of different sized floating point op1 and op2 - // We insert a cast + // We can generate an compare of different sized floating point op1 and op2. + // We insert a cast to double. // - if (varTypeIsFloating(op1->TypeGet())) + if ((op1->TypeGet() != op2->TypeGet()) && varTypeIsFloating(op1)) { - if (op1->TypeGet() != op2->TypeGet()) - { - assert(varTypeIsFloating(op2->TypeGet())); - - // say op1=double, op2=float. To avoid loss of precision - // while comparing, op2 is converted to double and double - // comparison is done. - if (op1->TypeGet() == TYP_DOUBLE) - { - // We insert a cast of op2 to TYP_DOUBLE - op2 = gtNewCastNode(TYP_DOUBLE, op2, false, TYP_DOUBLE); - } - else if (op2->TypeGet() == TYP_DOUBLE) - { - // We insert a cast of op1 to TYP_DOUBLE - op1 = gtNewCastNode(TYP_DOUBLE, op1, false, TYP_DOUBLE); - } - } + op1 = impImplicitR4orR8Cast(op1, TYP_DOUBLE); + op2 = impImplicitR4orR8Cast(op2, TYP_DOUBLE); } - /* Create and append the operator */ - + // Create and append the operator. op1 = gtNewOperNode(oper, TYP_INT, op1, op2); if (uns) @@ -7987,7 +7879,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) { op1->gtFlags |= GTF_RELOP_NAN_UN; } - goto COND_JUMP; case CEE_SWITCH: @@ -8446,31 +8337,11 @@ void Compiler::impImportBlockCode(BasicBlock* block) impBashVarAddrsToI(op1, op2); + // Allow a downcast of op2 from TYP_I_IMPL into a 32-bit Int for x86 JIT compatibility. + // Allow an upcast of op2 from a 32-bit Int into TYP_I_IMPL for x86 JIT compatibility. + op2 = impImplicitIorI4Cast(op2, lclTyp); op2 = impImplicitR4orR8Cast(op2, lclTyp); -#ifdef TARGET_64BIT - // Automatic upcast for a GT_CNS_INT into TYP_I_IMPL - if ((op2->OperGet() == GT_CNS_INT) && varTypeIsI(lclTyp) && !varTypeIsI(op2->gtType)) - { - op2->gtType = TYP_I_IMPL; - } - else - { - // Allow a downcast of op2 from TYP_I_IMPL into a 32-bit Int for x86 JIT compatibility - // - if (varTypeIsI(op2->gtType) && (genActualType(lclTyp) == TYP_INT)) - { - op2 = gtNewCastNode(TYP_INT, op2, false, TYP_INT); - } - // Allow an upcast of op2 from a 32-bit Int into TYP_I_IMPL for x86 JIT compatibility - // - if (varTypeIsI(lclTyp) && (genActualType(op2->gtType) == TYP_INT)) - { - op2 = gtNewCastNode(TYP_I_IMPL, op2, false, TYP_I_IMPL); - } - } -#endif // TARGET_64BIT - if (opcode == CEE_STIND_REF) { // STIND_REF can be used to store TYP_INT, TYP_I_IMPL, TYP_REF, or TYP_BYREF @@ -9724,32 +9595,10 @@ void Compiler::impImportBlockCode(BasicBlock* block) op2 = gtNewCastNode(op1->TypeGet(), op2, false, op1->TypeGet()); } #endif - -#ifdef TARGET_64BIT - // Automatic upcast for a GT_CNS_INT into TYP_I_IMPL - if ((op2->OperGet() == GT_CNS_INT) && varTypeIsI(lclTyp) && !varTypeIsI(op2->gtType)) - { - op2->gtType = TYP_I_IMPL; - } - else - { - // Allow a downcast of op2 from TYP_I_IMPL into a 32-bit Int for x86 JIT compatibility - // - if (varTypeIsI(op2->gtType) && (genActualType(lclTyp) == TYP_INT)) - { - op2 = gtNewCastNode(TYP_INT, op2, false, TYP_INT); - } - // Allow an upcast of op2 from a 32-bit Int into TYP_I_IMPL for x86 JIT compatibility - // - if (varTypeIsI(lclTyp) && (genActualType(op2->gtType) == TYP_INT)) - { - op2 = gtNewCastNode(TYP_I_IMPL, op2, false, TYP_I_IMPL); - } - } -#endif - - // Insert an implicit FLOAT<->DOUBLE cast if needed. - op2 = impImplicitR4orR8Cast(op2, op1->TypeGet()); + // Allow a downcast of op2 from TYP_I_IMPL into a 32-bit Int for x86 JIT compatibility. + // Allow an upcast of op2 from a 32-bit Int into TYP_I_IMPL for x86 JIT compatibility. + op2 = impImplicitIorI4Cast(op2, lclTyp); + op2 = impImplicitR4orR8Cast(op2, lclTyp); op1 = gtNewAssignNode(op1, op2); } @@ -9802,24 +9651,11 @@ void Compiler::impImportBlockCode(BasicBlock* block) /* Form the arglist: array class handle, size */ op2 = impPopStack().val; - assertImp(genActualTypeIsIntOrI(op2->gtType)); + assertImp(genActualTypeIsIntOrI(op2)); -#ifdef TARGET_64BIT // The array helper takes a native int for array length. // So if we have an int, explicitly extend it to be a native int. - if (genActualType(op2->TypeGet()) != TYP_I_IMPL) - { - if (op2->IsIntegralConst()) - { - op2->gtType = TYP_I_IMPL; - } - else - { - bool isUnsigned = false; - op2 = gtNewCastNode(TYP_I_IMPL, op2, isUnsigned, TYP_I_IMPL); - } - } -#endif // TARGET_64BIT + op2 = impImplicitIorI4Cast(op2, TYP_I_IMPL); #ifdef FEATURE_READYTORUN if (opts.IsReadyToRun()) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 3fddff3e16331..5cce6eef25c27 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -2693,17 +2693,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, // Element access index = indexClone; - -#ifdef TARGET_64BIT - if (index->OperGet() == GT_CNS_INT) - { - index->gtType = TYP_I_IMPL; - } - else - { - index = gtNewCastNode(TYP_I_IMPL, index, true, TYP_I_IMPL); - } -#endif + index = impImplicitIorI4Cast(index, TYP_I_IMPL, /* zeroExtend */ true); if (elemSize != 1) { @@ -3597,10 +3587,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, // TODO-Cleanup: We should support this on 32-bit but it requires decomposition work impPopStack(); - if (op1->TypeGet() != TYP_DOUBLE) - { - op1 = gtNewCastNode(TYP_DOUBLE, op1, false, TYP_DOUBLE); - } + op1 = impImplicitR4orR8Cast(op1, TYP_DOUBLE); retNode = gtNewBitCastNode(TYP_LONG, op1); } #endif @@ -3660,10 +3647,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, } else { - if (op1->TypeGet() != TYP_FLOAT) - { - op1 = gtNewCastNode(TYP_FLOAT, op1, false, TYP_FLOAT); - } + op1 = impImplicitR4orR8Cast(op1, TYP_FLOAT); retNode = gtNewBitCastNode(TYP_INT, op1); } break; @@ -4195,16 +4179,8 @@ void Compiler::impPopCallArgs(CORINFO_SIG_INFO* sig, GenTreeCall* call) } else { - // insert implied casts (from float to double or double to float) - if ((jitSigType == TYP_DOUBLE) && argNode->TypeIs(TYP_FLOAT)) - { - argNode = gtNewCastNode(TYP_DOUBLE, argNode, false, TYP_DOUBLE); - } - else if ((jitSigType == TYP_FLOAT) && argNode->TypeIs(TYP_DOUBLE)) - { - argNode = gtNewCastNode(TYP_FLOAT, argNode, false, TYP_FLOAT); - } - + // Insert implied casts (from float to double or double to float). + argNode = impImplicitR4orR8Cast(argNode, jitSigType); // insert any widening or narrowing casts for backwards compatibility argNode = impImplicitIorI4Cast(argNode, jitSigType); } @@ -6805,50 +6781,27 @@ GenTree* Compiler::impMathIntrinsic(CORINFO_METHOD_HANDLE method, if (!IsIntrinsicImplementedByUserCall(intrinsicName)) #endif { - CORINFO_CLASS_HANDLE tmpClass; - CORINFO_ARG_LIST_HANDLE arg; - var_types op1Type; - var_types op2Type; + CORINFO_ARG_LIST_HANDLE arg = sig->args; switch (sig->numArgs) { case 1: - op1 = impPopStack().val; - - arg = sig->args; - op1Type = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg, &tmpClass))); - - if (op1->TypeGet() != genActualType(op1Type)) - { - assert(varTypeIsFloating(op1)); - op1 = gtNewCastNode(callType, op1, false, callType); - } + assert(eeGetArgType(arg, sig) == callType); + op1 = impPopStack().val; + op1 = impImplicitR4orR8Cast(op1, callType); op1 = new (this, GT_INTRINSIC) GenTreeIntrinsic(genActualType(callType), op1, intrinsicName, method); break; case 2: + assert(eeGetArgType(arg, sig) == callType); + INDEBUG(arg = info.compCompHnd->getArgNext(arg)); + assert(eeGetArgType(arg, sig) == callType); + op2 = impPopStack().val; op1 = impPopStack().val; - - arg = sig->args; - op1Type = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg, &tmpClass))); - - if (op1->TypeGet() != genActualType(op1Type)) - { - assert(varTypeIsFloating(op1)); - op1 = gtNewCastNode(callType, op1, false, callType); - } - - arg = info.compCompHnd->getArgNext(arg); - op2Type = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg, &tmpClass))); - - if (op2->TypeGet() != genActualType(op2Type)) - { - assert(varTypeIsFloating(op2)); - op2 = gtNewCastNode(callType, op2, false, callType); - } - + op1 = impImplicitR4orR8Cast(op1, callType); + op2 = impImplicitR4orR8Cast(op2, callType); op1 = new (this, GT_INTRINSIC) GenTreeIntrinsic(genActualType(callType), op1, op2, intrinsicName, method); break; diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index c00f066ffefcb..35491ae70db9b 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -90,6 +90,7 @@ CONFIG_INTEGER(JitDumpTerseLsra, W("JitDumpTerseLsra"), 1) // Produce ters CONFIG_INTEGER(JitDumpToDebugger, W("JitDumpToDebugger"), 0) // Output JitDump output to the debugger CONFIG_INTEGER(JitDumpVerboseSsa, W("JitDumpVerboseSsa"), 0) // Produce especially verbose dump output for SSA CONFIG_INTEGER(JitDumpVerboseTrees, W("JitDumpVerboseTrees"), 0) // Enable more verbose tree dumps +CONFIG_INTEGER(JitDumpTreeIDs, W("JitDumpTreeIDs"), 1) // Print tree IDs in dumps CONFIG_INTEGER(JitEmitPrintRefRegs, W("JitEmitPrintRefRegs"), 0) CONFIG_INTEGER(JitEnableDevirtualization, W("JitEnableDevirtualization"), 1) // Enable devirtualization in importer CONFIG_INTEGER(JitEnableLateDevirtualization, W("JitEnableLateDevirtualization"), 1) // Enable devirtualization after