Fix to intermittent failure of jit test 200w1d-09_cpp_r.exe
authorsivarv <sivarv@microsoft.com>
Wed, 2 Mar 2016 18:26:17 +0000 (10:26 -0800)
committersivarv <sivarv@microsoft.com>
Wed, 2 Mar 2016 18:26:17 +0000 (10:26 -0800)
This is a long standing bug in xarch emitter that repros when a static field
access results in the following IR

lclvar =  GT_IND(GT_LEA(GT_CLS_VAR_ADDR, offset=200))

GT_CLAS_VAR_ADDR represents address of the static class object and
offset is used to access a field of a static class.

In this case codegen of GT_IND would call emitInsMov(treeNode= GT_IND)
emiInsMov is checking whether 'base' of addr is GT_CLS_VAR_ADDR and if
so is disregarding offset/indiex/scale fields within addr mode.  As a
result code generated is

lea      rdx, [reloc classVar[0xddc44ce8]]
movsd    xmm10, qword ptr [reloc classVar[0xddc44ce8]]

The bug is that emitInsMov() should be checking that oper of addr of GT_IND
is GT_CLS_VAR_ADDR. Same issue exists in GT_STOREIND case.  After the
fix the following code is generated

lea      rdx, [reloc classVar[0xdc5a4ce8]]
movsd    xmm10, qword ptr [rdx+200]

Why this bug repros intermittently?  fgMorphField() when morphing a static
field access obtains static's addr and checks to see whether its addr
can be encoded as pc-relative 32-bit offset.  If so then fgMorphField() will create
GT_CLS_VAR_ADDR to represent static's addr.  If static's addr cannot be
encoded pc-relative 32-bit offset then it will create long type icon to represent the
address.  Later long icon + offset is folded into a single long constant
and the test passes in this case.  The test fails whenver GT_CLS_VAR_ADDR +
offset materializes in IR which in turn depends on the distance between
jitted code address and the static's address. In most cases statics
were at a distance that cannot be encoded as pc-relative and hence works
correctly.  Hence the intermittent failure of this test.

src/jit/emitxarch.cpp

index 4ca70e34ab172fa6a07ce66c27c5676f81f736ff..15af9aa8481161fa244854ca0a2d0f1c7ba67e47 100644 (file)
@@ -2569,9 +2569,9 @@ void emitter::emitInsMov(instruction ins, emitAttr attr, GenTree* node)
         {
             GenTreeIndir* mem = node->AsIndir();
             
-            if (mem->HasBase() && mem->Base()->OperGet() == GT_CLS_VAR_ADDR)
+            if (mem->Addr()->OperGet() == GT_CLS_VAR_ADDR)
             {
-                emitIns_R_C(ins, attr, node->gtRegNum, mem->Base()->gtClsVar.gtClsVarHnd, 0);
+                emitIns_R_C(ins, attr, node->gtRegNum, mem->Addr()->gtClsVar.gtClsVarHnd, 0);
                 return;
             }
             else if (mem->Addr()->OperGet() == GT_LCL_VAR_ADDR)
@@ -2586,7 +2586,6 @@ void emitter::emitInsMov(instruction ins, emitAttr attr, GenTree* node)
                 GenTreePtr addr = mem->Addr();
 
                 assert (addr->OperIsAddrMode() ||
-                        addr->gtOper == GT_CLS_VAR_ADDR ||
                         (addr->IsCnsIntOrI() && addr->isContained()) ||
                         !addr->isContained());
                 size_t offset = mem->Offset();
@@ -2618,15 +2617,15 @@ void emitter::emitInsMov(instruction ins, emitAttr attr, GenTree* node)
             size_t offset = mem->Offset();
             GenTree* data = node->gtOp.gtOp2;
 
-            if ((memBase != nullptr) && (memBase->OperGet() == GT_CLS_VAR_ADDR))
+            if (mem->Addr()->OperGet() == GT_CLS_VAR_ADDR)
             {
                 if (data->isContained())
                 {
-                    emitIns_C_I(ins, attr, memBase->gtClsVar.gtClsVarHnd, 0, (int) data->AsIntConCommon()->IconValue());
+                    emitIns_C_I(ins, attr, mem->Addr()->gtClsVar.gtClsVarHnd, 0, (int) data->AsIntConCommon()->IconValue());
                 }
                 else
                 {
-                    emitIns_C_R(ins, attr, memBase->gtClsVar.gtClsVarHnd, data->gtRegNum, 0);
+                    emitIns_C_R(ins, attr, mem->Addr()->gtClsVar.gtClsVarHnd, data->gtRegNum, 0);
                 }
                 return;
             }