Introduction

Constant Folding is a fundamental compiler optimization technique in which constant expressions are evaluated at compile time, rather than at runtime. This process eliminates unnecessary calculations and improves the performance of the compiled program by reducing the workload on the CPU during execution.

At its core, constant folding is a type of strength reduction and peephole optimization, allowing compilers to produce more efficient intermediate or machine code.

Basic Concept

When a compiler encounters an expression consisting entirely of constants, it evaluates that expression and replaces it with the resulting value during compilation.

Example (Before Constant Folding)

int a = 2 + 3 * 4;

The expression 2 + 3 * 4 is fully composed of constants.

After Constant Folding

int a = 14;

The compiler evaluates the expression once and stores the literal value 14 directly in the binary.

Motivation

ReasonBenefit
Reduce runtime computationSpeeds up program execution
Simplify intermediate codeEases further compiler optimizations
Improve CPU cache utilizationSmaller instruction footprint
Enhance readability (IR level)Easier to analyze and debug

When It Applies

Constant folding applies when:

  • The expression includes only literals or constant variables
  • There are no side effects (e.g., no function calls, I/O, or volatile reads)
  • All operands are known at compile time

Types of Folded Expressions

1. Arithmetic Folding

int b = 10 / 2 + 7;  // folded to 12

2. Logical Folding

bool valid = true && false;  // folded to false

3. Bitwise Folding

int flags = 0xF0 & 0x0F;  // folded to 0x00

4. Relational Folding

bool result = 5 > 3;  // folded to true

5. String Concatenation (in some languages)

const msg = "Hello, " + "World!";  // folded to "Hello, World!"

Constant Folding in Intermediate Representations (IR)

In compilers like LLVM, GCC, and Java JIT, constant folding happens during IR construction and optimization passes.

Example in LLVM IR:

%1 = add i32 2, 3

May be replaced by:

%1 = i32 5

The folded value can enable further dead code elimination or loop unrolling.

Real-World Example

Java:

final int WIDTH = 1920;
final int HEIGHT = 1080;
int totalPixels = WIDTH * HEIGHT;

Because WIDTH and HEIGHT are final, the compiler can fold this at compile time:

int totalPixels = 2073600;

Languages and Environments That Perform Constant Folding

Language / CompilerConstant Folding Support
C/C++ (GCC, Clang)✅ Yes
Java (Javac, JVM)✅ Yes (with final)
JavaScript (V8, SpiderMonkey)✅ Yes in JIT engines
Python✅ Yes for literals
Rust (rustc)✅ Yes
Go✅ Yes

In Python (CPython)

Python performs limited constant folding as part of its bytecode compilation:

def f():
    return 2 + 3

Is compiled to bytecode like:

LOAD_CONST 5
RETURN_VALUE

Because 2 + 3 is folded at compile time.

Even nested operations are folded:

x = 1 + 2 * 3  # folded to 7

You can inspect it using the dis module:

import dis

def f():
    return 2 * 3 + 4

dis.dis(f)

Constant Folding vs Constant Propagation

FeatureConstant FoldingConstant Propagation
When it happensAt compile-time for expressionsAt compile-time for variables
What it doesComputes literal expressionsSubstitutes known constant values
Example2 * 36x = 5; y = x + 1;y = 6

They are often used together in modern compilers.

Constant Folding in Functional Languages

In languages like Haskell, folding is more extensive due to immutability and referential transparency:

let x = 2 + 2

The compiler knows 2 + 2 will always return 4, so it’s safe to fold it.

Limitations

LimitationExplanation
Cannot fold expressions with side effectse.g., print(2 + 3)
Cannot fold runtime-dependent valuese.g., Date.now() + 1000
Not always folded for debuggingSome compilers delay folding for visibility

Not Folded: Volatile and Dynamic Values

volatile int speed = 90;
int limit = speed + 10;  // Cannot be folded!

Volatile memory references must be read at runtime.

Folded Code and Debugging

Over-aggressive folding can make debugging harder:

#define BUFFER_SIZE (512 + 256 + 128)

May appear as:

#define BUFFER_SIZE 896

The symbolic intent (512 + 256 + 128) is lost. Some compilers preserve symbols during early debug builds to aid in debugging.

Compiler Flags That Affect Folding

CompilerFlagDescription
GCC-O1, -O2, -O3Enable levels of optimization, including folding
Clang-O1 to -O3Same as GCC
JavacEnabled by default for finalPerforms folding with final constants

In debug mode (-O0), folding might be partially disabled for clarity.

Summary

FeatureDescription
What is it?Compile-time evaluation of constant expressions
Why use it?Reduces runtime work, improves performance
Applies toArithmetic, logical, bitwise, and string constants
Used inC/C++, Java, Python, JS, IR compilers
Related techniquesConstant propagation, dead code elimination

Related Keywords