@@ -2733,3 +2733,158 @@ bool Compiler::fgLateCastExpansionForCall(BasicBlock** pBlock, Statement* stmt,
2733
2733
2734
2734
return true;
2735
2735
}
2736
+
2737
+ //------------------------------------------------------------------------------
2738
+ // fgExpandStackArrayAllocations : expand "new helpers" for stack arrays
2739
+ //
2740
+ // Returns:
2741
+ // PhaseStatus indicating what, if anything, was changed.
2742
+ //
2743
+ PhaseStatus Compiler::fgExpandStackArrayAllocations()
2744
+ {
2745
+ PhaseStatus result = PhaseStatus::MODIFIED_NOTHING;
2746
+
2747
+ if (!doesMethodHaveStackAllocatedArray())
2748
+ {
2749
+ // The method being compiled doesn't have any stack allocated arrays.
2750
+ return result;
2751
+ }
2752
+
2753
+ // Find allocation sites, and transform them into initializations of the
2754
+ // array method table and length, and replace the allocation call with
2755
+ // the address of the local array.
2756
+ //
2757
+ bool modified = false;
2758
+
2759
+ for (BasicBlock* const block : Blocks())
2760
+ {
2761
+ for (Statement* const stmt : block->Statements())
2762
+ {
2763
+ if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0)
2764
+ {
2765
+ continue;
2766
+ }
2767
+
2768
+ for (GenTree* const tree : stmt->TreeList())
2769
+ {
2770
+ if (!tree->IsCall())
2771
+ {
2772
+ continue;
2773
+ }
2774
+
2775
+ if (fgExpandStackArrayAllocation(block, stmt, tree->AsCall()))
2776
+ {
2777
+ // If we expand, we split the statement's tree
2778
+ // so will be done with this statment.
2779
+ //
2780
+ modified = true;
2781
+ break;
2782
+ }
2783
+ }
2784
+ }
2785
+ }
2786
+
2787
+ // we cant assert(modified) here as array allocation sites may
2788
+ // have been unreachable or dead-coded.
2789
+ //
2790
+ return modified ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
2791
+ }
2792
+
2793
+ //------------------------------------------------------------------------------
2794
+ // fgExpandStackArrayAllocation: expand new array helpers for stack allocated arrays
2795
+ //
2796
+ // Arguments:
2797
+ // block - block containing the helper call to expand
2798
+ // stmt - Statement containing the helper call
2799
+ // call - The helper call
2800
+ //
2801
+ // Returns:
2802
+ // true if a runtime lookup was found and expanded.
2803
+ //
2804
+ bool Compiler::fgExpandStackArrayAllocation(BasicBlock* block, Statement* stmt, GenTreeCall* call)
2805
+ {
2806
+ if (!call->IsHelperCall())
2807
+ {
2808
+ return false;
2809
+ }
2810
+
2811
+ const CorInfoHelpFunc helper = eeGetHelperNum(call->gtCallMethHnd);
2812
+ int lengthArgIndex = -1;
2813
+
2814
+ switch (helper)
2815
+ {
2816
+ case CORINFO_HELP_NEWARR_1_DIRECT:
2817
+ case CORINFO_HELP_NEWARR_1_VC:
2818
+ case CORINFO_HELP_NEWARR_1_OBJ:
2819
+ case CORINFO_HELP_NEWARR_1_ALIGN8:
2820
+ lengthArgIndex = 1;
2821
+ break;
2822
+
2823
+ case CORINFO_HELP_READYTORUN_NEWARR_1:
2824
+ lengthArgIndex = 0;
2825
+ break;
2826
+
2827
+ default:
2828
+ return false;
2829
+ }
2830
+
2831
+ // If this is a local array, the new helper will have an arg for the array's address
2832
+ //
2833
+ CallArg* const stackLocalAddressArg = call->gtArgs.FindWellKnownArg(WellKnownArg::StackArrayLocal);
2834
+
2835
+ if (stackLocalAddressArg == nullptr)
2836
+ {
2837
+ return false;
2838
+ }
2839
+
2840
+ JITDUMP("Expanding new array helper for stack allocated array at [%06d] in " FMT_BB ":\n", dspTreeID(call),
2841
+ block->bbNum);
2842
+ DISPTREE(call);
2843
+ JITDUMP("\n");
2844
+
2845
+ Statement* newStmt = nullptr;
2846
+ GenTree** callUse = nullptr;
2847
+ bool split = gtSplitTree(block, stmt, call, &newStmt, &callUse);
2848
+
2849
+ if (split)
2850
+ {
2851
+ while ((newStmt != nullptr) && (newStmt != stmt))
2852
+ {
2853
+ fgMorphStmtBlockOps(block, newStmt);
2854
+ newStmt = newStmt->GetNextStmt();
2855
+ }
2856
+ }
2857
+
2858
+ GenTree* const stackLocalAddress = stackLocalAddressArg->GetNode();
2859
+
2860
+ // Initialize the array method table pointer.
2861
+ //
2862
+ CORINFO_CLASS_HANDLE arrayHnd = (CORINFO_CLASS_HANDLE)call->compileTimeHelperArgumentHandle;
2863
+
2864
+ GenTree* const mt = gtNewIconEmbClsHndNode(arrayHnd);
2865
+ GenTree* const mtStore = gtNewStoreValueNode(TYP_I_IMPL, stackLocalAddress, mt);
2866
+ Statement* const mtStmt = fgNewStmtFromTree(mtStore);
2867
+
2868
+ fgInsertStmtBefore(block, stmt, mtStmt);
2869
+
2870
+ // Initialize the array length.
2871
+ //
2872
+ GenTree* const lengthArg = call->gtArgs.GetArgByIndex(lengthArgIndex)->GetNode();
2873
+ GenTree* const lengthArgInt = fgOptimizeCast(gtNewCastNode(TYP_INT, lengthArg, false, TYP_INT));
2874
+ GenTree* const lengthAddress = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(stackLocalAddress),
2875
+ gtNewIconNode(OFFSETOF__CORINFO_Array__length, TYP_I_IMPL));
2876
+ GenTree* const lengthStore = gtNewStoreValueNode(TYP_INT, lengthAddress, lengthArgInt);
2877
+ Statement* const lenStmt = fgNewStmtFromTree(lengthStore);
2878
+
2879
+ fgInsertStmtBefore(block, stmt, lenStmt);
2880
+
2881
+ // Replace call with local address
2882
+ //
2883
+ *callUse = gtCloneExpr(stackLocalAddress);
2884
+ DEBUG_DESTROY_NODE(call);
2885
+
2886
+ fgMorphStmtBlockOps(block, stmt);
2887
+ gtUpdateStmtSideEffects(stmt);
2888
+
2889
+ return true;
2890
+ }
0 commit comments