无法在 ARM 程序集中实现 C 逻辑
Unable to implement C Logic in ARM assembly
我有一个 C
代码想用 ARM
编程语言实现。
我心目中的 C 代码是这样的:
int a;
scanf("%d",&a);
if(a == 0 || a == 1){
a = 1;
}
else{
a = 2;
}
我尝试过的:
//arm equivalent of taking input to reg r0
//check for first condition
cmp r0,#1
moveq r0,#1
//if false
movne r0,#2
//check for second condition
cmp r0,#0
moveq r0,#1
这是正确的实施方式吗?
不,那行不通。
cmp r0,#1 is it a one
moveq r0,#1 yes, make it a one again?
movne r0,#2 otherwise make it a 2, what if it was a zero to start, now it is a 2
cmp r0,#0 at this point it is either a 1 or a 2 you forced it so it cannot be zero, what it started off is is now lost.
moveq r0,#1
您有正确的概念,但需要更好地订购。
尽管遵循这种思路
也许使用另一个寄存器
x = 2;
if(a==0) x = 1;
if(a==1) x = 1;
a = x;
思考这个
if(a==0) a = 1;
if(a!=1) a = 2;
或者像其他人所说的那样询问编译器。
由于 or、test OR 测试,通常它们需要单独完成第一个测试的 false 条件并不意味着您必须在声明 false 之前进行其他测试的 else 条件。但是如果为真,你需要跳过所有的东西而不是进入第二个测试,因为那可能(在这种情况下)是假的......
正如 Peter 指出的那样,您可以使用无符号小于或等于和大于条件(即使在 C 中它是一个带符号的 int,位是位)。
LS Unsigned lower or same
HI Unsigned higher
根据 ARM 指令集可以是:
cmp r0, #1
movls r0, #1
movhi r0, #2
bx lr
或
cmp r0, #1
ite ls
movls r0, #1
movhi r0, #2
bx lr
我比你聪明吗? NO 我只是简单地使用编译器来编译C代码。
https://godbolt.org/z/dqxv64Eb9
您的代码因 a=0
而损坏 - 在您的脑海中或在调试器中单步执行它,看看会发生什么。
鉴于此特定条件,它等同于 (unsigned)a <= 1U
(因为负整数会转换为巨大的无符号值)。您可以执行单个 cmp 和 movls
/ movhi
。编译器已经发现了这种优化; 以下是如何要求编译器为您制作 asm,这样您就可以学习聪明的人类编写的技巧:
int foo(int a) {
if(a == 0 || a == 1){
a = 1;
}
else{
a = 2;
}
return a;
}
使用 ARM GCC10 -O3 -marm on the Godbolt compiler explorer:
foo:
cmp r0, #1
movls r0, #1
movhi r0, #2
bx lr
有关制作具有有用的 asm 输出的函数的更多信息,请参阅 。在这种情况下,r0
是调用约定中的第一个参数传递寄存器,也是 return 值寄存器。
我还包含了另一个使用 if (a <= 1U)
的 C 版本,以表明它编译为相同的 asm。 (1U
是一个无符号常量,因此 C 整数提升规则将 a
隐式转换为 unsigned
,因此类型匹配 <=
运算符。您不需要显式执行(unsigned)a <= 1U
.)
一般情况:不是单一范围
对于像 a==0 || a==3
这样不是单一范围检查的情况,您可以 断言第二个 cmp
。 (Godbolt)
foo:
cmp r0, #3 # sets Z if a was 3
cmpne r0, #0 # leaves Z unmodified if it was already set, else sets it according to a == 0
moveq r0, #1
movne r0, #2
bx lr
您可以像 a==3 && b==4
一样链接 &&,或者对于像 a >= 3 && a <= 7
这样的检查,您可以使用 sub / cmp,使用与子映射后的 0 或 1 范围检查相同的无符号比较技巧 a
值到 0..n 范围内。请参阅 the Godbolt link。
我有一个 C
代码想用 ARM
编程语言实现。
我心目中的 C 代码是这样的:
int a;
scanf("%d",&a);
if(a == 0 || a == 1){
a = 1;
}
else{
a = 2;
}
我尝试过的:
//arm equivalent of taking input to reg r0
//check for first condition
cmp r0,#1
moveq r0,#1
//if false
movne r0,#2
//check for second condition
cmp r0,#0
moveq r0,#1
这是正确的实施方式吗?
不,那行不通。
cmp r0,#1 is it a one
moveq r0,#1 yes, make it a one again?
movne r0,#2 otherwise make it a 2, what if it was a zero to start, now it is a 2
cmp r0,#0 at this point it is either a 1 or a 2 you forced it so it cannot be zero, what it started off is is now lost.
moveq r0,#1
您有正确的概念,但需要更好地订购。
尽管遵循这种思路
也许使用另一个寄存器
x = 2;
if(a==0) x = 1;
if(a==1) x = 1;
a = x;
思考这个
if(a==0) a = 1;
if(a!=1) a = 2;
或者像其他人所说的那样询问编译器。
由于 or、test OR 测试,通常它们需要单独完成第一个测试的 false 条件并不意味着您必须在声明 false 之前进行其他测试的 else 条件。但是如果为真,你需要跳过所有的东西而不是进入第二个测试,因为那可能(在这种情况下)是假的......
正如 Peter 指出的那样,您可以使用无符号小于或等于和大于条件(即使在 C 中它是一个带符号的 int,位是位)。
LS Unsigned lower or same
HI Unsigned higher
根据 ARM 指令集可以是:
cmp r0, #1
movls r0, #1
movhi r0, #2
bx lr
或
cmp r0, #1
ite ls
movls r0, #1
movhi r0, #2
bx lr
我比你聪明吗? NO 我只是简单地使用编译器来编译C代码。 https://godbolt.org/z/dqxv64Eb9
您的代码因 a=0
而损坏 - 在您的脑海中或在调试器中单步执行它,看看会发生什么。
鉴于此特定条件,它等同于 (unsigned)a <= 1U
(因为负整数会转换为巨大的无符号值)。您可以执行单个 cmp 和 movls
/ movhi
。编译器已经发现了这种优化; 以下是如何要求编译器为您制作 asm,这样您就可以学习聪明的人类编写的技巧:
int foo(int a) {
if(a == 0 || a == 1){
a = 1;
}
else{
a = 2;
}
return a;
}
使用 ARM GCC10 -O3 -marm on the Godbolt compiler explorer:
foo:
cmp r0, #1
movls r0, #1
movhi r0, #2
bx lr
有关制作具有有用的 asm 输出的函数的更多信息,请参阅 r0
是调用约定中的第一个参数传递寄存器,也是 return 值寄存器。
我还包含了另一个使用 if (a <= 1U)
的 C 版本,以表明它编译为相同的 asm。 (1U
是一个无符号常量,因此 C 整数提升规则将 a
隐式转换为 unsigned
,因此类型匹配 <=
运算符。您不需要显式执行(unsigned)a <= 1U
.)
一般情况:不是单一范围
对于像 a==0 || a==3
这样不是单一范围检查的情况,您可以 断言第二个 cmp
。 (Godbolt)
foo:
cmp r0, #3 # sets Z if a was 3
cmpne r0, #0 # leaves Z unmodified if it was already set, else sets it according to a == 0
moveq r0, #1
movne r0, #2
bx lr
您可以像 a==3 && b==4
一样链接 &&,或者对于像 a >= 3 && a <= 7
这样的检查,您可以使用 sub / cmp,使用与子映射后的 0 或 1 范围检查相同的无符号比较技巧 a
值到 0..n 范围内。请参阅 the Godbolt link。