避免 ASM 中灵活的第二个操作数的硬数字移位
Avoiding hard-number shift of flexible second operand in ASM
此问题与 ARM
汇编语言有关。
我的问题是是否可以使用宏来替换 ASM 代码中的立即值来移位寄存器值,这样我就不必对数字进行硬编码。
我不确定上面的问题是否有意义,所以我将提供一些asm
代码的示例:
所以在ARM
(https://developer.arm.com/documentation/dui0473/m/arm-and-thumb-instructions/ror)中存在很少的指令,例如ror
指令,其中可以使用寄存器值按照我们的意愿旋转值:
#define rotate(number, ptr) ({ \
asm volatile( \
"ror %[output], %[output], %1\n" \
: [output]"+r"(ptr) \ // this is the in/output
: "r"(number)); \ // this is the rotator
})
现在,让我们看一下ARM
(https://developer.arm.com/documentation/dui0473/m/arm-and-thumb-instructions/orr)中的orr
指令。
语法如下:ORR{S}{cond} Rd, Rn, Operand2
其中 Operand2
是一个灵活的操作数,这意味着它可以是 constant
或 a register with optional shift
(来源:https://www.keil.com/support/man/docs/armasm/armasm_dom1361289851539.htm)
所以这样的事情会起作用:
#define orr_test(ptr) ({ \
uint64_t __result; \
asm volatile (\
"orr %0, %1, #4 << 60\n"\
: "=r" (__result) : "r" (ptr)); \
__result; \
})
但是,我怀疑 "orr %0, %0, #4 << 60\n"\
行中的 #4
是否可以以某种方式用宏替换,这样我就不必费力了代码 #4
。我认为这是不可能的(因为如果管理不当可能会导致大问题),但我仍然想问一下,因为我在网上找不到任何相关信息。
如果我上面提到的任何地方不清楚,请告诉我;谢谢。
编辑(根据要求):
这基本上是我希望在伪代码方面可能实现的内容:
#define orr_test(ptr, number) ({ \
uint64_t __result; \
asm volatile (\
"orr %0, %1, %[num] << 60\n"\
: "=r" (__result) : "r" (ptr), [num]"r"(number)); \
__result; \
})
换句话说,我不想用 shift 硬编码 #4
,而是希望使用宏来确定要移动的数字。
ARM64 orr
立即数指令采用 位掩码立即数 ,请参阅 for an explanation. And GCC has a constraint 了解此类操作数:L
。
所以我会写:
#define MASK (4UL << 60)
inline uint64_t set_bit(uint64_t x) {
uint64_t result;
asm("orr %0, %1, %2"
: "=r" (result)
: "r" (x), "L" (MASK));
return result;
}
我做了一些其他修复/改进:
您对 orr
的目标操作数和第一个源操作数都使用了 %0
,只有当幸运的是编译器为 [=15 选择了相同的寄存器时才有效=] 和 result
,它不需要这样做。您应该使用匹配 x
输入的操作数,这里是 %1
。如果编译器发现有利的话,它仍然可以自由地为两者选择相同的寄存器(在其他不合适的设置中,您可以使用 &
modifier)抑制它。
尽可能使用内联函数而不是宏。
请注意,如果您将 MASK
的值更改为不可编码为位掩码立即数的值,例如#define MASK (4UL << 60 | 1)
,你会得到一个编译错误。如果您想让它继续工作,您可以将 L
约束更改为 Lr
。如果表达式 MASK
是一个编译时常量,其值适合位掩码立即数,编译器将继续发出立即数。如果不是,它将发出额外的代码以将值加载到寄存器中,然后发出带有寄存器操作数的 orr
。 Try it.
(当然,这个例子对于内联 asm 来说是愚蠢的。GCC 生成 perfectly good code for the C equivalent return x | MASK;
. But I presume it was an example for some more complex code. Even so, you could think about whether the |
operation could be factored out, and just used as an input for whatever really needs to be in asm. As usual, always consider whether don't use inline asm 可能适用。)
此问题与 ARM
汇编语言有关。
我的问题是是否可以使用宏来替换 ASM 代码中的立即值来移位寄存器值,这样我就不必对数字进行硬编码。
我不确定上面的问题是否有意义,所以我将提供一些asm
代码的示例:
所以在ARM
(https://developer.arm.com/documentation/dui0473/m/arm-and-thumb-instructions/ror)中存在很少的指令,例如ror
指令,其中可以使用寄存器值按照我们的意愿旋转值:
#define rotate(number, ptr) ({ \
asm volatile( \
"ror %[output], %[output], %1\n" \
: [output]"+r"(ptr) \ // this is the in/output
: "r"(number)); \ // this is the rotator
})
现在,让我们看一下ARM
(https://developer.arm.com/documentation/dui0473/m/arm-and-thumb-instructions/orr)中的orr
指令。
语法如下:ORR{S}{cond} Rd, Rn, Operand2
其中 Operand2
是一个灵活的操作数,这意味着它可以是 constant
或 a register with optional shift
(来源:https://www.keil.com/support/man/docs/armasm/armasm_dom1361289851539.htm)
所以这样的事情会起作用:
#define orr_test(ptr) ({ \
uint64_t __result; \
asm volatile (\
"orr %0, %1, #4 << 60\n"\
: "=r" (__result) : "r" (ptr)); \
__result; \
})
但是,我怀疑 "orr %0, %0, #4 << 60\n"\
行中的 #4
是否可以以某种方式用宏替换,这样我就不必费力了代码 #4
。我认为这是不可能的(因为如果管理不当可能会导致大问题),但我仍然想问一下,因为我在网上找不到任何相关信息。
如果我上面提到的任何地方不清楚,请告诉我;谢谢。
编辑(根据要求):
这基本上是我希望在伪代码方面可能实现的内容:
#define orr_test(ptr, number) ({ \
uint64_t __result; \
asm volatile (\
"orr %0, %1, %[num] << 60\n"\
: "=r" (__result) : "r" (ptr), [num]"r"(number)); \
__result; \
})
换句话说,我不想用 shift 硬编码 #4
,而是希望使用宏来确定要移动的数字。
ARM64 orr
立即数指令采用 位掩码立即数 ,请参阅 L
。
所以我会写:
#define MASK (4UL << 60)
inline uint64_t set_bit(uint64_t x) {
uint64_t result;
asm("orr %0, %1, %2"
: "=r" (result)
: "r" (x), "L" (MASK));
return result;
}
我做了一些其他修复/改进:
您对
orr
的目标操作数和第一个源操作数都使用了%0
,只有当幸运的是编译器为 [=15 选择了相同的寄存器时才有效=] 和result
,它不需要这样做。您应该使用匹配x
输入的操作数,这里是%1
。如果编译器发现有利的话,它仍然可以自由地为两者选择相同的寄存器(在其他不合适的设置中,您可以使用&
modifier)抑制它。尽可能使用内联函数而不是宏。
请注意,如果您将 MASK
的值更改为不可编码为位掩码立即数的值,例如#define MASK (4UL << 60 | 1)
,你会得到一个编译错误。如果您想让它继续工作,您可以将 L
约束更改为 Lr
。如果表达式 MASK
是一个编译时常量,其值适合位掩码立即数,编译器将继续发出立即数。如果不是,它将发出额外的代码以将值加载到寄存器中,然后发出带有寄存器操作数的 orr
。 Try it.
(当然,这个例子对于内联 asm 来说是愚蠢的。GCC 生成 perfectly good code for the C equivalent return x | MASK;
. But I presume it was an example for some more complex code. Even so, you could think about whether the |
operation could be factored out, and just used as an input for whatever really needs to be in asm. As usual, always consider whether don't use inline asm 可能适用。)