Skip to content

Instantly share code, notes, and snippets.

@shmolyneaux
Created September 22, 2018 19:26
Show Gist options
  • Save shmolyneaux/41fcbe62f4a989482c24e8ca6a889dea to your computer and use it in GitHub Desktop.
Save shmolyneaux/41fcbe62f4a989482c24e8ca6a889dea to your computer and use it in GitHub Desktop.
Transcription of Beautiful Code Chapter 8 IL Generation
void FilterMethodIL(byte[] src, byte[] dst, int stride, int bytesPerPixel)
{
int cBytes = src.Length;
DynamicMethod dynameth = new DynamicMethod("Go", typeof(void),
new Type[] { typeof(byte[]), typeof(byte[]) }, GetType());
ILGenerator generator = dynameth.GetILGenerator();
generator.DeclareLocal(typeof(int)); // Index 0 = iDst
generator.DeclareLocal(typeof(double)); // Index 1 = pixelsAccum
generator.DeclareLocal(typeof(double)); // Index 2 = filterAccum
generator.Emit(OpCodes.Ldc_I4_0);
generator.Emit(OpCodes.Stloc_0);
Label labelTop = generator.DefineLabel();
generator.MarkLabel(labelTop);
generator.Emit(OpCodes.Ldc_R8, 0.0);
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Stloc_2);
for (int iFilter = 0; iFilter < filter.Length; iFilter++)
{
if (filter[iFilter] == 0)
continue;
generator.Emit(OpCodes.Ldarg_0);
Label labelLessThanZero = generator.DefineLabel();
Label labelGreaterThan = generator.DefineLabel();
Label labelLoopBottom = generator.DefineLabel();
generator.Emit(OpCodes.Ldloc_0); // dst index on stack
generator.Emit(OpCodes.Ldc_I4, offset); // offset on stack
generator.Emit(OpCodes.Add); // Add the two
generator.Emit(OpCodes.Dup); // Duplicate twice
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldc_I4_0);
generator.Emit(OpCodes.Blt_S, labelLessThanZero);
generator.Emit(OpCodes.Ldc_I4, cBytes);
generator.Emit(OpCodes.Bge_S, labelGreaterThan);
generator.Emit(OpCodes.Ldelem_U1);
generator.Emit(OpCodes.Conv_R8);
if (filter[iFilter] == 1)
{
// src element is on stack, so do nothing
}
else if (filter[iFilter] == -1)
{
generator.Emit(OpCodes.Neg);
}
else
{
generator.Emit(OpCodes.Ldc_R8, filter[iFilter]);
generator.Emit(OpCodes.Mul);
}
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Add);
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Ldc_R8, filter[iFilter]);
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Add);
generator.Emit(OpCodes.Stloc_2);
generator.Emit(OpCodes.Br, labelLoopBottom);
generator.MarkLabel(labelLessThanZero);
generator.Emit(OpCodes.Pop);
generator.MarkLabel(labelGreaterThan);
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Pop);
generator.MarkLabel(labelLoopBottom);
}
generator.Emit(OpCodes.Ldarg_1); // dst array
generator.Emit(OpCodes.Ldloc_0); // iDst index
Label labelSkipDivide = generator.DefineLabel();
Label labelCopyQuotient = generator.DefineLabel();
Label labelBlack = generator.DefineLabel();
Label labelWhite = generator.DefineLabel();
Label labelDone = generator.DefineLabel();
generator.Emit(OpCodes.Ldloc_1); // pixelsAccum
generator.Emit(OpCodes.Ldloc_2); // filterAccum
generator.Emit(OpCodes.Dup); // Make a copy
generator.Emit(OpCodes.Ldc_R8, 0.0); // Put 0 on stack
generator.Emit(OpCodes.Beq_S, labelSkipDivide);
generator.Emit(OpCodes.Div);
generator.Emit(OpCodes.Br_S, labelCopyQuotient);
generator.MarkLabel(labelSkipDivide);
generator.Emit(OpCodes.Pop); // Pop filterAccum
generator.MarkLabel(labelCopyQuotient);
generator.Emit(OpCodes.Dup); // Make a copy of quotient
generator.Emit(OpCodes.Dup); // And another
generator.Emit(OpCodes.Ldc_R8, 0.0);
generator.Emit(OpCodes.Blt_S, labelBlack);
generator.Emit(OpCodes.Ldc_R8, 255.0);
generator.Emit(OpCodes.Bgt_S, labelWhite);
generator.Emit(OpCodes.Conv_U1);
generator.Emit(OpCodes.Br_S, labelDone);
generator.MarkLabel(labelBlack);
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldc_I4_S, 0);
generator.Emit(OpCodes.Br_S, labelDone);
generator.MarkLabel(labelWhite);
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldc_I4_S, 255);
generator.MarkLabel(labelDone);
generator.Emit(OpCodes.Stelem_I1);
generator.Emit(OpCodes.Ldloc_0); // Put iDst on stack
generator.Emit(OpCodes.Ldc_I4_1); // Put 1 on stack
generator.Emit(OpCodes.Add); // Add 1 to iDst
generator.Emit(OpCodes.Dup); // Duplicate
generator.Emit(OpCodes.Stloc_0); // Store result in iDst
generator.Emit(OpCodes.Ldc_I4, cBytes); // Put cBytes value on stack
generator.Emit(OpCodes.Blt, labelTop); // Go to top if iDst < cBytes
generator.Emit(OpCodes.Ret);
dynameth.Invoke(this, new object[] { src, dst });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment