ARM MOV和MVN操作 [英] ARM MOV and MVN operand
问题描述
我想写code做两件事情:返回一个1到寄存器R2如果我的值是presentable作为ARM数据处理指令中的常数。这code这是否(提供更好的方法,如果它是低效率的,请)。不过,我也想修改它告诉我MOV或MVN是否需要使用。
区域ArmExample18b,code 条目
MOV R2,#0;注册返回值。如果= 1,再presentable,否则,不会再presentable
LDR R1,TABLE1;输入值,我们要使用
LDR R3,TABLE1 + 4;上限寄存器
LDR R4,TABLE1 + 8;下界寄存器
MOV R5,#12INVCHECK CLZ R6,R1,R6包含R1前导零的数
RBIT R7,R1
CLZ R8,R7,R8包含R1尾随零的数
CMP R6,R8
SUBCS R9,R6,R8
RSBCC R9,R6,R8
CMP R9,#8
MVNHI R1,R1
BHI INVCHECK
BLS LOOP
循环
CMP R3,R1;比较上限输入值
BLO STOP;如果不是u.b更大,停止,R2 = 0
CMP R4,R1;与下界比较输入值
MOVLS R2,#1;如果大于下限,它落入在范围内,设定R2 = 1
BLS STOP;然后停止
CMP R4,#0;若R4已达到0,那么我们在比较的结束,并且可以停止
BEQ STOP
LDR R3,TABLE1 + R5;改变上限
ADD R5,R5,#4
LDR R4,TABLE1 + R5;改变下界
ADD R5,R5,#4
乙LOOP
STOP B STOP
TABLE1 DCD量0x500,0x3fc0,为0x1000,量0xFF0,0x400的,0x3FC中,为0x100,为0xFF,0 结束
不过,我也想修改它告诉我MOV或MVN是否需要使用。
块引用>测试了
MOV
情况。如果没有,用于测试的MVN
的情况下,并设置标志(或任何你想要的API)。人们常常用+1(MOV),0(不适合)-1(MVN),因为这可能是好的,在主叫方纯ARM测试。被完全懵了,我开始调查的气体(GNU汇编器)是什么。我发现的 TC-arm.c在一个名为常规
连接code_arm_immediate()
。这里是源,/ *如果VAL可以连接codeD在ARM指令的立即字段,
返回EN codeD形式。否则,返回FAIL。 * /静态无符号整型
EN code_arm_immediate(无符号整数VAL)
{
unsigned int类型A,I; 对于(I = 0; I&下; 32; I + = 2)
如果((α= rotate_left(VAL,我))≤= 0xff的)
返回| (ⅰ&所述; 7;); / * 12位包:[SHIFT-CNT,常量。 * / 返回失败;
}一些有趣的点。这是不喜欢你的例子非常有效的,但它是更正确。我不认为你正在处理像常量的 0xf000000f 的可重新presented。此外,在
move_or_literal_pool的code()
在同一文件中有这样的伪code,IF((包装= EN code_arm_immediate(VAL))== FAIL)
包装= EN code_arm_immediate(〜VAL);这是pretty显然,如果你有
MOV
A测试,可以补充和测试MVN
。其实,我不认为你会试图通过测试每个并行因为你太复杂逻辑更有效。目前的步骤可以用一个指令来最小化找到的第一套位(CLZ
),因为你并不需要遍历所有的位[见<一href=\"http://stackoverflow.com/questions/15736602/fastest-way-to-count-number-of-1s-in-a-register-arm-assembly\">pop_count()].位= pop_count(VAL);
如果(比特下; = 8){
/ *搜索'MOV'* /使用CLZ正常化* /
移= CLZ(VAL);
VAL =&LT;&LT;转移;
如果((VAL&放大器; 0xff的&所述;&下; 24 == VAL)及&放大器;!移&放大器; 1)转到它。
如果((VAL&放大器; 0xFE的&所述;&下; 24 == VAL)及&放大器;移&放大器; 1)转到它。
/ *测试旋转* /
}
如果(位&GT; = 32-8){
/ *设置MVN'标志* /
/* 如上 */
}有实施的人口数的和/或数字的运行各种方式。真的,如果你的算法是的正确并处理旋转,简单的
连接code_arm_immediate()
好像它的简单性最终会被很有竞争力的到尝试使用高级指令检测位运行的任何解决方案。在连接code_arm_immediate()
将适合在高速缓存和循环将迅速上的ARMv7与高速缓存和分支prediction运行。I'm trying to write code to do two things: return a 1 to register r2 if my value is presentable as a constant in the ARM data processing instruction. This code does that (offer better methods if it's inefficient please). However, I also want to modify it to tell me whether a MOV or MVN needs to be used.
AREA ArmExample18b, CODE ENTRY MOV r2, #0 ;register return value. if =1, representable, otherwise, not representable LDR r1, TABLE1 ;input value we want to use LDR r3, TABLE1+4 ;upper bound register LDR r4, TABLE1+8 ;lower bound register MOV r5, #12 INVCHECK CLZ r6, r1 ;r6 contains number of leading zeros in r1 RBIT r7, r1 CLZ r8, r7 ;r8 contains number of trailing zeros in r1 CMP r6, r8 SUBCS r9, r6, r8 RSBCC r9, r6, r8 CMP r9, #8 MVNHI r1, r1 BHI INVCHECK BLS LOOP LOOP CMP r3, r1 ;compare input value with upper bound BLO STOP ;if bigger than u.b, stop, r2 = 0 CMP r4, r1 ;compare input value with lower bound MOVLS r2, #1 ;if larger than lower bound, it falls within range, set r2 = 1 BLS STOP ;then stop CMP r4, #0 ;if r4 has reached 0, then we are at the end of comparisons and can stop BEQ STOP LDR r3, TABLE1 + r5 ;change upper bound ADD r5, r5, #4 LDR r4, TABLE1 + r5 ;change lower bound ADD r5, r5, #4 B LOOP STOP B STOP TABLE1 DCD 0x500, 0x3fc0, 0x1000, 0xff0, 0x400, 0x3fc, 0x100, 0xff, 0 END
解决方案However, I also want to modify it to tell me whether a MOV or MVN needs to be used.
Test for the
MOV
case. If no, test for theMVN
case and set a flag (or whatever your API wants). Often people use +1 (MOV), 0 (can not fit), -1 (MVN) as this might be nice to test in the caller pure ARM.
Being completely ignorant, I started by investigating what gas (GNU assembler does). I found the answer in tc-arm.c in a routine called
encode_arm_immediate()
. Here is the source,/* If VAL can be encoded in the immediate field of an ARM instruction, return the encoded form. Otherwise, return FAIL. */ static unsigned int encode_arm_immediate (unsigned int val) { unsigned int a, i; for (i = 0; i < 32; i += 2) if ((a = rotate_left (val, i)) <= 0xff) return a | (i << 7); /* 12-bit pack: [shift-cnt,const]. */ return FAIL; }
Some interesting points. It is not very efficient like your example, but it is more correct. I don't think you are handling constants like 0xf000000f which can be represented. Also, the code in
move_or_literal_pool()
in the same file has this pseudo code,if((packed = encode_arm_immediate(val)) == FAIL) packed = encode_arm_immediate(~val);
It is pretty clear that if you have a test for
MOV
, you can complement and test forMVN
. In fact, I don't think you will be more efficient by trying to test each in parallel as you complicate the logic too much. The current steps can be minimized with an instruction to find the first set bit (clz
) as you don't need to iterate over all of the bits [see pop_count()].bits = pop_count(val); if(bits <= 8) { /* Search 'MOV' */ using clz to normalize */ shift = clz(val); val =<< shift; if((val & 0xff<<24 == val) && !shift&1) goto it. if((val & 0xfe<<24 == val) && shift&1) goto it. /* test for rotation */ } if(bits >= 32-8) { /* Set 'MVN' flag */ /* as above */ }
There are various ways to implement a population count and/or run of numbers. Really, if your algorithm is correct and handles the rotation, the simple
encode_arm_immediate()
seems like it's simplicity will end up being very competitive to any solution that tries to use advanced instruction to detect runs of bits. Theencode_arm_immediate()
will fit in the cache and the loop will be running quickly on an ARMv7 with caches and branch prediction.这篇关于ARM MOV和MVN操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!