@@ -2789,6 +2789,14 @@ void FlowGraph::markSimdBlocks(std::map<std::string, G4_BB*>& labelMap, FuncInfo
2789
2789
// If all active simd lanes on entry to shader/kernel are
2790
2790
// active in a BB, that BB is NOT divergent; otherwise,
2791
2791
// it is divergent.
2792
+ //
2793
+ // Note that this does not require the number of all the
2794
+ // active simd lanes equals to the simd dispatch width!
2795
+ // For example, simd8 kernel might have 4 active lanes
2796
+ // on entry to the kernel, thus if any BB of the kernel
2797
+ // has less than 4 active lanes, it is divergent! As
2798
+ // matter of fact, the entry BB must not be divergent.
2799
+ //
2792
2800
// Note: this will be used to replace inSIMDCF gradually.
2793
2801
void FlowGraph::markDivergentBBs ()
2794
2802
{
@@ -2847,6 +2855,9 @@ void FlowGraph::markDivergentBBs()
2847
2855
LastJoinBBId = -1 ;
2848
2856
}
2849
2857
};
2858
+ auto isPriorToLastJoin = [&](G4_BB* aBB) ->bool {
2859
+ return (int )aBB->getId () < LastJoinBBId;
2860
+ };
2850
2861
2851
2862
if (BBs.empty ())
2852
2863
{
@@ -2899,12 +2910,76 @@ void FlowGraph::markDivergentBBs()
2899
2910
}
2900
2911
}
2901
2912
2913
+ // Check if the BB referred to by CurrIT needs to update lastJoin and do
2914
+ // updating if so. The IterEnd is the end iterator of current function
2915
+ // that CurrIT refers to.
2916
+ //
2917
+ // 1. update lastJoinBB if needed
2918
+ // 2. set up divergence for entry of subroutines if divergent
2919
+ //
2920
+ auto updateLastJoinForBB = [&](BB_LIST_ITER& CurrIT, BB_LIST_ITER& IterEnd) ->bool
2921
+ {
2922
+ G4_BB* aBB = *CurrIT;
2923
+ if (aBB->size () == 0 )
2924
+ {
2925
+ return false ;
2926
+ }
2927
+
2928
+ int old_lastJoinBBId = LastJoinBBId;
2929
+
2930
+ G4_INST* lastInst = aBB->back ();
2931
+ if ((lastInst->opcode () == G4_while ||
2932
+ (lastInst->opcode () == G4_goto && lastInst->asCFInst ()->isBackward ())) &&
2933
+ (!lastInst->asCFInst ()->isUniform () || aBB->isDivergent ()))
2934
+ {
2935
+ if (CurrIT != IterEnd) {
2936
+ auto NI = CurrIT;
2937
+ ++NI;
2938
+ G4_BB* joinBB = *NI;
2939
+ pushJoin (joinBB);
2940
+ }
2941
+ }
2942
+ else if (((lastInst->opcode () == G4_goto && !lastInst->asCFInst ()->isBackward ()) ||
2943
+ lastInst->opcode () == G4_break) &&
2944
+ (!lastInst->asCFInst ()->isUniform () || aBB->isDivergent ()))
2945
+ {
2946
+ // forward goto/break : the last Succ BB is our target BB
2947
+ // For break, it should be the BB right after while inst.
2948
+ G4_BB* joinBB = aBB->Succs .back ();
2949
+ pushJoin (joinBB);
2950
+ }
2951
+ else if (lastInst->opcode () == G4_if &&
2952
+ (!lastInst->asCFInst ()->isUniform () || aBB->isDivergent ()))
2953
+ {
2954
+ G4_Label* labelInst = lastInst->asCFInst ()->getUip ();
2955
+ G4_BB* joinBB = findLabelBB (CurrIT, IterEnd, labelInst->getLabel ());
2956
+ assert (joinBB && " ICE(vISA) : missing endif label!" );
2957
+ pushJoin (joinBB);
2958
+ }
2959
+ else if (lastInst->opcode () == G4_call || lastInst->opcode () == G4_pseudo_fcall)
2960
+ {
2961
+ // If this function is already in divergent branch, the callee
2962
+ // must be in a divergent branch!.
2963
+ if (aBB->isDivergent () || lastInst->getPredicate () != nullptr )
2964
+ {
2965
+ FuncInfo* calleeFunc = aBB->getCalleeInfo ();
2966
+ if (funcInfoIndex.count (calleeFunc))
2967
+ {
2968
+ int ix = funcInfoIndex[calleeFunc];
2969
+ allFuncs[ix].InvokedFromDivergentBB = true ;
2970
+ }
2971
+ }
2972
+ }
2973
+
2974
+ return old_lastJoinBBId != LastJoinBBId;
2975
+ };
2976
+
2902
2977
for (int i = 0 ; i < numFuncs; ++i)
2903
2978
{
2904
2979
// each function: [IT, IE)
2905
- BB_LIST_ITER& IT = allFuncs[i].StartI ;
2980
+ BB_LIST_ITER& IS = allFuncs[i].StartI ;
2906
2981
BB_LIST_ITER& IE = allFuncs[i].EndI ;
2907
- if (IT == IE)
2982
+ if (IS == IE)
2908
2983
{
2909
2984
// sanity check
2910
2985
continue ;
@@ -2913,7 +2988,7 @@ void FlowGraph::markDivergentBBs()
2913
2988
if (allFuncs[i].InvokedFromDivergentBB )
2914
2989
{
2915
2990
// subroutine's divergent on entry. Mark every BB as divergent
2916
- for (; IT != IE; ++IT)
2991
+ for (auto IT = IS ; IT != IE; ++IT)
2917
2992
{
2918
2993
G4_BB* BB = *IT;
2919
2994
@@ -2941,15 +3016,32 @@ void FlowGraph::markDivergentBBs()
2941
3016
}
2942
3017
2943
3018
LastJoinBBId = -1 ;
2944
- for (; IT != IE; ++IT)
3019
+ for (auto IT = IS ; IT != IE; ++IT)
2945
3020
{
2946
3021
G4_BB* BB = *IT;
2947
3022
2948
- // This handles cases in which BB has endif/while/join as well as others
2949
- // so we don't need to explicitly check whether BB has endif/while/join, etc.
3023
+ // join could be: explicit (join inst) or implicit (endif/while)
2950
3024
popJoinIfMatch (BB);
2951
3025
2952
3026
// Handle loop
3027
+ // Loop needs to be scanned twice in order to get an accurate marking.
3028
+ // For example,
3029
+ // L:
3030
+ // B1:
3031
+ // if (p0) goto B2
3032
+ // ...
3033
+ // else
3034
+ // if (p1) goto OUT
3035
+ // endif
3036
+ // B2:
3037
+ // (p2) goto L
3038
+ // B3:
3039
+ // OUT:
3040
+ //
3041
+ // We don't know whether B1 is divergent until the entire loop body has been
3042
+ // scanned, so that we know any out-of-loop gotos (goto out and goto L in this
3043
+ // case). This require scanning the loop twice.
3044
+ //
2953
3045
for (auto iter = BB->Preds .begin (), iterEnd = BB->Preds .end (); iter != iterEnd; ++iter)
2954
3046
{
2955
3047
G4_BB* predBB = *iter;
@@ -2965,9 +3057,17 @@ void FlowGraph::markDivergentBBs()
2965
3057
// not loop
2966
3058
continue ;
2967
3059
}
3060
+
3061
+ // If lastJoin is already after loop end, no need to scan loop twice
3062
+ // as all BBs in the loop must be divergent
3063
+ if (isPriorToLastJoin (predBB))
3064
+ {
3065
+ continue ;
3066
+ }
3067
+
2968
3068
BB_LIST_ITER LoopIterEnd = std::find (BBs.begin (), BBs.end (), predBB);
2969
3069
2970
- // joinBB is the BB right after backward-goto/while
3070
+ // joinBB of a loop is the BB right after backward-goto/while
2971
3071
BB_LIST_ITER loopJoinIter = LoopIterEnd;
2972
3072
++loopJoinIter;
2973
3073
if (loopJoinIter == BBs.end ())
@@ -2983,87 +3083,37 @@ void FlowGraph::markDivergentBBs()
2983
3083
}
2984
3084
continue ;
2985
3085
}
3086
+
3087
+ // If backward goto/while is divergent, update lastJoin with
3088
+ // loop's join BB. No need to pre-scan loop!
2986
3089
G4_BB* joinBB = *loopJoinIter;
3090
+ if (!bInst->asCFInst ()->isUniform () &&
3091
+ bInst->opcode () != G4_jmpi)
3092
+ {
3093
+ pushJoin (joinBB);
3094
+ continue ;
3095
+ }
2987
3096
2988
- // Scan loop to find any out-of-loop branch, set join if found
3097
+ // pre-scan loop to find any out-of-loop branch, set join if found
2989
3098
for (auto LoopIter = IT; LoopIter != LoopIterEnd; ++LoopIter)
2990
3099
{
2991
- G4_BB* BB1 = *LoopIter;
2992
- if (BB1->size () == 0 )
3100
+ if (updateLastJoinForBB (LoopIter, IE))
2993
3101
{
2994
- continue ;
2995
- }
2996
- G4_INST* tmpInst = BB1->back ();
2997
- if (tmpInst->opcode () == G4_break || tmpInst->opcode () == G4_goto)
2998
- { // Assume divergent. todo: going over loop twice to find if it's divergent.
2999
- G4_BB* newJoinBB = joinBB;
3000
- if (tmpInst->opcode () == G4_goto)
3102
+ if (isPriorToLastJoin (predBB))
3001
3103
{
3002
- G4_BB* targetBB = BB1->Succs .back ();
3003
- if (targetBB->getId () <= predBB->getId ())
3004
- {
3005
- continue ;
3006
- }
3007
- newJoinBB = targetBB;
3104
+ continue ;
3008
3105
}
3009
-
3010
- // Need to find a 1st join, the other joins will
3011
- // be examined within the outer loop.
3012
- pushJoin (newJoinBB);
3013
- break ;
3014
3106
}
3015
3107
}
3016
-
3017
- if (!bInst->asCFInst ()->isUniform () &&
3018
- bInst->opcode () != G4_jmpi)
3019
- {
3020
- pushJoin (joinBB);
3021
- }
3022
3108
}
3023
3109
3024
- if (( int )BB-> getId () < LastJoinBBId ) {
3110
+ if (isPriorToLastJoin (BB) ) {
3025
3111
BB->setDivergent (true );
3026
3112
// set InSIMDFlow as well, will merge these two fields gradually
3027
3113
BB->setInSimdFlow (true );
3028
3114
}
3029
3115
3030
- if (BB->size () == 0 )
3031
- {
3032
- continue ;
3033
- }
3034
-
3035
- G4_INST* lastInst = BB->back ();
3036
- if (((lastInst->opcode () == G4_goto && !lastInst->asCFInst ()->isBackward ()) ||
3037
- lastInst->opcode () == G4_break) &&
3038
- (!lastInst->asCFInst ()->isUniform () || BB->isDivergent ()))
3039
- {
3040
- // forward goto/break : the last Succ BB is our target BB
3041
- // For break, it should be the BB right after while inst.
3042
- G4_BB* joinBB = BB->Succs .back ();
3043
- pushJoin (joinBB);
3044
- }
3045
- else if (lastInst->opcode () == G4_if &&
3046
- (!lastInst->asCFInst ()->isUniform () || BB->isDivergent ()))
3047
- {
3048
- G4_Label* labelInst = lastInst->asCFInst ()->getUip ();
3049
- G4_BB* joinBB = findLabelBB (IT, IE, labelInst->getLabel ());
3050
- assert (joinBB && " ICE(vISA) : missing endif label!" );
3051
- pushJoin (joinBB);
3052
- }
3053
- else if (lastInst->opcode () == G4_call || lastInst->opcode () == G4_pseudo_fcall)
3054
- {
3055
- // If this function is already in divergent branch, the callee
3056
- // must be in a divergent branch!.
3057
- if (BB->isDivergent () || lastInst->getPredicate () != nullptr )
3058
- {
3059
- FuncInfo* calleeFunc = BB->getCalleeInfo ();
3060
- if (funcInfoIndex.count (calleeFunc))
3061
- {
3062
- int ix = funcInfoIndex[calleeFunc];
3063
- allFuncs[ix].InvokedFromDivergentBB = true ;
3064
- }
3065
- }
3066
- }
3116
+ (void )updateLastJoinForBB (IT, IE);
3067
3117
}
3068
3118
}
3069
3119
return ;
0 commit comments