Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] JIT: Testing field-wise analysis #105162

Closed
wants to merge 72 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
1b0e3d3
initial prototype
hez2010 Jul 15, 2024
57b7e42
Morph ARR_LENGTH and INDEX_ADDR
hez2010 Jul 15, 2024
1b5b25e
Fix incorrect array length storage
hez2010 Jul 15, 2024
395b735
Use offset and correct type
hez2010 Jul 15, 2024
17de70b
handle reassignment
hez2010 Jul 15, 2024
5443c42
range check
hez2010 Jul 15, 2024
b2d07da
throw range check failure
hez2010 Jul 15, 2024
b5ae9e7
update comments
hez2010 Jul 15, 2024
87b29de
add metrics
hez2010 Jul 15, 2024
eeb681d
minor cleanup
hez2010 Jul 15, 2024
dee9f38
Introduce new temp and implement local address morphing
hez2010 Jul 16, 2024
94c103b
handle index out-of-range
hez2010 Jul 16, 2024
12b297b
Refactor to remove duplicates
hez2010 Jul 16, 2024
e0fa91e
Remove invalid asserts
hez2010 Jul 16, 2024
9e0a04f
make compiler happy
hez2010 Jul 16, 2024
ae822f8
Address review feedbacks
hez2010 Jul 16, 2024
a4588bb
Fix INDEX_ADDR and add Sub
hez2010 Jul 16, 2024
32b9e26
Support IsAddressLessThan and its friends
hez2010 Jul 16, 2024
39d1ad9
Fix assertions
hez2010 Jul 16, 2024
0df0d58
Merge remote-tracking branch 'origin/main' into value-array-stack-alloc
hez2010 Jul 16, 2024
9f408b2
Use new overload
hez2010 Jul 16, 2024
418a62b
JIT: Remove GTF_IND_INVARIANT and GTF_IND_NONFAULTING flags checking
jakobbotsch Jul 16, 2024
4572408
Remove old comment
jakobbotsch Jul 16, 2024
9255762
Expose jitconfig
hez2010 Jul 16, 2024
1af84b9
Remove another assert
jakobbotsch Jul 16, 2024
629c793
Count
jakobbotsch Jul 16, 2024
b578203
Try 2 at counting
jakobbotsch Jul 16, 2024
b4445f6
Introduce BBF_HAS_NEWARR
hez2010 Jul 16, 2024
af9c40e
Early exit on debug as well
hez2010 Jul 16, 2024
8b54f5a
Update computed flags
hez2010 Jul 16, 2024
cba4d2c
Merge remote-tracking branch 'jakobbotsch/indir-flags' into value-arr…
hez2010 Jul 17, 2024
b497fae
Merge remote-tracking branch 'origin/main' into value-array-stack-alloc
hez2010 Jul 17, 2024
6eca58d
Partially revert 39d1ad9
hez2010 Jul 17, 2024
49d8509
Reuse existing comma node
hez2010 Jul 17, 2024
4c6e359
Respect IsBoundsChecked
hez2010 Jul 17, 2024
4d84379
Check lowerbound too
hez2010 Jul 17, 2024
c0cad85
Fix assertion take 2
hez2010 Jul 18, 2024
d28553a
Remove redundant jit-ee calls
hez2010 Jul 18, 2024
f42e78f
Merge branch 'main' into value-array-stack-alloc
hez2010 Jul 18, 2024
c21c4f7
Fix assertion again
hez2010 Jul 18, 2024
18ec558
Check array length
hez2010 Jul 18, 2024
eadb4ad
Fix assertion in another way
hez2010 Jul 18, 2024
9d4021c
Unset the flag to avoid unnecessary assert
hez2010 Jul 18, 2024
1cba8c0
Merge branch 'main' into value-array-stack-alloc
hez2010 Jul 19, 2024
1fff53e
Add tests
hez2010 Jul 19, 2024
d521a94
sigh
hez2010 Jul 19, 2024
97ee2be
Support R2R/NativeAOT
hez2010 Jul 19, 2024
c66bdb8
Merge branch 'main' into value-array-stack-alloc
hez2010 Jul 19, 2024
5bcb786
Fix building
hez2010 Jul 19, 2024
a01562e
cleanup
hez2010 Jul 19, 2024
e728d4f
remove invalid assert
hez2010 Jul 19, 2024
d73c5c5
double align on 32bit platform
hez2010 Jul 19, 2024
c9fea23
Use correct alignment for align8
hez2010 Jul 19, 2024
772bee6
Fix intrinsic expansion
hez2010 Jul 20, 2024
499ac0b
Merge branch 'main' into value-array-stack-alloc
hez2010 Jul 20, 2024
3dbe8ac
Initial prototype
hez2010 Jul 18, 2024
9022078
handle delegates
hez2010 Jul 19, 2024
ada0890
handle escape through IND
hez2010 Jul 19, 2024
9f40866
Disable stackalloc for arrays and delegates
hez2010 Jul 20, 2024
bf58c6d
Track conditional field assignment
hez2010 Jul 20, 2024
1faa8d9
Refine field-wise analysis
hez2010 Jul 20, 2024
3b24b7a
Disable arrays and delegates
hez2010 Jul 20, 2024
b3dcc12
Remove invalid assert
hez2010 Jul 20, 2024
94966d1
Minor enhancement
hez2010 Jul 20, 2024
8f0ef52
Check type
hez2010 Jul 20, 2024
d3b8f57
rollback
hez2010 Jul 20, 2024
49e15bc
Refine analysis
hez2010 Jul 21, 2024
878faa6
Refine analysis
hez2010 Jul 21, 2024
6931aff
Fix format
hez2010 Jul 21, 2024
38ba808
Fully tracking stores
hez2010 Jul 21, 2024
08e8fb2
Full tracking leftovers
hez2010 Jul 21, 2024
66fc46b
More fixes
hez2010 Jul 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/jit/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ void BasicBlock::dspFlags() const
{BBF_HAS_IDX_LEN, "idxlen"},
{BBF_HAS_MD_IDX_LEN, "mdidxlen"},
{BBF_HAS_NEWOBJ, "newobj"},
{BBF_HAS_NEWARR, "newarr"},
{BBF_HAS_NULLCHECK, "nullcheck"},
{BBF_BACKWARD_JUMP, "bwd"},
{BBF_BACKWARD_JUMP_TARGET, "bwd-target"},
Expand Down
9 changes: 5 additions & 4 deletions src/coreclr/jit/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,13 +462,14 @@ enum BasicBlockFlags : uint64_t
BBF_NO_CSE_IN = MAKE_BBFLAG(38), // Block should kill off any incoming CSE
BBF_CAN_ADD_PRED = MAKE_BBFLAG(39), // Ok to add pred edge to this block, even when "safe" edge creation disabled
BBF_HAS_VALUE_PROFILE = MAKE_BBFLAG(40), // Block has a node that needs a value probing


BBF_HAS_NEWARR = MAKE_BBFLAG(41), // BB contains 'new' of an array type.
// The following are sets of flags.

// Flags to update when two blocks are compacted

BBF_COMPACT_UPD = BBF_GC_SAFE_POINT | BBF_NEEDS_GCPOLL | BBF_HAS_JMP | BBF_HAS_IDX_LEN | BBF_HAS_MD_IDX_LEN | BBF_BACKWARD_JUMP | \
BBF_HAS_NEWOBJ | BBF_HAS_NULLCHECK | BBF_HAS_MDARRAYREF | BBF_LOOP_HEAD,
BBF_HAS_NEWOBJ | BBF_HAS_NEWARR | BBF_HAS_NULLCHECK | BBF_HAS_MDARRAYREF | BBF_LOOP_HEAD,

// Flags a block should not have had before it is split.

Expand All @@ -486,15 +487,15 @@ enum BasicBlockFlags : uint64_t
// For example, the bottom block might or might not have BBF_HAS_NULLCHECK, but we assume it has BBF_HAS_NULLCHECK.
// TODO: Should BBF_RUN_RARELY be added to BBF_SPLIT_GAINED ?

BBF_SPLIT_GAINED = BBF_DONT_REMOVE | BBF_HAS_JMP | BBF_BACKWARD_JUMP | BBF_HAS_IDX_LEN | BBF_HAS_MD_IDX_LEN | BBF_PROF_WEIGHT | \
BBF_SPLIT_GAINED = BBF_DONT_REMOVE | BBF_HAS_JMP | BBF_BACKWARD_JUMP | BBF_HAS_IDX_LEN | BBF_HAS_MD_IDX_LEN | BBF_PROF_WEIGHT | BBF_HAS_NEWARR | \
BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END | BBF_HAS_NULLCHECK | BBF_HAS_HISTOGRAM_PROFILE | BBF_HAS_VALUE_PROFILE | BBF_HAS_MDARRAYREF | BBF_NEEDS_GCPOLL,

// Flags that must be propagated to a new block if code is copied from a block to a new block. These are flags that
// limit processing of a block if the code in question doesn't exist. This is conservative; we might not
// have actually copied one of these type of tree nodes, but if we only copy a portion of the block's statements,
// we don't know (unless we actually pay close attention during the copy).

BBF_COPY_PROPAGATE = BBF_HAS_NEWOBJ | BBF_HAS_NULLCHECK | BBF_HAS_IDX_LEN | BBF_HAS_MD_IDX_LEN | BBF_HAS_MDARRAYREF,
BBF_COPY_PROPAGATE = BBF_HAS_NEWOBJ | BBF_HAS_NEWARR | BBF_HAS_NULLCHECK | BBF_HAS_IDX_LEN | BBF_HAS_MD_IDX_LEN | BBF_HAS_MDARRAYREF,
};

FORCEINLINE
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/fgdiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,10 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
{
fprintf(fgxFile, "\n hot=\"true\"");
}
if (block->HasFlag(BBF_HAS_NEWARR))
{
fprintf(fgxFile, "\n callsNewArr=\"true\"");
}
if (block->HasFlag(BBF_HAS_NEWOBJ))
{
fprintf(fgxFile, "\n callsNew=\"true\"");
Expand Down
3 changes: 1 addition & 2 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -7496,12 +7496,11 @@ struct GenTreeArrAddr : GenTreeUnOp

public:
GenTreeArrAddr(GenTree* addr, var_types elemType, CORINFO_CLASS_HANDLE elemClassHandle, uint8_t firstElemOffset)
: GenTreeUnOp(GT_ARR_ADDR, TYP_BYREF, addr DEBUGARG(/* largeNode */ false))
: GenTreeUnOp(GT_ARR_ADDR, addr->TypeGet(), addr DEBUGARG(/* largeNode */ false))
, m_elemClassHandle(elemClassHandle)
, m_elemType(elemType)
, m_firstElemOffset(firstElemOffset)
{
assert(addr->TypeIs(TYP_BYREF));
assert(((elemType == TYP_STRUCT) && (elemClassHandle != NO_CLASS_HANDLE)) ||
(elemClassHandle == NO_CLASS_HANDLE));
}
Expand Down
16 changes: 15 additions & 1 deletion src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9790,11 +9790,25 @@ void Compiler::impImportBlockCode(BasicBlock* block)
op1->AsCall()->compileTimeHelperArgumentHandle = (CORINFO_GENERIC_HANDLE)resolvedToken.hClass;

// Remember that this function contains 'new' of an SD array.
block->SetFlags(BBF_HAS_NEWARR);
optMethodFlags |= OMF_HAS_NEWARRAY;

// We assign the newly allocated object (by a GT_CALL to newarr node)
// to a temp. Note that the pattern "temp = allocArr" is required
// by ObjectAllocator phase to be able to determine newarr nodes
// without exhaustive walk over all expressions.
lclNum = lvaGrabTemp(true DEBUGARG("NewArr temp"));

impStoreToTemp(lclNum, op1, CHECK_SPILL_NONE);

assert(lvaTable[lclNum].lvSingleDef == 0);
lvaTable[lclNum].lvSingleDef = 1;
JITDUMP("Marked V%02u as a single def local\n", lclNum);
lvaSetClass(lclNum, resolvedToken.hClass, true /* is Exact */);

/* Push the result of the call on the stack */

impPushOnStack(op1, tiRetVal);
impPushOnStack(gtNewLclvNode(lclNum, TYP_REF), tiRetVal);

callTyp = TYP_REF;
}
Expand Down
24 changes: 20 additions & 4 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2579,12 +2579,28 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
}

//
// We start by looking at the last statement, making sure it's a store, and
// that the target of the store is the array passed to InitializeArray.
// We start by looking at the last statement, making sure it's a store.
//
GenTree* arrayLocalStore = impLastStmt->GetRootNode();
if (!arrayLocalStore->OperIs(GT_STORE_LCL_VAR) || !arrayLocalNode->OperIs(GT_LCL_VAR) ||
(arrayLocalStore->AsLclVar()->GetLclNum() != arrayLocalNode->AsLclVar()->GetLclNum()))
if (arrayLocalStore->OperIs(GT_STORE_LCL_VAR) && arrayLocalNode->OperIs(GT_LCL_VAR))
{
// Make sure the target of the store is the array passed to InitializeArray.
if (arrayLocalStore->AsLclVar()->GetLclNum() != arrayLocalNode->AsLclVar()->GetLclNum())
{
// The array can be spilled to a temp for stack allocation.
// Try getting the actual store node from the previous statement.
if (arrayLocalStore->AsLclVar()->Data()->OperIs(GT_LCL_VAR) && impLastStmt->GetPrevStmt() != nullptr)
{
arrayLocalStore = impLastStmt->GetPrevStmt()->GetRootNode();
if (!arrayLocalStore->OperIs(GT_STORE_LCL_VAR) ||
arrayLocalStore->AsLclVar()->GetLclNum() != arrayLocalNode->AsLclVar()->GetLclNum())
{
return nullptr;
}
}
}
}
else
{
return nullptr;
}
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ CONFIG_STRING(JitObjectStackAllocationRange, W("JitObjectStackAllocationRange"))
RELEASE_CONFIG_INTEGER(JitObjectStackAllocation, W("JitObjectStackAllocation"), 1)
RELEASE_CONFIG_INTEGER(JitObjectStackAllocationRefClass, W("JitObjectStackAllocationRefClass"), 1)
RELEASE_CONFIG_INTEGER(JitObjectStackAllocationBoxedValueClass, W("JitObjectStackAllocationBoxedValueClass"), 1)
RELEASE_CONFIG_INTEGER(JitObjectStackAllocationArray, W("JitObjectStackAllocationArray"), 1)

RELEASE_CONFIG_INTEGER(JitEECallTimingInfo, W("JitEECallTimingInfo"), 0)

Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/jitmetadatalist.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ JITMETADATAMETRIC(NewRefClassHelperCalls, int, 0)
JITMETADATAMETRIC(StackAllocatedRefClasses, int, 0)
JITMETADATAMETRIC(NewBoxedValueClassHelperCalls, int, 0)
JITMETADATAMETRIC(StackAllocatedBoxedValueClasses, int, 0)
JITMETADATAMETRIC(NewArrayHelperCalls, int, 0)
JITMETADATAMETRIC(StackAllocatedArrays, int, 0)

#undef JITMETADATA
#undef JITMETADATAINFO
Expand Down
69 changes: 69 additions & 0 deletions src/coreclr/jit/lclmorph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,75 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
break;
}

case GT_INDEX_ADDR:
{
assert(TopValue(2).Node() == node);
assert(TopValue(1).Node() == node->gtGetOp1());
assert(TopValue(0).Node() == node->gtGetOp2());

if (node->gtGetOp2()->IsCnsIntOrI() && TopValue(1).IsAddress())
{
ssize_t offset = node->AsIndexAddr()->gtElemOffset +
node->gtGetOp2()->AsIntCon()->IconValue() * node->AsIndexAddr()->gtElemSize;

if (!node->AsIndexAddr()->IsBoundsChecked() ||
(static_cast<ssize_t>(node->AsIndexAddr()->gtElemOffset) <= offset &&
offset < static_cast<ssize_t>(m_compiler->lvaLclExactSize(TopValue(1).LclNum()))))
{
if (FitsIn<unsigned>(offset) &&
TopValue(2).AddOffset(TopValue(1), static_cast<unsigned>(offset)))
{
INDEBUG(TopValue(0).Consume());
PopValue();
PopValue();
break;
}
}
else
{
*use = m_compiler->gtNewOperNode(GT_COMMA, node->TypeGet(),
m_compiler->gtNewHelperCallNode(CORINFO_HELP_RNGCHKFAIL,
TYP_VOID),
m_compiler->gtNewIconNode(0, TYP_BYREF));
m_stmtModified = true;
INDEBUG(TopValue(0).Consume());
PopValue();
INDEBUG(TopValue(0).Consume());
PopValue();
break;
}
}

EscapeValue(TopValue(0), node);
PopValue();
EscapeValue(TopValue(0), node);
PopValue();
break;
}

case GT_ARR_LENGTH:
{
assert(TopValue(1).Node() == node);
assert(TopValue(0).Node() == node->gtGetOp1());

if (TopValue(0).IsAddress())
{
GenTree* gtLclFld =
m_compiler->gtNewLclFldNode(TopValue(0).LclNum(), TYP_INT,
TopValue(0).Offset() + OFFSETOF__CORINFO_Array__length);
SequenceLocal(gtLclFld->AsLclVarCommon());
*use = gtLclFld;
m_stmtModified = true;
INDEBUG(TopValue(0).Consume());
PopValue();
break;
}

EscapeValue(TopValue(0), node);
PopValue();
break;
}

default:
while (TopValue(0).Node() != node)
{
Expand Down
12 changes: 11 additions & 1 deletion src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8344,10 +8344,20 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
return tree;
}

#ifdef DEBUG
if ((tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED) != 0)
{
return tree;
}
#endif

/* If we created a comma-throw tree then we need to morph op1 */
if (fgIsCommaThrow(tree))
{
tree->AsOp()->gtOp1 = fgMorphTree(tree->AsOp()->gtOp1);
INDEBUG(if ((tree->AsOp()->gtOp1->gtDebugFlags & GTF_DEBUG_NODE_MORPHED) == 0))
{
tree->AsOp()->gtOp1 = fgMorphTree(tree->AsOp()->gtOp1);
}
fgMorphTreeDone(tree);
return tree;
}
Expand Down
Loading
Loading