The affect of the ISA on clock rate and CPI is not simple. The amount of work needed to decode the instruction and perform the operation can vary among instructions. If more work (that can not be done in parallel) needs to be done to process an instruction, then either the pipeline must be made longer or the pipeline stages must be longer. Consider the following two examples.
First compare two ISAs that are identical except that one (B) uses a denser instruction encoding that would add 5% to the length of a decode stage in a classic five stage pipeline (compared to the less densely encoded ISA A). One choice for ISA B would be to lengthen all pipeline stages by 5% (i.e., expand all stages equally); this choice might simplify the partitioning of work when reusing an existing design for the other ISA and the extra time in non-decode stages need not be wasted — e.g., increasing cache associativity could use more time in cache access pipeline stages, the ALU might use a smaller and/or more energy efficient adder, relaxing timing margins in most of the design might increase yield. This choice would increase the cycle time by 5%. The effect on CPI would depend on how the extra cycle time was used; increasing cache associativity would tend to reduce misses and therefore CPI (fewer cycles waiting for memory), extra fetch time might be used to improve branch prediction (reducing CPI), and even the lengthening of cycle time itself will tend to reduce CPI (e.g., memory latency and bandwidth can be less tied to the processor clock frequency).
Another choice would be to rebalance the pipeline while keeping the same pipeline depth. In theory, this could reduce the cycle time cost down to 1%, but the work of processing an instruction is not friendly to arbitrary division; some timing inefficiency will be introduced and area/power costs will likely increase (e.g., the placement of pipeline stage edges can affect the amount of data that must be latched). This would ideally only increase cycle time by 1% and have no effect on CPI.
Another choice would be to completely rework the pipeline and increase its length. If the fetch and decode stages were increased to three stages to form a six stage pipeline. If the cycle time was kept constant, this would provide roughly extra 95% of a cycle for additional work. The extra time might be used to access a larger instruction cache, perform decode-time optimizations such as instruction fusion (requiring wider fetch and/or instruction buffering), or do other useful work. Increasing the pipeline depth would increase the branch misprediction cost, increasing CPI, but uses of the extra time such as a larger instruction cache would tend to reduce CPI. If the total work was kept constant, increasing the number of stages by 20% would increase the frequency by something less than 20%; however, such encounters the difficulty of arbitrarily dividing work.
(Yet another choice might be to precode instructions, moving some decode work to when the instruction cache is filled on a miss. The same in-memory capacity instruction cache would be physically larger, possibly increasing cycle time. Alternatively the physical cache size might be kept more-or-less constant, possibly even with similar typical capacity in the number of instructions; however, this would be difficult to acheive as the number of wordlines in an SRAM array wants to be a power of two. Since instruction cache misses are slow anyway and less common than instruction fetches, moving decode delay could be helpful even if only part of the delay was shifted and there was some inefficiency of work due to the division.)
Since a denser instruction encoding would effectively increase instruction cache size in terms of the number of instructions, this could decrease CPI by decreasing instruction cache misses.
For a second example, consider a RISC-like ISA and a similar ISA but with load-and-operate instructions. Since some of the instructions are more complex, it would be expected that decoding an instruction would require more work with implications similar to those in the previous example. (Adding load-and-operate instructions would also tend to increase code density.) Ignoring any extra work for instruction decoding, implementing load-op instructions by simply cracking such into a load µop and an operate µop would be problematic for the classic five stage pipeline: the operate µop would have to stall during the MEMory pipeline stage whereas a compiler might often be able to place an instruction independent of the load immediately after the load. If 36% of instructions in the evaluation are loads and half of those are replaced by load-op instructions and the compile can fill half of the slots after loads, using load-op instructions would add cycles equal to 9% of the instruction count (half of the loads (18% of instructions) would be converted to load-ops and half of those (9% of instructions) would have an extra unused cycle compared with the RISC. (The CPI would obvious look much worse since the number of instructions is reduced. A 9% increase in cycle count with only 82% of the instructions would give almost 33% higher CPI.)
More sophisticated pipeline control would allow an instruction immediately following a load-op to execute while waiting for the data from the load µop of the previous instruction, making this equivalent to the RISC design. However, the more sophisticated control would likely increase cycle time. (The original MIPS R2000 did not use interlocking in order to increase frequency; to do this while supporting load-op instructions might require a skewed pipeline where loads are started at what would be the execute stage and computations would be executed two stages later when loaded data would be available — this would require a separate functional unit for calculating addresses.)
A load-op instruction avoids using one register for a temporary, so such would slightly reduce register pressure and spill-fill overhead (instruction count). A load-op instruction would also provide limited instruction buffering which might hide a single cycle/instruction hiccup in the front-end, but more general buffering could be implemented independent of the ISA. If the critical paths/loops in the design happened not to be lengthened by more complex decode and more sophisticated pipeline control (i.e., cycle time was not increased), the free temporary register could give a slight performance advantage.
These two examples hint at some of the tradeoffs even for a simple short-pipeline scalar implementation. Increasing pipeline depth decreases efficiency; not only is latch overhead more-or-less constant but equally dividing work is more difficult with shorter pipeline stages and some work is not entirely independent (branch prediction removes the control dependency but is not completely accurate). Where a pipeline stage ends also influences area and power costs (e.g., how many bits need to be latched); increasing area will tend to increase communication latency, which tends to decrease exploitable parallelism.
Instruction decode complexity and work complexity will also impact the difficulty of increasing execution width. Fixed length instructions make parsing the instruction stream into individual instructions trivial at the cost of code density and/or instruction count. Easily determining the instruction length — such as the S/360's use of two bits in a fixed position to indicate which of three instruction lengths applied — can be a reasonable compromise. Caching instruction boundary determinations using one bit per instruction parcel (length unit) to indicate a whether a parcel is at the boundary or not can reduce the parsing latency for later parsings.
More variable execution latencies also increase the complexity of result forwarding. Operations which take only a little more time than a simple addition introduce the choice of increasing the cycle time to allow such to be done in a single cycle or performing them in two cycles (ignoring possibilities such as delivering partial results as they are needed — e.g., width pipelining/staggered ALU —, doing more work to produce a result faster, or cracking the operation into single-cycle µops). Increasing cycle time has obvious drawbacks, but increasing the latency of some operations increases complexity. In a two-wide 5-stage design, a two-cycle operation would not need to add a forwarding path if it used the load execution pipeline (both loads and such higher latency operations would take two cycles so no new forwarding paths would be required), but if such operations were expected to be common limiting them to single wide execution and only when a load is not being issued may be undesirable. Increasing the number of forwarding paths increases the difficulty of meeting high frequency targets.
The ISA does not determine the clock rate but influences the tradeoffs involved in achieving a given clock rate. With techniques such as cracking instructions into multiple µops, fusing instructions, idiom recognition (for special handling of special cases), and out-of-order execution an ISA can be translated dynamically to work better with design constraints but such translation is not free.