Toggle navigation
Bruce Lee's Notes
HOME
ARCHIVES
ABOUT
CATEGORIES
TAGS
SEARCH
English
English
简体中文
Tags
Browse English posts by tag.
C/C++
AI
Computer Architecture
Operating Systems
Engineering
Compilers
Memory and Concurrency
Numerical Computing
Mathematics
Reflections
Robotics
C/C++
C Preprocessor Token-Pasting Operator
C/C++ preprocessing
Variadic Macros, Token Pasting, and Callback-Style Macro Expansion
C/C++
Commenting Multiline Macros: A Mistake That Cost an Afternoon and an Evening
C/C++
Reading the Source: Traps, Abstract Machine, and the Runtime Environment
C/C++
Project Makefiles and NEMU Batch Mode
C/C++
A Possible Implementation of sprintf and stdarg
C/C++
Using a Macro to Check Whether Another Macro Is Defined
C/C++ preprocessing
AI
AI: What We Should Understand and How We Might Develop
Facing the present and looking toward the future
Computer Architecture
Implementing RISC-V Trap Handling and System Calls
Engineering
Stage-Specific Forwarding, Load-Use Stalls, Early Branches, and Pipeline Flushes
RISC-V
Precise Traps, Multiple Issue, Register Renaming, and Memory Aliasing
RISC-V
Pipeline Hazards, Forwarding, Register Timing, and the x0 Trap
RISC-V
Fundamental RISC-V Design Principles
RISC-V
Cache Capacity, Block Size, Miss Penalties, and Set Associativity
RISC-V
Bounds Checks, Calling Conventions, Large Immediates, and PC-Relative Addressing
RISC-V
Long Branches, Synchronization, Compiler Optimizations, and x86 Complexity
RISC-V
Rounding, Intermediate Results, Parallel Floating-Point Arithmetic, and Processor Design
RISC-V
Multiplication Hardware, Subnormal Floating-Point Values, and the RISC-V F/D Extensions
RISC-V
DOS Basics and the Beginning of Assembly Programming
x86
A Beginner 8086 Assembly Lab: Copying Program Code
A small code-installation exercise
Where I Left Off in My x86 Assembly Notes
x86
A Simple 8086 Assembly Lab: Displaying a Number on Screen
An introductory assembly experiment
x86 Programming Notes, Part 1: Techniques and Instruction Details
x86
x86 Programming Notes, Part 2: I/O, Calls, Interrupts, and Protected Mode
x86
x86 Programming Notes, Part 3: Execution, Descriptors, and Mode Switching
x86
8086 Interrupts: Sources, the Vector Table, and Handler Execution
A closer look at 8086 interrupts
Assembly Environments and Conventions Used in This Blog
Starting again when necessary
Operating Systems
How the YEMU Emulator Works
Engineering
Compiling, Loading, and Executing a User Program
Engineering
Device Interfaces, Tracing, and Memory-Mapped I/O in NEMU
Engineering
ELF Symbol Handling and Abstract Machine Infrastructure
Engineering
From Compilation to Execution: Loading Navy Applications in Nanos-lite
Engineering
Notes on Operand Decoding and Implementing RISC-V Instructions
Engineering
Memory Management and Task Switching in a Multiprogram Environment
Engineering
Task Contexts, Stack Initialization, and Context Switching
Engineering
Startup Assembly and Experiments With printf
Engineering
Implementing and Using Memory and Function Tracing
Engineering
Tracing Infrastructure and an Instruction Ring Buffer
Engineering
Engineering
Tracing the Nested Calls Behind cmd_c
Engineering
Building Multiple Applications and Managing the Compilation Pipeline
Engineering
Debug Works, but Release “Optimizes Away” a Write
A required write hidden in an assertion disappears when checks are disabled.
One Version of the Headers, Another Version of the Generator
Headers, libraries, generators, and caches jointly determine toolchain identity.
The Library Is in the Package. Why Can’t the Program Find It?
Connect real library files, SONAMEs, linker names, and runtime search paths.
The Compiler Moved. Its Lookup-Table Module Didn’t Get the Address
Use real functionality and missing-resource tests to validate relocation.
Why Is Packing Compiler Outputs into One File Hard?
Treat a model file as a protocol with offsets, lengths, and ownership.
“I Only Rebuilt It.” Why Did the Installation Directory Disappear?
Define the responsibilities and failure states of environment setup, builds, and installation.
Compilation Failed. Why Is There Still a “Successful Model” in the Directory?
Make output directories, temporary artifacts, and stale files part of a clear success contract.
Why Does the Same Release Package Get a Different Hash Every Time?
Separate archive-event time, package timestamps, and byte reproducibility.
The Assembly Looks Right. Does That Mean the Machine Code Is Right?
Understand what pseudoassembly, assembly, machine code, and mathematical references each prove.
The Most Useful Words in an Operator Specification May Be “Not Yet Confirmed”
Keep unknowns explicit rather than turning example tables into capability promises.
You Found the Operator’s Name. Does That Make It Supported?
Require evidence for a complete compilation path before calling an operator supported.
An Instruction’s Four Identities: Why Code Generation Needs More Than Strings
Assign responsibilities and diagnostics across operation, kernel, emission, and encoding layers.
You Caught the Exception. What Happens to the Half-Written Machine Code?
After catching an error, account for the state and output already produced.
One More Loop, and the Binary Snapshot Looks Like a Different Program
Examine how loops, labels, and independent emitter instances affect binary determinism.
“I Parsed a Number” Does Not Mean the Input Is Valid
Check full input consumption, signs, and field ranges after parsing succeeds.
Engineering Debugging Notes
Project engineering
Timing, Logging, Argument Passing, and Automated Makefile Builds
Engineering
Instruction Pattern Matching: The Macros and Functions Behind INSTPAT
Engineering
Compilers
Debug Works, but Release “Optimizes Away” a Write
A required write hidden in an assertion disappears when checks are disabled.
One Version of the Headers, Another Version of the Generator
Headers, libraries, generators, and caches jointly determine toolchain identity.
The Library Is in the Package. Why Can’t the Program Find It?
Connect real library files, SONAMEs, linker names, and runtime search paths.
The Compiler Moved. Its Lookup-Table Module Didn’t Get the Address
Use real functionality and missing-resource tests to validate relocation.
Why Is Packing Compiler Outputs into One File Hard?
Treat a model file as a protocol with offsets, lengths, and ownership.
“I Only Rebuilt It.” Why Did the Installation Directory Disappear?
Define the responsibilities and failure states of environment setup, builds, and installation.
Compilation Failed. Why Is There Still a “Successful Model” in the Directory?
Make output directories, temporary artifacts, and stale files part of a clear success contract.
Why Does the Same Release Package Get a Different Hash Every Time?
Separate archive-event time, package timestamps, and byte reproducibility.
The Assembly Looks Right. Does That Mean the Machine Code Is Right?
Understand what pseudoassembly, assembly, machine code, and mathematical references each prove.
The Most Useful Words in an Operator Specification May Be “Not Yet Confirmed”
Keep unknowns explicit rather than turning example tables into capability promises.
You Found the Operator’s Name. Does That Make It Supported?
Require evidence for a complete compilation path before calling an operator supported.
An Instruction’s Four Identities: Why Code Generation Needs More Than Strings
Assign responsibilities and diagnostics across operation, kernel, emission, and encoding layers.
It Only Moves Data. How Can It Still Be Wrong?
Preserve coordinates, strides, aliasing, and quantization when moving data.
Same Output Shape, Different Answers: Pooling, Resizing, and Index Reductions
Let window denominators, sampling coordinates, and index rules determine actual results.
A Function Name Cannot Hold Its Numerical Contract
Specify domains, approximations, precision, and axes beyond a function's name.
Compiler Engineering Notes: 48 Bilingual Articles and Reading Paths
Numerics, operators, resources, and compiler delivery
Just Take the Mean—Why Is the Compiler Writing Loops?
Lower arbitrary reduction axes into executable loops and account for layout and transfer costs.
The Vanishing Dimension: How keep_dims=false Can Break an Inverse Permutation
Preserve axis identity when dimensions disappear, then reconstruct the inverse permutation.
Max, Min, and Sum: Similar Operators, Different Mathematical Homework
Share reduction structure without copying initialization, accumulation, or rescaling semantics.
This Reduction Does Nothing—Why Can’t We Delete It?
A mathematical identity can still require a change of quantized representation.
The Multiplication Is Right; the Scale Is Wrong: An Integer Kernel’s Two Ledgers
Track input scales, output scales, and the range of the intermediate product.
Once BatchNorm Becomes Multiply-Add, the Numerical Work Begins
Follow fixed statistics through channelwise affine transforms, multipliers, shifts, and biases.
Just a Few Channel Parameters—So Why Is Local Memory Full?
Avoid materializing channel parameters across a whole tensor while preserving broadcasting.
Build a Dedicated Operator, Then Remove It: A Design Change Worth Recording
Compare the expressiveness and maintenance cost of a dedicated affine operator and its decomposition.
Epsilon Was Nonzero—Until It Nearly Vanished in the Integer Domain
Follow epsilon, squares, and reciprocal square roots through normalization range planning.
Floating Point Passes, Quantization Fails: A Rewrite Gives the Output the Input’s Identity
Treat the rewritten result type as both a container and a numerical contract.
The Importer Got Clever Too Soon: Algebraic Optimization before Quantization Metadata
Understand the interaction between algebraic rewrite order, metadata matching, and constants.
Grouped Convolution: Once You Slice the Cake, Slice the Labels Too
Split input and weight groups while carrying their quantization metadata with them.
Transposed Convolution Weights: The Shape Is Honest, but Memory Speaks Another Dialect
Derive slices from actual weight storage, not just a logical dimension order.
Why Does Reshape Need Code? The Elements Stay the Same; Their Route Changes
Prove the linear element mapping and distinguish shape changes from physical rearrangement.
When the Debugger Starts Lying: One Permute, Three Ways to Fix Dump
Three alternative branch fixes show why observation paths need layout contracts too.
Broadcasting: Sometimes the Right Address Is the One That Does Not Move
Build per-axis address plans for scalars, lower-rank inputs, and more complex broadcasts.
The First Row Works, the Second Disappears: Alignment, Strides, and Padded Constants
Make logical widths, physical strides, padded storage, and parameter layouts agree.
Subtracting Zero Can Disappear; Subtracting from Zero Cannot
Keep constant folding, commutativity, and operand direction as separate decisions.
Abs and Sign: One Line of Arithmetic Does Not Make Their Parameter Contracts Interchangeable
Carry a unary operator's definition through types, quantization, and parameter encoding.
Who Moved My Scratch Register? Teaching an Emitter to Borrow and Return
Replace informal scratch-register conventions with explicit borrowing and lifetime rules.
Putting Activation Inside Convolution: Preserve the Quantization Boundary Before Removing the Node
Preserve intermediate quantization and legality when fusing convolution with activation.
A Sigmoid After MatMul: Why the Compiler Still Refuses to Fuse It
Understand how consumers, views, and dependencies constrain matrix-activation fusion.
When Weights Move to the Left: A Transpose Identity That Moves the Whole Compiler Chain
A transpose identity starts the rewrite; weight identity and quantization axes must follow.
Why Does Someone Keep Borrowing My “Temporary” Register?
Express register ownership through scope and define the limits of automatic release.
A Few More Branches in the Graph—and Synchronization Registers Run Out First?
Explain how graph fan-out and dependency joins create synchronization-resource pressure.
The View Moved No Data. Why Can’t We Return the Memory?
Follow asynchronous consumers through view chains before reclaiming underlying storage.
The Address Fits. Why Does the Compiler Say Memory Is Full?
Separate encodable addresses, allocation intervals, and actual memory budgets.
Why Write the Same Final State Twice?
Distinguish persistent state, final state, and direct-output buffers.
I Waited for the Event. Why Isn't the Data Ready?
Make synchronization events cover the actual production of data across execution engines.
You Caught the Exception. What Happens to the Half-Written Machine Code?
After catching an error, account for the state and output already produced.
One More Loop, and the Binary Snapshot Looks Like a Different Program
Examine how loops, labels, and independent emitter instances affect binary determinism.
“I Parsed a Number” Does Not Mean the Input Is Valid
Check full input consumption, signs, and field ranges after parsing succeeds.
Fewer Operations—So Why Disable the Optimization?
Treat disabling an optimization as a design decision about slicing and quantization contracts.
Memory and Concurrency
It Only Moves Data. How Can It Still Be Wrong?
Preserve coordinates, strides, aliasing, and quantization when moving data.
Why Does Reshape Need Code? The Elements Stay the Same; Their Route Changes
Prove the linear element mapping and distinguish shape changes from physical rearrangement.
When the Debugger Starts Lying: One Permute, Three Ways to Fix Dump
Three alternative branch fixes show why observation paths need layout contracts too.
Broadcasting: Sometimes the Right Address Is the One That Does Not Move
Build per-axis address plans for scalars, lower-rank inputs, and more complex broadcasts.
The First Row Works, the Second Disappears: Alignment, Strides, and Padded Constants
Make logical widths, physical strides, padded storage, and parameter layouts agree.
Who Moved My Scratch Register? Teaching an Emitter to Borrow and Return
Replace informal scratch-register conventions with explicit borrowing and lifetime rules.
Why Does Someone Keep Borrowing My “Temporary” Register?
Express register ownership through scope and define the limits of automatic release.
A Few More Branches in the Graph—and Synchronization Registers Run Out First?
Explain how graph fan-out and dependency joins create synchronization-resource pressure.
The View Moved No Data. Why Can’t We Return the Memory?
Follow asynchronous consumers through view chains before reclaiming underlying storage.
The Address Fits. Why Does the Compiler Say Memory Is Full?
Separate encodable addresses, allocation intervals, and actual memory budgets.
Why Write the Same Final State Twice?
Distinguish persistent state, final state, and direct-output buffers.
I Waited for the Event. Why Isn't the Data Ready?
Make synchronization events cover the actual production of data across execution engines.
Fewer Operations—So Why Disable the Optimization?
Treat disabling an optimization as a design decision about slicing and quantization contracts.
Numerical Computing
Same Output Shape, Different Answers: Pooling, Resizing, and Index Reductions
Let window denominators, sampling coordinates, and index rules determine actual results.
A Function Name Cannot Hold Its Numerical Contract
Specify domains, approximations, precision, and axes beyond a function's name.
Just Take the Mean—Why Is the Compiler Writing Loops?
Lower arbitrary reduction axes into executable loops and account for layout and transfer costs.
The Vanishing Dimension: How keep_dims=false Can Break an Inverse Permutation
Preserve axis identity when dimensions disappear, then reconstruct the inverse permutation.
Max, Min, and Sum: Similar Operators, Different Mathematical Homework
Share reduction structure without copying initialization, accumulation, or rescaling semantics.
This Reduction Does Nothing—Why Can’t We Delete It?
A mathematical identity can still require a change of quantized representation.
The Multiplication Is Right; the Scale Is Wrong: An Integer Kernel’s Two Ledgers
Track input scales, output scales, and the range of the intermediate product.
Once BatchNorm Becomes Multiply-Add, the Numerical Work Begins
Follow fixed statistics through channelwise affine transforms, multipliers, shifts, and biases.
Just a Few Channel Parameters—So Why Is Local Memory Full?
Avoid materializing channel parameters across a whole tensor while preserving broadcasting.
Build a Dedicated Operator, Then Remove It: A Design Change Worth Recording
Compare the expressiveness and maintenance cost of a dedicated affine operator and its decomposition.
Epsilon Was Nonzero—Until It Nearly Vanished in the Integer Domain
Follow epsilon, squares, and reciprocal square roots through normalization range planning.
Floating Point Passes, Quantization Fails: A Rewrite Gives the Output the Input’s Identity
Treat the rewritten result type as both a container and a numerical contract.
The Importer Got Clever Too Soon: Algebraic Optimization before Quantization Metadata
Understand the interaction between algebraic rewrite order, metadata matching, and constants.
Grouped Convolution: Once You Slice the Cake, Slice the Labels Too
Split input and weight groups while carrying their quantization metadata with them.
Transposed Convolution Weights: The Shape Is Honest, but Memory Speaks Another Dialect
Derive slices from actual weight storage, not just a logical dimension order.
Subtracting Zero Can Disappear; Subtracting from Zero Cannot
Keep constant folding, commutativity, and operand direction as separate decisions.
Abs and Sign: One Line of Arithmetic Does Not Make Their Parameter Contracts Interchangeable
Carry a unary operator's definition through types, quantization, and parameter encoding.
Putting Activation Inside Convolution: Preserve the Quantization Boundary Before Removing the Node
Preserve intermediate quantization and legality when fusing convolution with activation.
A Sigmoid After MatMul: Why the Compiler Still Refuses to Fuse It
Understand how consumers, views, and dependencies constrain matrix-activation fusion.
When Weights Move to the Left: A Transpose Identity That Moves the Whole Compiler Chain
A transpose identity starts the rewrite; weight identity and quantization axes must follow.
Mathematics
Unit Impulse and Unit Step in Continuous and Discrete Time
Signals and systems
Reflections
Beyond Technical Depth: What Else Makes a Capable Engineer?
Keep working for a better life
Preparing for the Long Haul
Sustained effort and a better life
Robotics
DDS Sandbox Restrictions and the Limits of ROS 2 Runtime Verification
ROS2
fleet_manager: Task Queue, Planner Dependency, and Assignment State Retention
ROS2
path_planner: Graph Model, BFS, and Route Stitching
ROS2
robot_agent: Execution States and Waypoint Progression
ROS2
Why Planning Uses Services While State and Assignments Use Topics
ROS2
Why the Project Has Not Chosen Nav2-First Integration
ROS2
Why Conflict Detection and Reservations Are the Next Major Complexity Increase
ROS2
ROS2 Fleet Coordinator V1: From Task Submission to Route Dispatch
ROS2
ESC