Introduction to Optimization Local Value Numbering

Similar documents
Local Optimization: Value Numbering The Desert Island Optimization. Comp 412 COMP 412 FALL Chapter 8 in EaC2e. target code

Compiler Passes. Optimization. The Role of the Optimizer. Optimizations. The Optimizer (or Middle End) Traditional Three-pass Compiler

Middle End. Code Improvement (or Optimization) Analyzes IR and rewrites (or transforms) IR Primary goal is to reduce running time of the compiled code

Introduction to Optimization. CS434 Compiler Construction Joel Jones Department of Computer Science University of Alabama

Calvin Lin The University of Texas at Austin

Loop Optimizations. Outline. Loop Invariant Code Motion. Induction Variables. Loop Invariant Code Motion. Loop Invariant Code Motion

Lecture 3 Local Optimizations, Intro to SSA

Instruction Scheduling Beyond Basic Blocks Extended Basic Blocks, Superblock Cloning, & Traces, with a quick introduction to Dominators.

Code Shape Comp 412 COMP 412 FALL Chapters 4, 5, 6 & 7 in EaC2e. source code. IR IR target. code. Front End Optimizer Back End

Data Structures and Algorithms in Compiler Optimization. Comp314 Lecture Dave Peixotto

CS 406/534 Compiler Construction Putting It All Together

Intermediate Representations

CS293S Redundancy Removal. Yufei Ding

Instruction Selection: Preliminaries. Comp 412

The Software Stack: From Assembly Language to Machine Code

Combining Optimizations: Sparse Conditional Constant Propagation

Parsing. Note by Baris Aktemur: Our slides are adapted from Cooper and Torczon s slides that they prepared for COMP 412 at Rice.

Goals of Program Optimization (1 of 2)

Induction Variable Identification (cont)

Code Shape II Expressions & Assignment

Intermediate Representations Part II

Introduction to Optimization, Instruction Selection and Scheduling, and Register Allocation

Parsing II Top-down parsing. Comp 412

Local Register Allocation (critical content for Lab 2) Comp 412

Compiler Optimizations. Chapter 8, Section 8.5 Chapter 9, Section 9.1.7

A Bad Name. CS 2210: Optimization. Register Allocation. Optimization. Reaching Definitions. Dataflow Analyses 4/10/2013

Computing Inside The Parser Syntax-Directed Translation. Comp 412 COMP 412 FALL Chapter 4 in EaC2e. source code. IR IR target.

Welcome to COMP 512. COMP 512 Rice University Spring 2015

Intermediate Representations

Compiler Optimizations. Chapter 8, Section 8.5 Chapter 9, Section 9.1.7

Implementing Control Flow Constructs Comp 412

Just-In-Time Compilers & Runtime Optimizers

Compiler Optimization Techniques

Why Global Dataflow Analysis?

Intermediate representation

CSE 501 Midterm Exam: Sketch of Some Plausible Solutions Winter 1997

Procedure and Function Calls, Part II. Comp 412 COMP 412 FALL Chapter 6 in EaC2e. target code. source code Front End Optimizer Back End

Intermediate Representations. Reading & Topics. Intermediate Representations CS2210

CS5363 Final Review. cs5363 1

Register Allocation. Note by Baris Aktemur: Our slides are adapted from Cooper and Torczon s slides that they prepared for COMP 412 at Rice.

Redundant Computation Elimination Optimizations. Redundancy Elimination. Value Numbering CS2210

Global Register Allocation via Graph Coloring

Building a Parser Part III

Lab 3, Tutorial 1 Comp 412

Handling Assignment Comp 412

Compiler Design. Fall Control-Flow Analysis. Prof. Pedro C. Diniz

Tour of common optimizations

Introduction to Code Optimization. Lecture 36: Local Optimization. Basic Blocks. Basic-Block Example

Generating Code for Assignment Statements back to work. Comp 412 COMP 412 FALL Chapters 4, 6 & 7 in EaC2e. source code. IR IR target.

Loop Invariant Code Motion. Background: ud- and du-chains. Upward Exposed Uses. Identifying Loop Invariant Code. Last Time Control flow analysis

Syntax Analysis, III Comp 412

Languages and Compiler Design II IR Code Optimization

Loop Invariant Code Mo0on

Syntax Analysis, III Comp 412

Syntax Analysis, VII One more LR(1) example, plus some more stuff. Comp 412 COMP 412 FALL Chapter 3 in EaC2e. target code.

The View from 35,000 Feet

CSC D70: Compiler Optimization

Lazy Code Motion. Comp 512 Spring 2011

Intermediate Representation (IR)

Code Optimization. Code Optimization

CS415 Compilers. Intermediate Represeation & Code Generation

Calvin Lin The University of Texas at Austin

Copyright 2003, Keith D. Cooper, Ken Kennedy & Linda Torczon, all rights reserved. Students enrolled in Comp 412 at Rice University have explicit

Computing Inside The Parser Syntax-Directed Translation. Comp 412

CSC D70: Compiler Optimization Register Allocation

Overview Of Op*miza*on, 2

7. Optimization! Prof. O. Nierstrasz! Lecture notes by Marcus Denker!

Compiler Design. Register Allocation. Hwansoo Han

Code Merge. Flow Analysis. bookkeeping

CS 406/534 Compiler Construction Instruction Selection and Global Register Allocation

Parsing III. CS434 Lecture 8 Spring 2005 Department of Computer Science University of Alabama Joel Jones

A Sparse Algorithm for Predicated Global Value Numbering

Control flow graphs and loop optimizations. Thursday, October 24, 13

CSE P 501 Compilers. SSA Hal Perkins Spring UW CSE P 501 Spring 2018 V-1

CS415 Compilers Register Allocation. These slides are based on slides copyrighted by Keith Cooper, Ken Kennedy & Linda Torczon at Rice University

Data Flow Analysis. Agenda CS738: Advanced Compiler Optimizations. 3-address Code Format. Assumptions

Loops. Lather, Rinse, Repeat. CS4410: Spring 2013

CODE GENERATION Monday, May 31, 2010

CS415 Compilers. Syntax Analysis. These slides are based on slides copyrighted by Keith Cooper, Ken Kennedy & Linda Torczon at Rice University

Compiler Construction 2016/2017 Loop Optimizations

Register allocation. instruction selection. machine code. register allocation. errors

Intermediate Code & Local Optimizations

CS577 Modern Language Processors. Spring 2018 Lecture Optimization

EECS 583 Class 8 Classic Optimization

What Compilers Can and Cannot Do. Saman Amarasinghe Fall 2009

CS 432 Fall Mike Lam, Professor. Data-Flow Analysis

What Do Compilers Do? How Can the Compiler Improve Performance? What Do We Mean By Optimization?

Intermediate Code & Local Optimizations. Lecture 20

Compiler Construction 2010/2011 Loop Optimizations

Syntax Analysis, VI Examples from LR Parsing. Comp 412

The Processor Memory Hierarchy

USC 227 Office hours: 3-4 Monday and Wednesday CS553 Lecture 1 Introduction 4

An Overview of GCC Architecture (source: wikipedia) Control-Flow Analysis and Loop Detection

Register Allocation. CS 502 Lecture 14 11/25/08

CSE443 Compilers. Dr. Carl Alphonce 343 Davis Hall

Control Flow Analysis

Register Allocation. Global Register Allocation Webs and Graph Coloring Node Splitting and Other Transformations

Lecture 21 CIS 341: COMPILERS

Naming in OOLs and Storage Layout Comp 412

CS 426 Fall Machine Problem 4. Machine Problem 4. CS 426 Compiler Construction Fall Semester 2017

Transcription:

COMP 506 Rice University Spring 2018 Introduction to Optimization Local Value Numbering source IR IR target code Front End Optimizer Back End code Copyright 2018, Keith D. Cooper & Linda Torczon, all rights reserved. Students enrolled in Comp 506 at Rice University have explicit permission to make copies of these materials for their personal use. Faculty from other educational institutions may use these materials for nonprofit educational purposes, provided this copyright notice is preserved

Optimization Content from 8 EaC2e Compilers operate at multiple granularities or scopes Local techniques Work on a single basic block Maximal length sequence of straight-line code Regional techniques Consider multiple blocks, but less than whole procedure Single loop, loop nest, dominator region, Intraprocedural, or global, techniques Operate on an entire procedure Common unit of compilation Interprocedural, or whole-program, techniques Operate on > 1 procedure, up to whole program Logistical issues related to accessing the code (but just one) (optimize in the linker?) COMP 506, Spring 2018 2

Optimization At each of these scopes, the compiler uses different graphs Local techniques Dependence graph Regional Techniques Control-flow graph (CFG) Dominator tree (instruction scheduling) (natural loops) Intraprocedural, or global, techniques Control-flow graph Def-Use chains, sparse evaluation graphs, graph of SSA connections Interprocedural, or whole-program, techniques Call (multi) graph Compiler writers should be able to perform graph traversals in their COMP 506, Spring 2018 sleep preorder, postorder, reverse postorder, depth first, 3

Optimization At each of these scopes, the techniques take different approaches Local techniques Simple in-order walks of the block Regional Techniques Find a way to treat multiple blocks as a single block Work with an entire loop nest (EBBs, dominators) Intraprocedural, or global, techniques Data-flow analysis to determine safety and opportunity Separate transformation phase to rewrite the code Interprocedural, or whole-program, techniques Need a compilation framework where optimizer can see all the relevant code Sometimes, limit to all procedures in a file Sometimes, perform optimization at link time COMP 506, Spring 2018 4

Optimization We want to differentiate between analysis and transformation Analysis reasons about the code s behavior Transformation rewrites the code to change its behavior Each needs the other to be worthwhile Local techniques can interleave analysis and transformation The most important property of a basic block is that the operations execute in a predictable, defined order In larger scopes, the compiler typically must complete its analysis before it transforms the code Analysis must consider all possible paths, including cycles Cycles and if-then-else branches typically force compiler into offline analysis Leads to confusion in terminology between optimization, analysis, and transformation COMP 506, Spring 2018 5

Optimization Terminology Optimization We will use optimization to refer to a broad technique or strategy, such as code motion or dead code elimination Transformation We will use transformation to refer to algorithms & techniques that rewrite the code being compiled Analysis We will use the term analysis to refer to algorithms & techniques that derive information about the code being compiled COMP This subtle 506, Spring distinction 2018 in usage was suggested by Vivek Sarkar, now at Georgia Tech. 6

Redundancy Elimination as an Example An expression x+y is redundant if and only if, along every path from the procedure s entry, it has been evaluated, and its constituent subexpressions (x & y) have not been re-defined. If the compiler can prove that an instance of an expression is redundant It can preserve the results of earlier evaluations It can replace the current evaluation with a reference Two pieces to the problem Proving that x+y is redundant Rewriting the code to eliminate the redundant evaluation Value numbering is a single-pass, local technique that accomplishes both. COMP 506, Spring 2018 7

Local Value Numbering The first step in performing local value numbering is to identify the basic blocks maximal length sequences of straight-line (branch-free) code Find all the basic blocks in the code Apply local value numbering to each block To find the basic blocks, we build a control-flow graph Nodes represent basic blocks Edges represent the flow of control Once the compiler has a CFG, it can value number each block COMP 506, Spring 2018 8

Building a Control-Flow Graph The first step in almost any optimization is building a CFG // find all the leaders, assume first op // & block are numbered zero next 0 // block number leader[next++] 0 // block s 1 st op // find other leaders for i 0 to n if op[i] is a jump then leader[next++] target(i) if op[i] is a branch then leader[next++] taken(i) leader[next++] not_taken(i) // build all the blocks for i 0 to next 1 j leader[i] + 1 while j n and j leader j j + 1 last[i] j 1 If target, taken, or not_taken are ambiguous, then we must include all labeled ops as leaders. Sources of ambiguous targets: u Jump or branch to a register u PC-relative jump or branch No Ambiguity In ILOC: All branches in ILOC have two explicit targets. Branches and jumps target a label rather than a register. In the original compiler, jump to register was followed with an advisory list of labels generated when the ILOC was generated. COMP 506, Spring 2018 5.3.4 in EaC2e (p. 241) 9

Building a Control-Flow Graph The first step in almost any optimization is building a CFG // find all the leaders, assume first op // & block are numbered zero next 0 // block number leader[next++] 0 // block s 1 st op // find other leaders for i 0 to n if op[i] is a jump then leader[next++] target(i) if op[i] is a branch then leader[next++] taken(i) leader[next++] not_taken(i) // build all the blocks for i 0 to next 1 j leader[i] + 1 while j n and j leader j j + 1 last[i] j 1 LEADER 0 COMP 506, Spring 2018 Example due to Dr. Lori Pollock 10 LAST EXAMPLE 0 a 4 1 t1 a * 4 2 L1: t2 t1 / c 3 if t2 < w then goto L2 4 m t1 * k 5 t3 m + i 6 L2: h i 7 m t3 h 8 if t3 0 then goto L3 9 goto L1 10 L3: halt

Building a Control-Flow Graph The first step in almost any optimization is building a CFG // find all the leaders, assume first op // & block are numbered zero next 0 // block number leader[next++] 0 // block s 1 st op // find other leaders for i 0 to n if op[i] is a jump then leader[next++] target(i) if op[i] is a branch then leader[next++] taken(i) leader[next++] not_taken(i) // build all the blocks for i 0 to next 1 j leader[i] + 1 while j n and j leader j j + 1 last[i] j 1 EXAMPLE 0 a 4 1 t1 a * 4 2 L1: t2 t1 / c 3 if t2 < w then goto L2 4 m t1 * k 5 t3 m + i 6 L2: h i 7 m t3 h 8 if t3 0 then goto L3 9 goto L1 10 L3: halt LEADER 0 6 4 10 9 2 COMP 506, Spring 2018 11 LAST

Building a Control-Flow Graph The first step in almost any optimization is building a CFG // find all the leaders, assume first op // & block are numbered zero next 0 // block number leader[next++] 0 // block s 1 st op // find other leaders for i 0 to n if op[i] is a jump then leader[next++] target(i) if op[i] is a branch then leader[next++] taken(i) leader[next++] not_taken(i) // build all the blocks for i 0 to next 1 j leader[i] + 1 while j n and j leader j j + 1 last[i] j 1 EXAMPLE 0 a 4 1 t1 a * 4 2 L1: t2 t1 / c 3 if t2 < w then goto L2 4 m t1 * k 5 t3 m + i 6 L2: h i 7 m t3 h 8 if t3 0 then goto L3 9 goto L1 10 L3: halt LEADER 0 6 4 10 9 2 LAST 1 8 5 10 9 3 COMP 506, Spring 2018 12

Building a Control-Flow Graph The first step in almost any optimization is building a CFG // find all the leaders, assume first op // & block are numbered zero next 0 // block number leader[next++] 0 // block s 1 st op // find other leaders for i 0 to n if op[i] is a jump then leader[next++] target(i) if op[i] is a branch then leader[next++] taken(i) leader[next++] not_taken(i) // build all the blocks for i 0 to next 1 j leader[i] + 1 while j n and j leader j j + 1 last[i] j 1 EXAMPLE 0 a 4 1 t1 a * 4 2 L1: t2 t1 / c 3 if t2 < w then goto L2 4 m t1 * k 5 t3 m + i 6 L2: h i 7 m t3 h 8 if t3 0 then goto L3 9 goto L1 10 L3: halt LEADER 0 6 4 10 9 2 LAST 1 8 5 10 9 3 COMP 506, Spring 2018 13

Building a Control-Flow Graph The first step in almost any optimization is building a CFG // find all the leaders, assume first op // & block are numbered zero next 0 // block number leader[next++] 0 // block s 1 st op // find other leaders for i 0 to n if op[i] is a jump then leader[next++] target(i) if op[i] is a branch then leader[next++] taken(i) leader[next++] not_taken(i) // build all the blocks for i 0 to next 1 j leader[i] + 1 while j n and j leader j j + 1 last[i] j 1 EXAMPLE 0 a 4 1 t1 a * 4 2 L1: t2 t1 / c 3 if t2 < w then goto L2 4 m t1 * k 5 t3 m + i 6 L2: h i 7 m t3 h 8 if t3 0 then goto L3 9 goto L1 10 L3: halt To build the control-flow graph, add code after assignments to leader. COMP 506, Spring 2018 14

Local Value Numbering An Old Idea The key notion (Balke 1967 or Ershov 1954) Assign an identifying number, VN(e), to each expression e VN(x+y) = VN(j) iff x+y and j always have the same value Use hashing over value numbers to make it efficient Use the value numbers to improve the code Improving the code Replace redundant expressions Simplify algebraic identities Discover constant-valued expressions, fold & propagate them V(n) is n s value number This technique was invented for low-level, linear IRs Equivalent methods exist for trees (build a DAG, 8.3.1 in EaC1e) COMP 506, Spring 2018 15

Local Value Numbering Local Þ one block at a time Block Þ straight-line code The Algorithm For each operation o in the block 1 Get value numbers for the operands from a hash lookup 2 Hash <operator,vn(o 1 ),VN(o 2 )> to get a value number for o 3 If o already had a value number, replace o with a reference 4 If o 1 & o 2 are constant, evaluate it & use a load immediate If hashing behaves, the algorithm runs in linear time If you don t believe in hashing, try multi-set discrimination 1 Minor issues Commutative operator Þ hash operands in each order or sort the operands by their VNs before hashing (either works, sorting is likely cheaper) Looks at operand s value number, not its name COMP 1 EaC2e: 506, digression Spring 2018 on page 256 or reference [65] 16

Local Value Numbering An Example Original Code a x + y * b x + y a 17 * c x + y With VNs a 3 x 1 + y 2 * b 3 x 1 + y 2 a 4 17 4 * c 3 x 1 + y 2 Rewritten a 3 x 1 + y 2 * b 3 a 3 a 4 17 4 * c 3 a 3 (oops!) Two redundancies: Eliminate stmts with a * Coalesce results? Options: Use c 3 b 3 Save a 3 in t 3 Rename around it COMP a 17506, kills Spring the copy 2018 of value 3 in a 17

Local Value Numbering Example (continued) Original Code a 0 x 0 + y 0 * b 0 x 0 + y 0 a 1 17 * c 0 x 0 + y 0 With VNs a 03 x 0 1 + y 0 2 * b 03 x 01 + y 0 2 a 14 17 4 * c 03 x 01 + y 0 2 Rewritten a 03 x 0 1 + y 0 2 * b 03 a 0 3 a 14 17 4 * c 03 a 0 3 Renaming: Give each value a unique name Makes it clear Notation: While complex, the meaning is clear Result: a 03 is available rewriting works COMP 506, Spring 2018 18 *

Simple Extensions to Local Value Numbering Constant folding Add a field to the table that records when a value is constant Evaluate constant values at compile-time Replace with load immediate or immediate operand No stronger local algorithm Algebraic identities Must check (many) special cases Replace result with the input s VN Build a decision tree on operation Identities: (Click) x y, x+0, x-0, x*1, x 1, x-x, x*0, x x, xú0, x Ù 0xFF FF, max(x,maxint), min(x,minint), max(x,x), min(y,y), and so on... (over value numbers, not names) COMP 506, Spring 2018 19

But, Wait a Minute If local value numbering renames everything, how does the program work after optimization? The flow of data across blocks is encoded into the names given to values While LVN is local, renaming is not Different approaches to the problem of names Skip renaming and accept that LVN will miss some opportunities Differentiate local names from global names & rename local ones Requires analysis of entire procedure to discover difference between names 1 Global name appears in two different basic blocks Skip renaming and complicate the algorithm for LVN 2 Adopt a global approach to renaming before applying LVN 3 Handle the problem with code shape 1 The analysis is simple, based on Briggs classification of names in semi-pruned SSA construction. 2 The algorithm could track all names associated with a value, updating that map on each assignment. COMP 3 For example, 506, Spring the 2018 compiler could convert the code to an SSA name space. 20

Code Shape The compiler can create a code shape that sidesteps this naming issue Each program variable gets a unique permanent name Evaluate each subexpression into a local, temporary name For each assignment, copy the RHS expression into the name associated with the LHS variable Evaluations are the result of operations other than a register-to-register copy Assignments are the result of a register-to-register copy Connections across blocks all result from assignment LVN leaves the copy operations alone name virtual register To make this easy: Assign virtual register numbers to variables, starting at low number Assign any temporary value a number higher than any variable Assignment becomes a copy from higher numbered register to lower one 1 The code shape solution may find fewer redundancies than either differentiating local COMP & global 506, names Spring or 2018 building SSA form. (A program variable might be used in just 1 block.) See p. 248 in EaC2e 21

Optimization In discussing any optimization, we should look at three issues Safety: Does it change the results of the computation? Safety is proven with results of analysis Data-flow analysis or other special case analysis Profitability: Is it expected to speed up execution? Many authors assume transformations are always profitable Use either heuristics or a careful algebra of costs Opportunity: Can we efficiently locate places to apply it? Can we find find all the places where the transformation works? Do we need to update safety information afterward? COMP 506, Spring 2018 22

Safety The first principle of code optimization: The compiler must preserve the code s meaning When can the compiler transform the code? Original & transformed code must have the same final state Variables that are visible at exit Equality of result, not equality of method (ignore temporaries) Formal notion For two expressions, M and N, we say that M and N are observationally equivalent if and only if, in any context C where both M and N are closed (that is, have no free variables), evaluating C[M] and C[N] either produces identical results or neither terminates. Plotkin, 1975 Þ Different translations with identical results are fine COMP 506, Spring 2018 23

Safety In practice, compilers use a simpler notion of equivalence If, in the actual program context, the result of evaluating e cannot be distinguished from the result of evaluating e, the compiler can replace e with e. This restatement ignores divergence If e is faster than e, the transformation is profitable Equivalence and context Compiled code always executes in some context Optimization is the art of capitalizing on context Lack of context Þ fully general (i.e., slow) code Some compilers employ a worse standard Correct behavior for standard conforming code Undefined behavior for other code (FORTRAN) COMP 506, Spring 2018 24

Safety My favorite bad quote on safety You, as a compiler writer, must decide if it s worth the risk of doing this kind of optimization. It s difficult for the compiler to distinguish between the safe and dangerous cases, here. For example, many C compilers perform risky optimizations because the compiler writer has assumed that a C programmer can understand the problems and take steps to remedy them at the source code level. It s better to provide the maximum optimization, even if it s dangerous, than to be conservative at the cost of less efficient code. A Pascal programmer may not have the same level of sophistication as a C programmer, however, so the better choice in this situation might be to avoid the risky optimization entirely or to require a special command-line switch to enable the optimization. Allen Holub, Compiler Design in C, Prentice Hall, 1990, p. 677 The point You must not violate the first principle Without the first principle, just compile a return and be done COMP This statement 506, Spring was 2018gone by the 2 nd Edition. 25

Safety & Local Value Numbering Why is local value numbering safe? Hash table starts empty Expressions placed in table as processed If <operator,vn(o 1 ),VN(o 2 )> is in the table, then It has already occurred at least once in the block Neither o 1 nor o 2 have been subsequently redefined The mapping uses VN(o 1 ) and VN(o 2 ), not o 1 and o 2 If one was redefined, it would have a new VN Critical property of a basic block: If any statement executes, they all execute, in a predetermined order If <operator,vn(o 1 ),VN(o 2 )> has a VN, the compiler can safely use it The algorithm incrementally constructs a proof that <operator,vn(o 1 ),VN(o 2 )> is redundant The algorithm modifies the code, but does not invalidate the table COMP 506, Spring 2018 26

Profitability The compiler should only transform the code when it helps! Eliminating one or more operations Replacing an operation with a cheaper one Moving an operation to a place where it will execute fewer times Sometimes, we can prove profitability Fold a constant expression into an immediate operation Sometimes, we must guess Eliminating a redundant operation in a loop Sometimes, we cannot tell Inlining in a Fortran compiler We should know when we cannot tell if some transformation is profitable! Compiler writers need to think explicitly about profitability... COMP 506, Spring 2018 27

Profitability & Local Value Numbering When is local value numbering profitable? If reuse is cheaper than re-computation Does not cause a spill or a copy In practice, assumed to be true (hard to determine) Local constant folding is always profitable Re-computing uses a register, as does load immediate Immediate form of operation avoids even that cost Algebraic identities If it eliminates an operation, it is profitable (x + 0) Profitability of simplification depends on target (2x Þ x+x) Easy to factor target machine costs into the implementation don t apply it unless it is profitable! COMP 506, Spring 2018 28

Opportunity To perform an optimization, the compiler must locate all the places in the code where it can be applied Allows compiler to evaluate each possible application Leads to efficient application of the transformation Avoids additional search Approaches Perform analysis to find opportunities VERYBUSY expressions & code hoisting Look at every operation Value numbering, loop invariant code motion Iterate over subset of the IR Operator strength reduction on SSA form COMP 506, Spring 2018 29

Opportunity & Local Value Numbering How does local value numbering find opportunity? Linear scan over block, in execution order Constructs a model of program state At each operation, check for several opportunities Summary It performs an exhaustive search of the opportunities This answer is not satisfying, but it is true Must limit cost of checking each operation For example, use a tree of algebraic identities by operator Hashing keeps cost down to O(1) per operand + per operation COMP 506, Spring 2018 30