[英]why always gcc makes jle/jg?
我编写了一些仅与字符进行比较的汇编测试代码,无论条件是否相等,gcc总是使jle / jg组合。
范例1。
如果('A'<测试&&测试<'Z')
0x000000000040054d <+32>: cmp BYTE PTR [rbp-0x1],0x41
0x0000000000400551 <+36>: jle 0x40056a <main+61>
0x0000000000400553 <+38>: cmp BYTE PTR [rbp-0x1],0x59
0x0000000000400557 <+42>: jg 0x40056a <main+61>
范例2。
如果('A'<=测试&&测试<='Z')
0x000000000040054d <+32>: cmp BYTE PTR [rbp-0x1],0x40
0x0000000000400551 <+36>: jle 0x40056a <main+61>
0x0000000000400553 <+38>: cmp BYTE PTR [rbp-0x1],0x5a
0x0000000000400557 <+42>: jg 0x40056a <main+61>
我认为这是关于优化的问题,但是即使我使用-O0选项进行编译,GCC也会给出相同的结果。
如何通过'A'<sth <'Z'获得JL / JG,如何通过'A'<= sth <='Z'获得JLE / JGE?
可以看到,第一个比较是在[x41 ... x59]范围内。 第二个比较是针对[x40 ... x5a]范围。 基本上,编译器使其成为
if ( 'A'-1 < test && test < 'Z'+1 )
然后生成相同的代码
更新
只是为了弄清楚为什么我认为编译器更喜欢JL和JLE。 JLE取决于要更新的标志值(ZF = 1),但JL不需要。 因此,即使指令时序本身相同,JLE也会引入可能会损害指令级并行性的依赖项
因此,明确选择-转换代码以使用更简单的指令。
通常,您不能强制编译器发出特定指令。 在这种情况下,如果您删除了常量,则编译器将无法对其进行调整,则可能会成功。 请注意,由于表达式的性质,编译器可能仍会逆转其中一个测试,从而带来一个相等。 您可能可以使用goto
解决该问题。 显然,这两个更改都会生成更糟糕的代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.