[Mesa-dev] [PATCH 6/6] glsl: Generate IR for switch statements

Dan McCabe zen3d.linux at gmail.com
Fri Jun 24 17:11:17 PDT 2011


On 06/24/2011 01:17 PM, Dan McCabe wrote:
> On 06/20/2011 03:50 PM, Ian Romanick wrote:
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>
>> On 06/17/2011 05:43 PM, Dan McCabe wrote:
>>> Beware! Here be dragons!
>>>
>>>
>> I think this will generate the wrong code for:
>>
>>     for (i = 0; i<  10; i++) {
>>         switch (i) {
>>             default: continue;
>>         }
>>     }
>>
>> It seems like that will generate some approximation of:
>>
>>     for (i = 0; i<  10; i++) {
>>         do {
>>             continue;
>>             break;
>>         } while (true);
>>     }
>>
>> Right?  This is why I had originally tracked loops and switch-statements
>> in a single stack.  In this situation, you'd want to set a "do a
>> continue" flag in the switch-statement and emit a break (from the
>> switch).  Something like:
>>
>>
>>     for (i = 0; i<  10; i++) {
>>         bool do_cont = false;
>>
>>         do {
>>             do_cont = true;
>>             break;
>>             break;
>>         } while (true);
>>
>>         if (do_cont)
>>             continue;
>>     }
>>
>>
> Yikes! Looks like you tripped over one of those dragons :(.
>
> Using a do_cont variable (or similar device) feels kludgey to me. I've 
> been mulling this over for the last couple of days while I did other 
> things and I think the right way to do this might be to get rid of the 
> use of "loop" altogether.
>
> But the devil is in the details, which I haven't worked out yet. Going 
> back to the unified loop/switch stack might be needed, though.
>
> cheers, danm
>

All is not lost! (But you already knew that :)

One of the motivations of using the loop device is that it enabled the 
relatively unmodified infrastructure for break statements. But let's get 
rid of the break device and see where we go.

Without xlating switch stmts into loops, we can still retain the 
test_val_tmp and is_fallthru_tmp temporaries (in fact, we need to; 
nothing changes there since that is how case labels are managed).

However, the standard break processing no longer applies, since we are 
not in a loop (for the switch stmt in any event). If we introduce a bool 
temporary called is_break_tmp and initialize it to false, then when we 
encounter a break stmt, we set is_break_tmp to true. Now we must guard 
the case statement with both fallthru_var and is_break_var. If 
is_break_tmp was set, we simply clear is_fallthru_tmp right after all 
case tests to false.

Note that this approach does require maintaining a loop/switch stack as 
the code originally did so that we can tell if a break statement is 
associate with a loop or with a switch stmt. Only if the top of the 
stack indicates that switch is being processed will the above break 
processing be invoked.

Looking at a translation of my canonical example:

    switch (expr) {
    case c0:
    case c1:
          stmt0;
    case c2:
    case c3:
          stmt1;
          break;
    case c4:
    default:
          stmt2;
    }

We can translated this into:

    int test_val_tmp = expr;
    bool is_fallthru_tmp = false;
    bool is_break_tmp = false;

    if (test_val_tmp == c0) {
        is_fallthru_tmp = true;
    }
    if (test_val_tmp == c1) {
        is_fallthru_tmp = true;
    }
    if (is_break_tmp) {
        is_fallthru_tmp = false;
    }
    if (is_fallthru_tmp) {
        stmt0;
    }

    if (test_val_tmp == c2) {
        is_fallthru_tmp = true;
    }
    if (test_val_tmp == c3) {
        is_fallthru_tmp = true;
    }
    if (is_break_tmp) {
        is_fallthru_tmp = false;
    }
    if (is_fallthru_tmp) {
        stmt1;
        is_break_tmp = true; // break stmt
    }

    if (test_val_tmp == c4) {
        is_fallthru_tmp = true;
    }
    is_fallthru_tmp = true; // default
    if (is_break_tmp) {
        is_fallthru_tmp = false;
    }
    if (is_fallthru_tmp) {
        stmt2;
    }

Comparing this to what we did previously, the things that change in this 
code are:
1) no enclosing loop
2) create a bool is_break_tmp initialized to false
3) after all case labels and before each case statement list, clear 
is_fallthru_tmp when is_break_tmp
4) set is_break_tmp for each break statement

And maintain the loop/switch stack again as in the original code.

I'll get this cranked out on Monday and resubmit for review. If anyone 
has concerns or questions about what I'm doing here, please let me know.

cheers, danm

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20110624/6a77ffdd/attachment.htm>


More information about the mesa-dev mailing list