Sh supports two styles of conditional execution, indicated by the SH_IF and SH_WHEN keyword sets. Both sets of keywords support the same semantics but have different execution models. The implementation of SH_IF tries to actually avoid the execution of the computation specified in the sequence of statements it guards. The implementation of SH_WHEN executes all operation sequences and then discards unneeded results. The first execution model results in multipass execution or branches and may have additional overhead, but should be used if the cost of executing the body is large or possibly non-terminating. The SH_WHEN construct should be used when the cost of the body is low.
Only SH_IF is currently implemented. We are planning to add support for SH_WHEN soon, but in the mean time you can make use of the cond() library function to perform conditional assignment.
The compiler will take the use of either conditional control construct as a (strong) hint only, and may choose to use the alternative execution model in some circumstances. For instance, if SH_IF is used around a very short body and the compiler determines that conditional assignment will always be cheaper than multipass execution, then conditional assignment will be used. On the other hand, if the body of an SH_WHEN includes a loop that cannot be unrolled (for which termination in a finite number of steps cannot be guaranteed) then it may be necessary to use true conditional execution. Sh will not use the conditional assignment model for operation sequences it cannot prove will terminate, even if SH_WHEN is specified. However, in all cases Sh will preserve the semantics of the program specified by the user.
Sh does not currently support a switch statement. Sh compilation targets currently operate primarily on floating-point values, where equality comparisons are not reliable and integer clamping is expensive, so a switch statement does not make much sense. One could imagine a switch-like statement with a set of intervals instead of exact values given, but this would not give much syntactic convenience over a list of SH_ELSEIF s, and would be unlikely to provide additional efficiency. However, an SH_SWITCH /SH_CASE keyword is reserved and may be provided in the future when/if integer support improves.
True conditional execution is controlled by the SH_IF , SH_ELSE , / SH_ELSEIF , and SH_ENDIF keywords. These keywords are used as in Listing ??. The SH_ELSE and SH_ELSEIF parts are optional. There can be as many SH_ELSEIF parts as necessary.
The value of the test argument is interpreted relative to the Sh rules for logical values: true corresponds to postive, non-zero values, false is anything zero or negative. This value must be a scalar. When doing comparisons on tuples, use the any or all library functions to collapes tuples of logical values to a single scalar.
/ The SH_WHEN construct has identical semantics and syntax to the SH_IF construct. However, its execution model is different: it uses conditional assignment, whereas SH_IF is implemented using as true conditional execution using multipass execution or branching, depending on the compilation target. Normally, all branches of a SH_WHEN construct are actually executed, but only one set of variable updates is ultimately performed and the results of the other sets of computations is discarded. This is more compatible with the SIMD mode of execution used by some GPUs, so can be executed in a single pass. For short conditional computations, it may actually be more efficient. However, care should be taken that the computations invoked by the bodies of SH_WHEN control constructs are small. The interpretation of the control value is the same as Sh_IF . Also, in an expression conditional assignment can also be expressed using the cond library function.
An example is given in Listing ??. The SH_OTHERWISEWHEN and SH_OTHERWISE parts are optional.
Note: This manual is available as a bound book from AK Peters, including better formatting, in-depth examples, and about 200 pages not available on-line.