Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
271187c
Refactor bisector system, add supervisor, add unit tests, and fix tra…
tgiphil May 4, 2026
e3c2fa2
Enable SafePoint stages in method compiler pipeline
tgiphil May 4, 2026
cbfefde
Standardize bisect arg names, refactor bisector logic
tgiphil May 4, 2026
700b95d
Refactor: centralize bisector constants in Constant.cs
tgiphil May 4, 2026
add0e39
Remove forced-disabled transforms from bisector logic
tgiphil May 4, 2026
4d24be1
Refactor bisector classes to internal top-level types
tgiphil May 4, 2026
6b70159
Refactor: Move unit test serialization to new class
tgiphil May 4, 2026
d1d259e
Refactor unit test discovery and execution flow
tgiphil May 4, 2026
5b0630a
Refactor Sub64 logic for clarity in BitTrackerOperations
tgiphil May 5, 2026
e073085
Add sign extension tests and fix SignExtend32x64 mask
tgiphil May 5, 2026
7cae362
Add new optimization defaults; reformat Constant.cs
tgiphil May 5, 2026
ddb62d6
Refactor bisector session state and iteration handling
tgiphil May 5, 2026
1b9af45
Replay all bisector session results from index 0
tgiphil May 5, 2026
e75446c
Add regression tests and fix BitTrackerOperations bugs
tgiphil May 5, 2026
4d15c05
Improve BitTrackerOperations edge case handling and tests
tgiphil May 5, 2026
6b1cd31
update 1
tgiphil May 5, 2026
cb01152
Reorganize tests
tgiphil May 5, 2026
cd4e096
Add AddCarryOut32/64 logic and expand boolean narrowing tests
tgiphil May 5, 2026
6abd131
Add unit tests and handlers for Add/Sub carry/overflow ops
tgiphil May 5, 2026
0014113
Document BitTrackerStage and related subsystems
tgiphil May 5, 2026
c7cf3de
Fix signed subtraction overflow logic and tests
tgiphil May 5, 2026
0817bde
Standardize carry/overflow out IR handling in BitTracker
tgiphil May 5, 2026
782a85a
Update AddOverflowOut handlers in BitTrackerStage
tgiphil May 5, 2026
c6b2b40
Update BitTracker handlers for SubCarry/Overflow IR ops
tgiphil May 5, 2026
5f03c74
Update bisector to support all stages by default
tgiphil May 5, 2026
c30369d
Update BitTrackerStage to use generic handler for SubCarryOut
tgiphil May 5, 2026
423411a
Tighten BitValue equality; simplify bisector counters
tgiphil May 5, 2026
7b6d2e0
Track newly observed transforms per iteration
tgiphil May 6, 2026
9a745fd
Refactor bisector header output to single line
tgiphil May 6, 2026
41ef4b6
Clean up bisector: remove dead code and debug prints
tgiphil May 6, 2026
7ab49d8
Refactor bisector output methods and add FailureCount
tgiphil May 6, 2026
d2f2182
Refactor: organize bisector logic into regions & helpers
tgiphil May 6, 2026
6e6c807
Track and report unit test restarts-exceeded failures
tgiphil May 6, 2026
ef28f0e
Move BitTrackerOperations to Analysis namespace
tgiphil May 6, 2026
6463bfe
Enhance transform hooks and conditional diagnostics
tgiphil May 6, 2026
1cb2765
Enable transform hooks selectively in OptimizationStage
tgiphil May 7, 2026
e835b9c
Add global.json to specify .NET SDK version 10.0.203
tgiphil May 7, 2026
be1536f
Improve PipelinePool lifecycle management in Compiler
tgiphil May 7, 2026
4cd93c2
Code cleanup: formatting, unused usings, add NotifyStop
tgiphil May 8, 2026
d120f4b
Adjust method pipeline, docs, and UI usability
tgiphil May 8, 2026
b9fa62d
Enhance reduction logic and add optimization args
tgiphil May 8, 2026
3873b04
Remove dynamic bisecting, fuzz tests, and refactor transforms
tgiphil May 9, 2026
dded7f6
Rename EnableTransformHooks to AllowTransformHooks
tgiphil May 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ Key namespaces/classes:
- `Mosa.Compiler.Framework.Context` – represents a position in the instruction stream
- `Mosa.Compiler.MosaTypeSystem` – MOSA's type system (wraps `dnlib`)
- `Mosa.Compiler.Framework.IR` – IR instruction definitions
- `Mosa.Compiler.Framework.Stages.BitTrackerStage` – per-method stage that propagates value range and known-bit information; see **BitTracker Stage** section below
- `Mosa.Compiler.Framework.Stages.BitTrackerOperations` – stateless, node-free operation logic for BitTrackerStage; unit-tested in `Mosa.Compiler.Framework.xUnit/BitTrackerOperationsTests.cs`
- `Mosa.Compiler.Framework.BitValue` – the value/bit-range lattice type used throughout the BitTracker subsystem
- `Mosa.Compiler.Common.IntegerTwiddling` – carry/overflow predicate helpers used by BitTrackerOperations

Optimization levels (set via `-oN`):
- `-o0` = no optimizations
Expand Down Expand Up @@ -229,6 +233,151 @@ When adding new files to existing projects:
5. If adding a new compiler transform, inherit from `BaseTransform` and register it in the appropriate stage.
6. If adding new unit tests (xUnit), add them to `Mosa.Compiler.Common.xUnit` or `Mosa.Compiler.Framework.xUnit`.
7. If adding new bare-metal test cases, add them to `Mosa.UnitTests` following the existing pattern with `[MosaUnitTest]` attributes.
8. If adding a new setting to `MosaSettings` or `CommandLineArguments`, also add the corresponding entry to `Docs/command-line-arguments.rst`.

---

## BitTracker Stage

`BitTrackerStage` (`Mosa.Compiler.Framework/Stages/BitTrackerStage.cs`) is a per-method optimization stage that propagates **value range and known-bit information** through the instruction stream. This extra knowledge enables downstream constant folding, branch elimination, and instruction simplification.

### Architecture

The stage is split across two files:

| File | Role |
|---|---|
| `BitTrackerStage.cs` | Stage driver: iterates virtual registers, calls per-instruction visitors, folds constants, eliminates dead branches |
| `BitTrackerOperations.cs` | Pure static operation logic: takes `BitValue` operands directly — no `Node` dependency — making it fully unit-testable in isolation |

The stage runs iteratively (up to 10 passes) until all virtual registers are `IsStable`, to handle SSA phi-nodes and other circular dependencies.

### `BitValue` — the information lattice

`BitValue` (`Mosa.Compiler.Framework/BitValue.cs`) tracks what is known about a virtual register's value at compile time. All mutations are monotone — they can only **narrow** the range, never widen it.

Key properties:

| Property | Type | Meaning |
|---|---|---|
| `BitsSet` / `BitsSet32` | `ulong` / `uint` | Bits that are definitely 1 |
| `BitsClear` / `BitsClear32` | `ulong` / `uint` | Bits that are definitely 0 |
| `BitsKnown` | `ulong` | `BitsSet \| BitsClear` — union of all known bits |
| `MinValue` / `MaxValue` | `ulong` | Inclusive unsigned value range |
| `Is32Bit` / `Is64Bit` | `bool` | Whether this is a 32-bit or 64-bit register |
| `IsResolved` | `bool` | True when `MinValue == MaxValue` or all bits are known |
| `IsStable` | `bool` | True when no further narrowing is expected |
| `AreLower32BitsKnown` | `bool` | All 32 low bits known |
| `AreAll64BitsKnown` | `bool` | All 64 bits known |
| `IsZero` / `IsOne` / `IsZeroOrOne` | `bool` | Convenience predicates |

Key mutation methods (all return `this` for fluent chaining):

```csharp
result.SetValue(ulong value) // Set exact known constant
result.SetValue(bool value) // Set 0 or 1
result.NarrowMin(ulong min) // Raise the lower bound
result.NarrowMax(ulong max) // Lower the upper bound
result.NarrowSetBits(ulong bits) // Intersect known-set bits
result.NarrowClearBits(ulong bits) // Intersect known-clear bits
result.NarrowToBoolean() // Constrain to {0, 1}: MaxValue=1, BitsClear=~1ul
result.Narrow(BitValue other) // Apply all narrowing from another BitValue
result.SetStable() // Mark as stable (unconditionally)
result.SetStable(BitValue a) // Mark stable only if `a` is stable
result.SetStable(BitValue a, b) // Mark stable only if both are stable
result.SetStable(BitValue a, b, c) // Mark stable only if all three are stable
```

Constructors:
```csharp
new BitValue(bool is32Bit) // Unresolved, unstable
new BitValue(bool is32Bit, ulong value) // Fully known constant, stable
```

### `IntegerTwiddling` — overflow/carry predicates

`IntegerTwiddling` (`Mosa.Compiler.Common/IntegerTwiddling.cs`) provides all carry/overflow detection used by `BitTrackerOperations`.

| Method | Semantics |
|---|---|
| `IsAddUnsignedCarry(uint a, uint b)` | `a + b` overflows 32-bit unsigned |
| `IsAddUnsignedCarry(ulong a, ulong b)` | `a + b` overflows 64-bit unsigned |
| `IsAddUnsignedCarry(uint a, uint b, bool carry)` | `a + b + carry` overflows 32-bit unsigned |
| `IsAddSignedOverflow(int a, int b)` | `a + b` overflows 32-bit signed |
| `IsAddSignedOverflow(long a, long b)` | `a + b` overflows 64-bit signed |
| `IsSubUnsignedCarry(uint a, uint b)` | `b > a` (borrow: unsigned subtraction underflows) |
| `IsSubUnsignedCarry(ulong a, ulong b)` | `b > a` (borrow: 64-bit) |
| `IsSubSignedOverflow(int a, int b)` | **`a + b` signed overflow** — note: despite the name, this checks signed overflow for the equivalent addition `a + b`, consistent with how x86/x64 OF is computed for SUB. Use it for `SubOverflowOut` instructions. |
| `IsSubSignedOverflow(long a, long b)` | Same, 64-bit |

> **Important gotcha**: `IsSubSignedOverflow(a, b)` does **not** test whether `a - b` overflows in the intuitive sense. It tests whether `a + b` overflows signed, which matches the hardware overflow flag for subtraction. So `IsSubSignedOverflow(int.MinValue, -1)` returns `true` (int.MinValue + (-1) underflows), while `IsSubSignedOverflow(int.MaxValue, -1)` returns `false`.
Comment on lines +310 to +313

### Dual-result instructions

Instructions with two result operands (`result` = value, `result2` = flag) use a dedicated `BitTrackerOperations` method with signature:

```csharp
public static void XxxOut32(BitValue result, BitValue result2, BitValue value1, BitValue value2)
```

The handler in `BitTrackerStage` passes both result `BitValue`s:

```csharp
private static void AddCarryOut32(Node node)
{
BitTrackerOperations.AddCarryOut32(node.Result.BitValue, node.Result2.BitValue,
node.Operand1.BitValue, node.Operand2.BitValue);
}
```

The flag (`result2`) is modelled at three levels of precision:
1. **Both operands fully known** → compute exact flag value with `result2.SetValue(bool)`
2. **Range analysis proves flag impossible** → `result2.SetValue(0)`
3. **Range analysis proves flag certain** → `result2.SetValue(1)`
4. **Uncertain** → `result2.NarrowToBoolean().SetStable(value1, value2)`

Currently registered dual-result instructions and their flag semantics:

| Instruction | `result2` flag | Detection method |
|---|---|---|
| `AddCarryOut32/64` | Unsigned carry from addition | `IsAddUnsignedCarry` |
| `AddOverflowOut32/64` | Signed overflow from addition | `IsAddSignedOverflow` |
| `SubCarryOut32/64` | Unsigned borrow from subtraction (`op2 > op1`) | `IsSubUnsignedCarry` |
| `SubOverflowOut32/64` | Signed overflow (via `IsSubSignedOverflow`, which checks `a+b` signed overflow) | `IsSubSignedOverflow` |

### Adding a new `BitTrackerOperations` entry

1. Add a `public static void` method to `BitTrackerOperations.cs`. Single-result instructions receive `(BitValue result, BitValue value1, ...)`. Dual-result instructions receive `(BitValue result, BitValue result2, BitValue value1, ...)`.
2. Add a private static dispatch method in `BitTrackerStage.cs` that unpacks the `Node` and calls the operation.
3. Register the dispatch method in `BitTrackerStage.Initialize()` with `Register(IR.InstructionName, MethodName)`.
4. Add a corresponding xUnit test class to `Mosa.Compiler.Framework.xUnit/BitTrackerOperationsTests.cs`. Each class is named `BitTracker_<InstructionName>Tests`. Cover: both operands fully known (no-flag case and flag case), zero/identity operands, range provably no-flag, range always-flag, uncertain range, min/max narrowing.

### Standard operation pattern

```csharp
public static void Add32(BitValue result, BitValue value1, BitValue value2)
{
if (value1.AreLower32BitsKnown && value2.AreLower32BitsKnown)
{
result.SetValue(value1.BitsSet32 + value2.BitsSet32); // exact constant
}
else if (value1.AreLower32BitsKnown && value1.BitsSet32 == 0)
{
result.Narrow(value2).SetStable(value2); // identity: 0 + x = x
}
else if (!IntegerTwiddling.IsAddUnsignedCarry((uint)value1.MaxValue, (uint)value2.MaxValue))
{
result // range: no overflow possible
.NarrowMin(value1.MinValue + value2.MinValue)
.NarrowMax(value1.MaxValue + value2.MaxValue)
.SetStable(value1, value2);
}
else
{
result.SetStable(value1, value2); // unknown, just mark stable
}
}
```

---

Expand Down
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
[b]in - Copy/
[b]in - Copy (2)/
[b]in2/
/[Tt]emp
/[Tt]mp

*.[Oo]bj
*.suo
Expand Down Expand Up @@ -52,8 +54,6 @@ MigrationBackup/
/Source/*/Properties/launchSettings.json
stderr.txt
stdout.txt

/docs/CNAME
false

# Launcher output
false
1 change: 1 addition & 0 deletions Source/.github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ When adding new files to existing projects:
5. If adding a new compiler transform, inherit from `BaseTransform` and register it in the appropriate stage.
6. If adding new unit tests (xUnit), add them to `Mosa.Compiler.Common.xUnit` or `Mosa.Compiler.Framework.xUnit`.
7. If adding new bare-metal test cases, add them to `Mosa.UnitTests` following the existing pattern with `[MosaUnitTest]` attributes.
8. If adding a new setting to `MosaSettings` or `CommandLineArguments`, also add the corresponding entry to `Docs/command-line-arguments.rst`.

---

Expand Down
2 changes: 1 addition & 1 deletion Source/Data/IR-Optimizations-ConstantFolding.json
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@
"Type": "ConstantFolding",
"Name": "ConvertU32ToR#",
"SubName": "",
"Expression": "IR.ConvertI32ToR# a",
"Expression": "IR.ConvertU32ToR# a",
"Filter": "IsResolvedConstant(a)",
"Result": "(IR.MoveR# [ToR#(To32(a))])",
"Priority": "100"
Expand Down
4 changes: 2 additions & 2 deletions Source/Data/IR-Optimizations-StrengthReduction-Complex.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"SubName": "RemUnsigned",
"Expression": "IR.Compare32x## {==} (IR.RemUnsigned## a 2) 0",
"Filter": "",
"Result": "(IR.And## a [To##(1)])",
"Result": "(IR.And## (IR.Not## a) [To##(1)])",
"Variations": "Yes"
},
{
Expand All @@ -48,7 +48,7 @@
"SubName": "RemUnsigned",
"Expression": "IR.Compare64x## {==} (IR.RemUnsigned## a 2) 0",
"Filter": "",
"Result": "(IR.And## a [To##(1)])",
"Result": "(IR.And## (IR.Not## a) [To##(1)])",
"Variations": "Yes"
},
{
Expand Down
Loading
Loading