Skip to content

Commit f4fc8ab

Browse files
Copilotdadhi
andauthored
Drop ConditionalWeakTable general backward-branch optimizer, keep only ad-hoc short-form branches
Agent-Logs-Url: https://github.com/dadhi/FastExpressionCompiler/sessions/20368e58-840b-428b-b785-c852cbfd5438 Co-authored-by: dadhi <39516+dadhi@users.noreply.github.com>
1 parent 4692876 commit f4fc8ab

3 files changed

Lines changed: 6 additions & 68 deletions

File tree

src/FastExpressionCompiler/FastExpressionCompiler.cs

Lines changed: 2 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -8372,50 +8372,6 @@ public static class ILGeneratorTools
83728372
/// <summary>Configuration option to disable the ILGenerator Emit debug output</summary>
83738373
public static bool DisableDemit;
83748374

8375-
// Tracks the IL offset of each marked label per ILGenerator, used by smart branch emitters to select short form when possible
8376-
internal static readonly ConditionalWeakTable<ILGenerator, Dictionary<Label, int>> _ilLabelPositions =
8377-
new ConditionalWeakTable<ILGenerator, Dictionary<Label, int>>();
8378-
8379-
// Maps a long-form branch opcode to its short-form equivalent, or returns the same opcode if no short form exists
8380-
[MethodImpl((MethodImplOptions)256)]
8381-
private static OpCode GetShortFormBranchOpCode(OpCode longFormOpCode)
8382-
{
8383-
if (longFormOpCode == OpCodes.Br) return OpCodes.Br_S;
8384-
if (longFormOpCode == OpCodes.Brtrue) return OpCodes.Brtrue_S;
8385-
if (longFormOpCode == OpCodes.Brfalse) return OpCodes.Brfalse_S;
8386-
if (longFormOpCode == OpCodes.Beq) return OpCodes.Beq_S;
8387-
if (longFormOpCode == OpCodes.Bne_Un) return OpCodes.Bne_Un_S;
8388-
if (longFormOpCode == OpCodes.Blt) return OpCodes.Blt_S;
8389-
if (longFormOpCode == OpCodes.Blt_Un) return OpCodes.Blt_Un_S;
8390-
if (longFormOpCode == OpCodes.Bgt) return OpCodes.Bgt_S;
8391-
if (longFormOpCode == OpCodes.Bgt_Un) return OpCodes.Bgt_Un_S;
8392-
if (longFormOpCode == OpCodes.Ble) return OpCodes.Ble_S;
8393-
if (longFormOpCode == OpCodes.Ble_Un) return OpCodes.Ble_Un_S;
8394-
if (longFormOpCode == OpCodes.Bge) return OpCodes.Bge_S;
8395-
if (longFormOpCode == OpCodes.Bge_Un) return OpCodes.Bge_Un_S;
8396-
return longFormOpCode; // no short form available
8397-
}
8398-
8399-
// Returns the short-form opcode if the label is already marked (backward branch) and the branch delta fits in a signed byte.
8400-
// The delta is computed from the end of the short-form instruction (ILOffset + 2) to the target label position.
8401-
[MethodImpl((MethodImplOptions)256)]
8402-
private static bool TryGetShortFormOpCodeForBackwardBranch(ILGenerator il, OpCode opcode, Label label, out OpCode shortFormOpCode)
8403-
{
8404-
shortFormOpCode = GetShortFormBranchOpCode(opcode);
8405-
if (shortFormOpCode != opcode &&
8406-
_ilLabelPositions.TryGetValue(il, out var positions) &&
8407-
positions.TryGetValue(label, out var labelOffset))
8408-
{
8409-
// Short form branch: 2 bytes total (1-byte opcode + 1-byte signed offset).
8410-
// The offset is relative to the start of the next instruction (ILOffset + 2).
8411-
var delta = labelOffset - (il.ILOffset + 2);
8412-
if (delta >= -128 && delta <= 127)
8413-
return true;
8414-
}
8415-
shortFormOpCode = opcode;
8416-
return false;
8417-
}
8418-
84198375
#if DEMIT
84208376
[MethodImpl((MethodImplOptions)256)]
84218377
public static void Demit(this ILGenerator il, OpCode opcode, [CallerMemberName] string emitterName = "", [CallerLineNumber] int emitterLine = 0)
@@ -8475,13 +8431,6 @@ public static void Demit(this ILGenerator il, OpCode opcode, ConstructorInfo val
84758431
public static void Demit(this ILGenerator il, OpCode opcode, Label value,
84768432
[CallerArgumentExpression("value")] string valueName = null, [CallerMemberName] string emitterName = null, [CallerLineNumber] int emitterLine = 0)
84778433
{
8478-
if (TryGetShortFormOpCodeForBackwardBranch(il, opcode, value, out var emitOpCode))
8479-
{
8480-
il.Emit(emitOpCode, value);
8481-
if (DisableDemit) return;
8482-
Debug.WriteLine($"{emitOpCode} {valueName ?? value.ToString()} -- {emitterName}:{emitterLine}");
8483-
return;
8484-
}
84858434
il.Emit(opcode, value);
84868435
if (DisableDemit) return;
84878436
Debug.WriteLine($"{opcode} {valueName ?? value.ToString()} -- {emitterName}:{emitterLine}");
@@ -8502,8 +8451,6 @@ public static void DmarkLabel(this ILGenerator il, Label value,
85028451
[CallerArgumentExpression("value")] string valueName = null, [CallerMemberName] string emitterName = null, [CallerLineNumber] int emitterLine = 0)
85038452
{
85048453
il.MarkLabel(value);
8505-
// Track the label position for smart branch selection (used by Demit with Label to select short form for backward branches)
8506-
_ilLabelPositions.GetOrCreateValue(il)[value] = il.ILOffset;
85078454
if (DisableDemit) return;
85088455
Debug.WriteLine($"MarkLabel: {valueName ?? value.ToString()} -- {emitterName}:{emitterLine}");
85098456
}
@@ -8590,19 +8537,13 @@ public static void Demit(this ILGenerator il, string value, OpCode opcode, [Call
85908537
public static void Demit(this ILGenerator il, OpCode opcode, ConstructorInfo value) => il.Emit(opcode, value);
85918538

85928539
[MethodImpl((MethodImplOptions)256)]
8593-
public static void Demit(this ILGenerator il, OpCode opcode, Label value) =>
8594-
il.Emit(TryGetShortFormOpCodeForBackwardBranch(il, opcode, value, out var shortForm) ? shortForm : opcode, value);
8540+
public static void Demit(this ILGenerator il, OpCode opcode, Label value) => il.Emit(opcode, value);
85958541

85968542
[MethodImpl((MethodImplOptions)256)]
85978543
public static void DemitSwitch(this ILGenerator il, Label[] gotoLabels) => il.Emit(OpCodes.Switch, gotoLabels);
85988544

85998545
[MethodImpl((MethodImplOptions)256)]
8600-
public static void DmarkLabel(this ILGenerator il, Label value)
8601-
{
8602-
il.MarkLabel(value);
8603-
// Track the label position for smart branch selection (used by Demit with Label to select short form for backward branches)
8604-
_ilLabelPositions.GetOrCreateValue(il)[value] = il.ILOffset;
8605-
}
8546+
public static void DmarkLabel(this ILGenerator il, Label value) => il.MarkLabel(value);
86068547

86078548
[MethodImpl((MethodImplOptions)256)]
86088549
public static void Demit(this ILGenerator il, OpCode opcode, byte value) => il.Emit(opcode, value);
@@ -8652,9 +8593,6 @@ public static ILGenerator RentPooledOrNewILGenerator(DynamicMethod dynMethod, Ty
86528593
if (pooledIL != null)
86538594
{
86548595
reuseILGenerator(dynMethod, pooledIL, returnType, paramTypes);
8655-
// Clear any stale label positions from the previous compilation to prevent incorrect branch optimization
8656-
if (ILGeneratorTools._ilLabelPositions.TryGetValue(pooledIL, out var positions))
8657-
positions.Clear();
86588596
return pooledIL;
86598597
}
86608598
else

test/FastExpressionCompiler.IssueTests/Issue498_InvalidProgramException_when_using_loop.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ public void Original_test(TestContext t)
9696
OpCodes.Ldc_I4_1, // at IL_0024
9797
OpCodes.Add, // at IL_0025
9898
OpCodes.Stloc_1, // at IL_0026
99-
OpCodes.Br_S, // IL_0000 at IL_0027 (short backward branch: fits in sbyte)
100-
OpCodes.Br_S, // IL_0000 at IL_002A (short backward branch: fits in sbyte)
101-
OpCodes.Ret // at IL_002C
99+
OpCodes.Br, // IL_0000 at IL_0027
100+
OpCodes.Br, // IL_0000 at IL_0032
101+
OpCodes.Ret // at IL_0037
102102
);
103103

104104
calResult = ff();

test/FastExpressionCompiler.LightExpression.IssueTests/Issue346_Is_it_possible_to_implement_ref_local_variables.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ public void Real_world_test_ref_array_element()
616616
OpCodes.Stloc_1,
617617
OpCodes.Br, //60
618618
OpCodes.Br, //65
619-
OpCodes.Br_S, //10 (short backward branch: loop back-jump fits in sbyte)
619+
OpCodes.Br, //10
620620
OpCodes.Ldloc_0,
621621
OpCodes.Ret
622622
);

0 commit comments

Comments
 (0)