summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichelle McDaniel <adiaaida@gmail.com>2016-07-21 06:41:33 -0700
committerGitHub <noreply@github.com>2016-07-21 06:41:33 -0700
commit92eeb0ef418b5c2aa08350a73b813c515c993ff6 (patch)
treef2950cb77b179d69c70aa4d7b5220df599dd92b3
parentd1697c6f8b6e6d1f06b4d734fabd3b328e1dc724 (diff)
parent243e7c4f661d5ad0217c9e743c391a0df43bb6a0 (diff)
downloadcoreclr-92eeb0ef418b5c2aa08350a73b813c515c993ff6.tar.gz
coreclr-92eeb0ef418b5c2aa08350a73b813c515c993ff6.tar.bz2
coreclr-92eeb0ef418b5c2aa08350a73b813c515c993ff6.zip
Merge pull request #6219 from adiaaida/compareLongs
Fix silent bad codegen in signed comparison
-rwxr-xr-xsrc/jit/codegen.h3
-rw-r--r--src/jit/codegenlinear.h1
-rwxr-xr-xsrc/jit/codegenxarch.cpp458
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.cs46
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.csproj40
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6238/app.config27
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6238/project.json45
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.cs46
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.csproj40
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6239/app.config27
-rw-r--r--tests/src/JIT/Regression/JitBlue/GitHub_6239/project.json45
11 files changed, 657 insertions, 121 deletions
diff --git a/src/jit/codegen.h b/src/jit/codegen.h
index ce08d9fa65..70f21c6010 100755
--- a/src/jit/codegen.h
+++ b/src/jit/codegen.h
@@ -103,8 +103,7 @@ private:
static void genJumpKindsForTree(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
#if !defined(_TARGET_64BIT_)
- static void genJumpKindsForTreeLongHi(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
- static void genJumpKindsForTreeLongLo(GenTreePtr cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
+ static void genJumpKindsForTreeLongHi(GenTreePtr cmpTree, emitJumpKind jmpKind[2]);
#endif //!defined(_TARGET_64BIT_)
static bool genShouldRoundFP();
diff --git a/src/jit/codegenlinear.h b/src/jit/codegenlinear.h
index 6ffccbf593..2fbb8d004c 100644
--- a/src/jit/codegenlinear.h
+++ b/src/jit/codegenlinear.h
@@ -49,6 +49,7 @@
#if !defined(_TARGET_64BIT_)
void genCompareLong(GenTreePtr treeNode);
+ void genJTrueLong(GenTreePtr treeNode);
#endif
#ifdef FEATURE_SIMD
diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp
index fedee032e4..5fea9fc583 100755
--- a/src/jit/codegenxarch.cpp
+++ b/src/jit/codegenxarch.cpp
@@ -2457,7 +2457,18 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
// X86 Long comparison
else if (varTypeIsLong(op1Type))
{
- genCompareLong(treeNode);
+ // When not materializing the result in a register, the compare logic is generated
+ // when we generate the GT_JTRUE.
+ if (treeNode->gtRegNum != REG_NA)
+ {
+ genCompareLong(treeNode);
+ }
+ else
+ {
+ // We generate the compare when we generate the GT_JTRUE, but we need to consume
+ // the operands now.
+ genConsumeOperands(treeNode->AsOp());
+ }
}
#endif // !defined(_TARGET_64BIT_)
else
@@ -2470,44 +2481,55 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
case GT_JTRUE:
{
GenTree *cmp = treeNode->gtOp.gtOp1;
+
assert(cmp->OperIsCompare());
assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
- // Get the "kind" and type of the comparison. Note that whether it is an unsigned cmp
- // is governed by a flag NOT by the inherent type of the node
- // TODO-XArch-CQ: Check if we can use the currently set flags.
- emitJumpKind jumpKind[2];
- bool branchToTrueLabel[2];
- genJumpKindsForTree(cmp, jumpKind, branchToTrueLabel);
-
- BasicBlock* skipLabel = nullptr;
- if (jumpKind[0] != EJ_NONE)
+#if !defined(_TARGET_64BIT_)
+ // For long compares, we emit special logic
+ if (varTypeIsLong(cmp->gtGetOp1()))
+ {
+ genJTrueLong(cmp);
+ }
+ else
+#endif
{
- BasicBlock *jmpTarget;
- if (branchToTrueLabel[0])
+ // Get the "kind" and type of the comparison. Note that whether it is an unsigned cmp
+ // is governed by a flag NOT by the inherent type of the node
+ // TODO-XArch-CQ: Check if we can use the currently set flags.
+ emitJumpKind jumpKind[2];
+ bool branchToTrueLabel[2];
+ genJumpKindsForTree(cmp, jumpKind, branchToTrueLabel);
+
+ BasicBlock* skipLabel = nullptr;
+ if (jumpKind[0] != EJ_NONE)
{
- jmpTarget = compiler->compCurBB->bbJumpDest;
+ BasicBlock *jmpTarget;
+ if (branchToTrueLabel[0])
+ {
+ jmpTarget = compiler->compCurBB->bbJumpDest;
+ }
+ else
+ {
+ // This case arises only for ordered GT_EQ right now
+ assert((cmp->gtOper == GT_EQ) && ((cmp->gtFlags & GTF_RELOP_NAN_UN) == 0));
+ skipLabel = genCreateTempLabel();
+ jmpTarget = skipLabel;
+ }
+
+ inst_JMP(jumpKind[0], jmpTarget);
}
- else
+
+ if (jumpKind[1] != EJ_NONE)
{
- // This case arises only for ordered GT_EQ right now
- assert((cmp->gtOper == GT_EQ) && ((cmp->gtFlags & GTF_RELOP_NAN_UN) == 0));
- skipLabel = genCreateTempLabel();
- jmpTarget = skipLabel;
+ // the second conditional branch always has to be to the true label
+ assert(branchToTrueLabel[1]);
+ inst_JMP(jumpKind[1], compiler->compCurBB->bbJumpDest);
}
- inst_JMP(jumpKind[0], jmpTarget);
+ if (skipLabel != nullptr)
+ genDefineTempLabel(skipLabel);
}
-
- if (jumpKind[1] != EJ_NONE)
- {
- // the second conditional branch always has to be to the true label
- assert(branchToTrueLabel[1]);
- inst_JMP(jumpKind[1], compiler->compCurBB->bbJumpDest);
- }
-
- if (skipLabel != nullptr)
- genDefineTempLabel(skipLabel);
}
break;
@@ -6771,7 +6793,8 @@ void CodeGen::genJumpKindsForTree(GenTreePtr cmpTree,
//------------------------------------------------------------------------
// genJumpKindsForTreeLongHi: Generate the jump types for compare
// operators of the high parts of a compare with long type operands
-// on x86
+// on x86 for the case where rel-op result needs to be materialized into a
+// register.
//
// Arguments:
// cmpTree - The GT_CMP node
@@ -6781,38 +6804,50 @@ void CodeGen::genJumpKindsForTree(GenTreePtr cmpTree,
// Return Value:
// None.
//
-void CodeGen::genJumpKindsForTreeLongHi(GenTreePtr cmpTree,
- emitJumpKind jmpKind[2],
- bool jmpToTrueLabel[2])
+void CodeGen::genJumpKindsForTreeLongHi(GenTreePtr cmpTree,
+ emitJumpKind jmpKind[2])
{
- jmpToTrueLabel[0] = true;
- jmpToTrueLabel[1] = true;
-
assert(cmpTree->OperIsCompare());
+ CompareKind compareKind = ((cmpTree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
- bool isUnsigned = (cmpTree->gtFlags & GTF_UNSIGNED) != 0;
-
- // For comparison of longs on x86, GT_LT, GT_LE, GT_GT, and GT_GE need two jump cases, since
- // only if the hi operators are equal will we fall through.
switch (cmpTree->gtOper)
{
case GT_LT:
case GT_LE:
+ if (compareKind == CK_SIGNED)
+ {
+ jmpKind[0] = EJ_jl;
+ jmpKind[1] = EJ_jg;
+ }
+ else
+ {
+ jmpKind[0] = EJ_jb;
+ jmpKind[1] = EJ_ja;
+ }
+ break;
+
case GT_GT:
case GT_GE:
- if (isUnsigned)
+ if (compareKind == CK_SIGNED)
{
- jmpKind[0] = EJ_ja;
+ jmpKind[0] = EJ_jg;
+ jmpKind[1] = EJ_jl;
}
else
{
- jmpKind[0] = EJ_jg;
+ jmpKind[0] = EJ_ja;
+ jmpKind[1] = EJ_jb;
}
+ break;
+
+ case GT_EQ:
+ // GT_EQ will not jump to the true label if the hi parts are equal
+ jmpKind[0] = EJ_NONE;
jmpKind[1] = EJ_jne;
break;
-
+
case GT_NE:
- case GT_EQ:
+ // GT_NE will always jump to the true label if the high parts are not equal
jmpKind[0] = EJ_jne;
jmpKind[1] = EJ_NONE;
break;
@@ -6823,32 +6858,8 @@ void CodeGen::genJumpKindsForTreeLongHi(GenTreePtr cmpTree,
}
//------------------------------------------------------------------------
-// genJumpKindsForTreeLongLo: Generate the jump types for compare
-// operators of the low parts of a compare with long type operands
-// on x86
-//
-// Arguments:
-// cmpTree - The GT_CMP node
-// jmpKind - Return array of jump kinds
-// jmpToTrueLabel - Return array of if the jump is going to true label
-//
-// Return Value:
-// None.
-//
-void CodeGen::genJumpKindsForTreeLongLo(GenTreePtr cmpTree,
- emitJumpKind jmpKind[2],
- bool jmpToTrueLabel[2])
-{
- jmpToTrueLabel[0] = true;
- jmpToTrueLabel[1] = true;
-
- assert(cmpTree->OperIsCompare());
- jmpKind[0] = genJumpKindForOper(cmpTree->gtOper, CK_UNSIGNED);
- jmpKind[1] = EJ_NONE;
-}
-
-//------------------------------------------------------------------------
-// genCompareLong: Generate code for comparing two longs on x86
+// genCompareLong: Generate code for comparing two longs on x86 when the result of the compare
+// is manifested in a register.
//
// Arguments:
// treeNode - the compare tree
@@ -6858,7 +6869,8 @@ void CodeGen::genJumpKindsForTreeLongLo(GenTreePtr cmpTree,
// Comments:
// For long compares, we need to compare the high parts of operands first, then the low parts.
// If the high compare is false, we do not need to compare the low parts. For less than and
-// greater than, if the high compare is true, we can assume the entire compare is true.
+// greater than, if the high compare is true, we can assume the entire compare is true. For
+// compares that are realized in a register, we will generate:
//
// Opcode x86 equivalent Comment
// ------ -------------- -------
@@ -6872,43 +6884,78 @@ void CodeGen::genJumpKindsForTreeLongLo(GenTreePtr cmpTree,
// cmp loOp1,loOp2
// label: setne
//
-// GT_LT cmp hiOp1,hiOp2 If hiOp1 is greater than hiOp2, the entire compare
-// ja label is false. If hiOp1 is less than hiOp2, the entire
-// jne label compare is true.
-// cmp loOp1,loOp2
+// GT_LT; unsigned cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne label correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
// label: setb
//
-// GT_LE cmp hiOp1,hiOp2 If hiOp1 is greater than hiOp2, the entire compare
-// ja label is false. If hiOp1 is less than hiOp2, the entire
-// jne label compare is true.
-// cmp loOp1,loOp2
+// GT_LE; unsigned cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne label correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
// label: setbe
//
-// GT_GT cmp hiOp1,hiOp2 If hiOp1 is greater than hiOp2, the entire compare
-// ja label is true. If hiOp1 is less than hiOp2, the entire
-// jne label compare is false.
-// cmp loOp1,loOp2
+// GT_GT; unsigned cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne label correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
// label: seta
//
-// GT_GE cmp hiOp1,hiOp2 If hiOp1 is greater than hiOp2, the entire compare
-// ja label is true. If hiOp1 is less than hiOp2, the entire
-// jne label compare is false.
-// cmp loOp1,loOp2
+// GT_GE; unsigned cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne label correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
// label: setae
//
+// For signed long comparisons, we need additional labels, as we need to use signed conditions on the
+// "set" instruction:
+//
+// GT_LT; signed cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne labelHi correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
+// setb Unsigned set for lo compare
+// jmp labelFinal
+// labelHi: setl Signed set for high compare
+// labelFinal:
+//
+// GT_LE; signed cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne labelHi correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
+// setbe Unsigend set for lo compare
+// jmp labelFinal
+// labelHi: setle Signed set for hi compare
+// labelFinal:
+//
+// GT_GT; signed cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne labelHi correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
+// seta Unsigned set for lo compare
+// jmp labelFinal
+// labelHi: setg Signed set for high compare
+// labelFinal
+//
+// GT_GE; signed cmp hiOp1,hiOp2 If hiOp1 is not equal to hiOp2, the flags are set
+// jne labelHi correctly and we do not need to check lo. Otherwise,
+// cmp loOp1,loOp2 we need to compare the lo halves
+// setae Unsigned set for lo compare
+// jmp labelFinal
+// labelHi: setge Signed set for hi compare
+// labelFinal:
+//
// TODO-X86-CQ: Check if hi or lo parts of op2 are 0 and change the compare to a test.
void CodeGen::genCompareLong(GenTreePtr treeNode)
{
assert(treeNode->OperIsCompare());
- GenTreeOp *tree = treeNode->AsOp();
+ GenTreeOp* tree = treeNode->AsOp();
GenTreePtr op1 = tree->gtOp1;
GenTreePtr op2 = tree->gtOp2;
+ assert(varTypeIsLong(op1->TypeGet()));
+ assert(varTypeIsLong(op2->TypeGet()));
+
+ regNumber targetReg = treeNode->gtRegNum;
+
genConsumeOperands(tree);
- assert(varTypeIsLong(op1->TypeGet()) && varTypeIsLong(op2->TypeGet()));
- regNumber targetReg = treeNode->gtRegNum;
+ assert(targetReg != REG_NA);
GenTreePtr loOp1 = op1->gtGetOp1();
GenTreePtr hiOp1 = op1->gtGetOp2();
@@ -6924,48 +6971,221 @@ void CodeGen::genCompareLong(GenTreePtr treeNode)
getEmitter()->emitInsBinary(ins, cmpAttr, hiOp1, hiOp2);
// Generate the first jump for the high compare
- emitJumpKind jumpKind[2];
- bool branchToTrueLabel[2];
- genJumpKindsForTreeLongHi(tree, jumpKind, branchToTrueLabel);
-
- BasicBlock* label = genCreateTempLabel();
- inst_JMP(jumpKind[0], label);
+ CompareKind compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
+
+ BasicBlock* labelHi = genCreateTempLabel();
+ BasicBlock* labelFinal = genCreateTempLabel();
- // Generate the second jump for LE, LT, GT, and GE. We only do the lower compare if
- // the hi parts are equal
- if (jumpKind[1] != EJ_NONE)
+ if (compareKind == CK_SIGNED && (tree->gtOper != GT_NE && tree->gtOper != GT_EQ))
{
- assert(branchToTrueLabel[1]);
- inst_JMP(jumpKind[1], label);
- }
+ // If we are doing a signed comparison, we need to do a signed set if the high compare is true,
+ // but an unsigned set if we fall through to the low compare. If we have a GT_NE or GT_EQ, we do not
+ // need to worry about the sign of the comparison, so we can use the simplified case.
- // Now create compare for low parts
- ins = INS_cmp;
- cmpType = TYP_INT;
- cmpAttr = emitTypeSize(cmpType);
+ // We only have to check for equality for the hi comparison. If they are not equal, then the set will
+ // do the right thing. If they are equal, we have to check the lo halves.
+ inst_JMP(EJ_jne, labelHi);
- // Emit the comparison
- getEmitter()->emitInsBinary(ins, cmpAttr, loOp1, loOp2);
+ // Emit the comparison. Perform the set for the lo. Jump to labelFinal
+ getEmitter()->emitInsBinary(ins, cmpAttr, loOp1, loOp2);
- // Define the label for hi jump target here. If we have jumped here, we want to set
- // the target register based on the jump kind of the lower half (the actual compare
- // type). If we have fallen through, then we are doing a normal int compare for the
- // lower parts
+ // The low set must be unsigned
+ emitJumpKind jumpKindLo = genJumpKindForOper(tree->gtOper, CK_UNSIGNED);
- genDefineTempLabel(label);
- if (targetReg != REG_NA)
+ inst_SET(jumpKindLo, targetReg);
+ // Set the higher bytes to 0
+ inst_RV_RV(ins_Move_Extend(TYP_UBYTE, true), targetReg, targetReg, TYP_UBYTE, emitTypeSize(TYP_UBYTE));
+ genProduceReg(tree);
+
+ inst_JMP(EJ_jmp, labelFinal);
+
+ // Define the label for hi jump target here. If we have jumped here, we want to set
+ // the target register based on the jump kind of the actual compare type.
+
+ genDefineTempLabel(labelHi);
+ inst_SET(genJumpKindForOper(tree->gtOper, compareKind), targetReg);
+
+ // Set the higher bytes to 0
+ inst_RV_RV(ins_Move_Extend(TYP_UBYTE, true), targetReg, targetReg, TYP_UBYTE, emitTypeSize(TYP_UBYTE));
+ genProduceReg(tree);
+
+ genDefineTempLabel(labelFinal);
+ }
+ else
{
- emitJumpKind jumpKindLo[2];
- bool branchToTrueLabelLo[2];
+ // If the compare is unsigned, or if the sign doesn't change the set instruction, we can use
+ // the same set logic for both the hi and lo compare, so we don't need to jump to a high label,
+ // we can just jump to the set that the lo compare will use.
+
+ // We only have to check for equality for the hi comparison. If they are not equal, then the set will
+ // do the right thing. If they are equal, we have to check the lo halves.
+ inst_JMP(EJ_jne, labelFinal);
+
+ // Emit the comparison
+ getEmitter()->emitInsBinary(ins, cmpAttr, loOp1, loOp2);
+
+ // Define the label for hi jump target here. If we have jumped here, we want to set
+ // the target register based on the jump kind of the lower half (the actual compare
+ // type). If we have fallen through, then we are doing a normal int compare for the
+ // lower parts
+
+ genDefineTempLabel(labelFinal);
// The low set must be unsigned
- genJumpKindsForTreeLongLo(tree, jumpKindLo, branchToTrueLabelLo);
- inst_SET(jumpKindLo[0], targetReg);
+ emitJumpKind jumpKindLo = genJumpKindForOper(tree->gtOper, CK_UNSIGNED);
+ inst_SET(jumpKindLo, targetReg);
// Set the higher bytes to 0
inst_RV_RV(ins_Move_Extend(TYP_UBYTE, true), targetReg, targetReg, TYP_UBYTE, emitTypeSize(TYP_UBYTE));
genProduceReg(tree);
}
+
+}
+
+//------------------------------------------------------------------------
+// genJTrueLong: Generate code for comparing two longs on x86 for the case where the result
+// is not manifested in a register.
+//
+// Arguments:
+// treeNode - the compare tree
+//
+// Return Value:
+// None.
+// Comments:
+// For long compares, we need to compare the high parts of operands first, then the low parts.
+// We only have to do the low compare if the high parts of the operands are equal.
+//
+// In the case where the result of a rel-op is not realized in a register, we generate:
+//
+// Opcode x86 equivalent Comment
+// ------ -------------- -------
+//
+// GT_LT; unsigned cmp hiOp1,hiOp2
+// jb trueLabel
+// ja falseLabel
+// cmp loOp1,loOp2
+// jb trueLabel
+// falseLabel:
+//
+// GT_LE; unsigned cmp hiOp1,hiOp2
+// jb trueLabel
+// ja falseLabel
+// cmp loOp1,loOp2
+// jbe trueLabel
+// falseLabel:
+//
+// GT_GT; unsigned cmp hiOp1,hiOp2
+// ja trueLabel
+// jb falseLabel
+// cmp loOp1,loOp2
+// ja trueLabel
+// falseLabel:
+//
+// GT_GE; unsigned cmp hiOp1,hiOp2
+// ja trueLabel
+// jb falseLabel
+// cmp loOp1,loOp2
+// jae trueLabel
+// falseLabel:
+//
+// GT_LT; signed cmp hiOp1,hiOp2
+// jl trueLabel
+// jg falseLabel
+// cmp loOp1,loOp2
+// jb trueLabel
+// falseLabel:
+//
+// GT_LE; signed cmp hiOp1,hiOp2
+// jl trueLabel
+// jg falseLabel
+// cmp loOp1,loOp2
+// jbe trueLabel
+// falseLabel:
+//
+// GT_GT; signed cmp hiOp1,hiOp2
+// jg trueLabel
+// jl falseLabel
+// cmp loOp1,loOp2
+// ja trueLabel
+// falseLabel:
+//
+// GT_GE; signed cmp hiOp1,hiOp2
+// jg trueLabel
+// jl falseLabel
+// cmp loOp1,loOp2
+// jae trueLabel
+// falseLabel:
+//
+// GT_EQ; cmp hiOp1,hiOp2
+// jne falseLabel
+// cmp loOp1,loOp2
+// je trueLabel
+// falseLabel:
+//
+// GT_NE; cmp hiOp1,hiOp2
+// jne labelTrue
+// cmp loOp1,loOp2
+// jne trueLabel
+// falseLabel:
+//
+// TODO-X86-CQ: Check if hi or lo parts of op2 are 0 and change the compare to a test.
+void CodeGen::genJTrueLong(GenTreePtr treeNode)
+{
+ assert(treeNode->OperIsCompare());
+
+ GenTreeOp* tree = treeNode->AsOp();
+ GenTreePtr op1 = tree->gtOp1;
+ GenTreePtr op2 = tree->gtOp2;
+
+ assert(varTypeIsLong(op1->TypeGet()));
+ assert(varTypeIsLong(op2->TypeGet()));
+
+ regNumber targetReg = treeNode->gtRegNum;
+
+ assert(targetReg == REG_NA);
+
+ GenTreePtr loOp1 = op1->gtGetOp1();
+ GenTreePtr hiOp1 = op1->gtGetOp2();
+ GenTreePtr loOp2 = op2->gtGetOp1();
+ GenTreePtr hiOp2 = op2->gtGetOp2();
+
+ // Emit the compare instruction
+ getEmitter()->emitInsBinary(INS_cmp, EA_4BYTE, hiOp1, hiOp2);
+
+ // Generate the first jump for the high compare
+ CompareKind compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
+
+ // TODO-X86-CQ: If the next block is a BBJ_ALWAYS, we can set falseLabel = compiler->compCurBB->bbNext->bbJumpDest.
+ BasicBlock* falseLabel = genCreateTempLabel();
+
+ emitJumpKind jumpKindHi[2];
+
+ // Generate the jumps for the high compare
+ genJumpKindsForTreeLongHi(tree, jumpKindHi);
+
+ BasicBlock* trueLabel = compiler->compCurBB->bbJumpDest;
+
+ if (jumpKindHi[0] != EJ_NONE)
+ {
+ inst_JMP(jumpKindHi[0], trueLabel);
+ }
+
+ if (jumpKindHi[1] != EJ_NONE)
+ {
+ inst_JMP(jumpKindHi[1], falseLabel);
+ }
+
+ // The low jump must be unsigned
+ emitJumpKind jumpKindLo = genJumpKindForOper(tree->gtOper, CK_UNSIGNED);
+
+ // Emit the comparison and the jump to the trueLabel
+ getEmitter()->emitInsBinary(INS_cmp, EA_4BYTE, loOp1, loOp2);
+
+ inst_JMP(jumpKindLo, trueLabel);
+
+ // Generate falseLabel, which is the false path. We will jump here if the high compare is false
+ // or fall through if the low compare is false.
+ genDefineTempLabel(falseLabel);
}
#endif //!defined(_TARGET_64BIT_)
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.cs b/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.cs
new file mode 100644
index 0000000000..5f0c6b7f5b
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// This test tests our signed contained compare logic
+// We should generate a signed set for the high compare, and an unsigned
+// set for the low compare
+//
+
+using System;
+using System.Runtime.CompilerServices;
+
+class Program
+{
+ uint i;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static int Test(long a, long b)
+ {
+ if (a < b)
+ {
+ return 5;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ static int Main()
+ {
+ const int Pass = 100;
+ const int Fail = -1;
+
+ if (Test(-2L, 0L) == 5)
+ {
+ Console.WriteLine("Passed");
+ return Pass;
+ }
+ else
+ {
+ Console.WriteLine("Failed");
+ return Fail;
+ }
+ }
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.csproj
new file mode 100644
index 0000000000..933fc1077e
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6238/GitHub_6238.csproj
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>False</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="project.json" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <PropertyGroup>
+ <ProjectJson>project.json</ProjectJson>
+ <ProjectLockJson>project.lock.json</ProjectLockJson>
+ </PropertyGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+ </PropertyGroup>
+</Project>
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6238/app.config b/tests/src/JIT/Regression/JitBlue/GitHub_6238/app.config
new file mode 100644
index 0000000000..62803f5972
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6238/app.config
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.20.0" newVersion="4.0.20.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Text.Encoding" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6238/project.json b/tests/src/JIT/Regression/JitBlue/GitHub_6238/project.json
new file mode 100644
index 0000000000..ecf2e0894c
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6238/project.json
@@ -0,0 +1,45 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1-rc3-24117-00",
+ "System.Collections": "4.0.10",
+ "System.Collections.NonGeneric": "4.0.1-rc3-24117-00",
+ "System.Collections.Specialized": "4.0.1-rc3-24117-00",
+ "System.ComponentModel": "4.0.1-rc3-24117-00",
+ "System.Console": "4.0.0-rc3-24117-00",
+ "System.Diagnostics.Process": "4.1.0-rc3-24117-00",
+ "System.Globalization": "4.0.10",
+ "System.Globalization.Calendars": "4.0.0",
+ "System.IO": "4.0.10",
+ "System.IO.FileSystem": "4.0.1-rc3-24117-00",
+ "System.IO.FileSystem.Primitives": "4.0.0",
+ "System.Linq": "4.1.0-rc3-24117-00",
+ "System.Linq.Queryable": "4.0.1-rc3-24117-00",
+ "System.Reflection": "4.1.0-rc3-24117-00",
+ "System.Reflection.Primitives": "4.0.0",
+ "System.Runtime": "4.1.0-rc3-24117-00",
+ "System.Runtime.Extensions": "4.0.10",
+ "System.Runtime.Handles": "4.0.0",
+ "System.Runtime.InteropServices": "4.1.0-rc3-24117-00",
+ "System.Runtime.Loader": "4.0.0-rc3-24117-00",
+ "System.Text.Encoding": "4.0.10",
+ "System.Threading": "4.0.10",
+ "System.Threading.Thread": "4.0.0-rc3-24117-00",
+ "System.Threading.ThreadPool": "4.0.10-rc3-24117-00",
+ "System.Xml.ReaderWriter": "4.0.11-rc3-24117-00",
+ "System.Xml.XDocument": "4.0.11-rc3-24117-00",
+ "System.Xml.XmlDocument": "4.0.1-rc3-24117-00",
+ "System.Xml.XmlSerializer": "4.0.11-rc3-24117-00"
+ },
+ "frameworks": {
+ "dnxcore50": {}
+ },
+ "runtimes": {
+ "win7-x86": {},
+ "win7-x64": {},
+ "ubuntu.14.04-x64": {},
+ "osx.10.10-x64": {},
+ "centos.7-x64": {},
+ "rhel.7-x64": {},
+ "debian.8-x64": {}
+ }
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.cs b/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.cs
new file mode 100644
index 0000000000..3a57e4d594
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// This test tests our signed uncontained compare logic
+// We should generate a signed jump for the high compare, and an unsigned
+// jump for the low compare.
+//
+
+using System;
+using System.Runtime.CompilerServices;
+
+class Program
+{
+ uint i;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static int Test(long a, long b)
+ {
+ if (a < b)
+ {
+ return 5;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ static int Main()
+ {
+ const int Pass = 100;
+ const int Fail = -1;
+
+ if (Test(-2147483649L, -2147483648L) == 5)
+ {
+ Console.WriteLine("Passed");
+ return Pass;
+ }
+ else
+ {
+ Console.WriteLine("Failed");
+ return Fail;
+ }
+ }
+}
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.csproj
new file mode 100644
index 0000000000..cfb0d65b01
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6239/GitHub_6239.csproj
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType></DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildProjectName).cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="project.json" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <PropertyGroup>
+ <ProjectJson>project.json</ProjectJson>
+ <ProjectLockJson>project.lock.json</ProjectLockJson>
+ </PropertyGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
+ </PropertyGroup>
+</Project>
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6239/app.config b/tests/src/JIT/Regression/JitBlue/GitHub_6239/app.config
new file mode 100644
index 0000000000..62803f5972
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6239/app.config
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.20.0" newVersion="4.0.20.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Text.Encoding" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.IO" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.10.0" newVersion="4.0.10.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_6239/project.json b/tests/src/JIT/Regression/JitBlue/GitHub_6239/project.json
new file mode 100644
index 0000000000..ecf2e0894c
--- /dev/null
+++ b/tests/src/JIT/Regression/JitBlue/GitHub_6239/project.json
@@ -0,0 +1,45 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1-rc3-24117-00",
+ "System.Collections": "4.0.10",
+ "System.Collections.NonGeneric": "4.0.1-rc3-24117-00",
+ "System.Collections.Specialized": "4.0.1-rc3-24117-00",
+ "System.ComponentModel": "4.0.1-rc3-24117-00",
+ "System.Console": "4.0.0-rc3-24117-00",
+ "System.Diagnostics.Process": "4.1.0-rc3-24117-00",
+ "System.Globalization": "4.0.10",
+ "System.Globalization.Calendars": "4.0.0",
+ "System.IO": "4.0.10",
+ "System.IO.FileSystem": "4.0.1-rc3-24117-00",
+ "System.IO.FileSystem.Primitives": "4.0.0",
+ "System.Linq": "4.1.0-rc3-24117-00",
+ "System.Linq.Queryable": "4.0.1-rc3-24117-00",
+ "System.Reflection": "4.1.0-rc3-24117-00",
+ "System.Reflection.Primitives": "4.0.0",
+ "System.Runtime": "4.1.0-rc3-24117-00",
+ "System.Runtime.Extensions": "4.0.10",
+ "System.Runtime.Handles": "4.0.0",
+ "System.Runtime.InteropServices": "4.1.0-rc3-24117-00",
+ "System.Runtime.Loader": "4.0.0-rc3-24117-00",
+ "System.Text.Encoding": "4.0.10",
+ "System.Threading": "4.0.10",
+ "System.Threading.Thread": "4.0.0-rc3-24117-00",
+ "System.Threading.ThreadPool": "4.0.10-rc3-24117-00",
+ "System.Xml.ReaderWriter": "4.0.11-rc3-24117-00",
+ "System.Xml.XDocument": "4.0.11-rc3-24117-00",
+ "System.Xml.XmlDocument": "4.0.1-rc3-24117-00",
+ "System.Xml.XmlSerializer": "4.0.11-rc3-24117-00"
+ },
+ "frameworks": {
+ "dnxcore50": {}
+ },
+ "runtimes": {
+ "win7-x86": {},
+ "win7-x64": {},
+ "ubuntu.14.04-x64": {},
+ "osx.10.10-x64": {},
+ "centos.7-x64": {},
+ "rhel.7-x64": {},
+ "debian.8-x64": {}
+ }
+}