2

我正在将代码从 C# 转换为 IL(CIL/MSIL 等)。我坚持使用条件,因为我希望能够存储到下一个可用的免费位置。例子:

var x = 0;
if(x > 20)
 x = 1;

Console.WriteLine(x);

如果我将其转换为我认为正确的 IL,我会得到:

IL_0001:  ldc.i4.0    
IL_0002:  stloc.0     
IL_0003:  ldloc.0     
IL_0004:  ldc.i4.s    14 
IL_0006:  cgt         
IL_0008:  ldc.i4.0    
IL_0009:  ceq         
IL_000B:  stloc.1     
IL_000C:  ldloc.1     
IL_000D:  brtrue.s    IL_0011
IL_000F:  ldc.i4.1    
IL_0010:  stloc.0     
IL_0011:  ldloc.0     
IL_0012:  call        System.Console.WriteLine

我相信这是正确的 IL,但我的例子是非常静态的。如果您在 IL 代码中看到,它将 ceq 的结果存储到 loc.1

这就是我的问题——编译器看到 loc.0 已被占用(变量“x”)并使用下一个空闲位置,即 1。我的目标是在给定方法可能有 N 个变量的情况下动态执行此操作在条件句之前。

所以,最后,这是我的问题:我如何从 C# 发出一个操作码来说“ stloc.nextAvailable ”并且它是等效的负载?

4

2 回答 2

3

stloc并且ldloc只能使用恒定索引。然而,这并不是一件坏事——这意味着如果你发出了其他代码,你已经有了下一个可用的索引,或者如果你以某种方式在其他地方获取了代码,你所要做的就是取所有本地索引的最大值并添加一个(或者从方法头中读取本地人的数量,如果有的话)。

或者您可以跳过本地并cgt直接使用(使用 a brfalse)的结果,或者使用ble指令。那么这个问题甚至一开始都没有出现。

于 2012-06-20T00:20:58.307 回答
2

在我看来,您正在查看在为调试模式编译时生成的 IL,stloc.1并且ldloc.1正在引用一个在您的代码中不存在但可以创建以在将鼠标悬停在大于符号上时提供漂亮的小工具提示的本地调试。

我希望发布模式生成的 IL 看起来更像这样(如果它不Console.WriteLine(0);提前优化整个事情):

//load the 4-byte integer 0 on to the stack
IL_0001:    ldc.i4.0
//set the value of local 0 (x) to the previous value on the stack (0)
IL_0002:    stloc.0
//load up x for the comparison
IL_0003:    ldloc.0
//load the 4-byte integer 0x14 (20) on to the stack
IL_0004:    ldc.i4.s    14
//check to see whether two elements back on the stack is greater than one element back on the stack (x > 20), push 1 one back on the stack in the case the first is greater, 0 otherwise
IL_0005:    cgt
//if 0x14 (20) was the greater (or equal) value, jump over the body of the if block
IL_0006:    brfalse.s    IL_0009
//load the 4-byte integer 1 (1) on to the stack
IL_0007:    ldc.i4.1
//set the value of local 0 (x) to the previous value on the stack (1)
IL_0008:    stloc.0
//load the value of local 0 (x) on to the stack
IL_0009:    ldloc.0
//call Console.WriteLine
IL_000A:    call    System.Console.WriteLine
于 2012-06-20T08:55:46.813 回答