GCC将发出ARM idiv指令

11

我该如何指示gccarm应用处理器中发出idiv(整数除法,udivsdiv)指令?

目前我能想到的唯一方法是使用gcc 4.7的-mcpu=cortex-a15选项。

$cat idiv.c
int test_idiv(int a, int b) {
    return a / b;
}

在GCC 4.7上(随Android NDK r8e捆绑)

$gcc -O2 -mcpu=cortex-a15 -c idiv.c
$objdump -S idiv.o

00000000 <test_idiv>:
   0:   e710f110    sdiv    r0, r0, r1
   4:   e12fff1e    bx  lr

如果你在-mcpu=cortex-a15旁边添加-march=armv7-a,那么即使加了这个选项也会出现idiv.c:1:0: warning: switch -mcpu=cortex-a15 conflicts with -march=armv7-a switch [enabled by default],并且不会发出idiv指令。

$gcc -O2 -mcpu=cortex-a15 -march=armv7-a -c idiv.c

idiv.c:1:0: warning: switch -mcpu=cortex-a15 conflicts with -march=armv7-a switch [enabled by default]

$objdump -S idiv.o
00000000 <test_idiv>:
   0:   e92d4008    push    {r3, lr}
   4:   ebfffffe    bl  0 <__aeabi_idiv>
   8:   e8bd8008    pop {r3, pc}
在gcc 4.6 (随附于Android NDK r8e)中,它根本不会发出idiv指令,但识别-mcpu=cortex-a15并且也不会对-mcpu=cortex-a15 -march=armv7-a组合抱怨。
据我所知,在armv7上,idiv是可选的,因此应该有更简洁的方法来指示gcc发出它们,但是如何?

你确定有一个名为idiv的实际指令吗?我只能找到 sdiv(有符号除法)和 udiv(无符号除法)... - unwind
@unwind 我假设idiv = sdiv | udiv - auselen
你的目标是哪个 CPU?据我所知,Cortex-A15 支持 sdiv/udiv,但 Cortex-A5 不支持。两者都兼容 ARMv7-A。 - Austin Phillips
@AustinPhillips 没什么特别的,我只是想了解是否有一种方法可以告诉gcc溢出idiv指令而不是链接到__aeabi*的内容。一个例子可能是为支持idiv的模拟器构建Android堆栈。 - auselen
1
警告冲突看起来像是一个错误。只需不指定-march。请参见arm.c,第1644行。或者这个逻辑只是为了解决这种情况。由于您请求的CPUARCH更好,因此ARCH无效。我认为您只需要一个naked -mcpu=cortex-a7(或-mcpu=cortex-a15-mcpu=cortex-r5)来获取idiv;这些是唯一支持它并且比ARCH更好的CPU。 - artless noise
1个回答

7
如果指令不在“机器描述”中,则我怀疑GCC不会生成代码。如果编译器不支持该指令,则始终可以使用内联汇编来获取指令。由于您的操作码相当罕见/特定于机器,因此可能没有太多的努力将其放入GCC源代码中,特别是有"arch"和"tune/cpu"标志。 "tune/cpu"用于更具体的机器,但是"arch"应该允许该架构中的所有机器。如果我理解正确,这个操作码似乎违反了这个规则。
对于GCC 4.6.2,看起来"thumb2"和"cortex-r4"是使用这些指令的线索,正如您注意到的那样,对于GCC 4.7.2,"cortex-a15"似乎已添加以使用这些指令。在GCC 4.7.2中,"thumb2.md"文件不再包含"udiv" / "sdiv"。但是,它可能在其他地方被包含;我并不完全熟悉所有的"machine description"语言。似乎" cortex-a7", "cortex-a15" 和 "cortex-r5"也可以通过4.7.2启用这些指令。
这并没有直接回答问题,但它确实提供了一些获取答案的信息/路径。您可以使用"-mcpu=cortex-r4"编译模块,尽管这可能会产生链接器问题。此外,还有"int my_idiv(int a,int b)__attribute__ ((__target __(“arch=cortexe-r4”)))); ",其中您可以针对每个函数指定代码生成器使用的"machine-description"。我自己没有使用过任何这些内容,但它们只是要尝试的可能性。通常,您不希望保留错误的机器,因为它可能会生成次优(甚至可能是非法的)操作码。您将不得不进行实验,然后可能提供真正的答案。
注1:这适用于"stock" GCC 4.6.2和4.7.2。我不知道您的Android编译器是否有补丁。
gcc-4.6.2/gcc/config/arm$ grep [ius]div *.md
arm.md: "...,sdiv,udiv,other"
cortex-r4.md:;; We guess that division of A/B using sdiv or udiv, on average, 
cortex-r4.md:;; This gives a latency of nine for udiv and ten for sdiv.
cortex-r4.md:(define_insn_reservation "cortex_r4_udiv" 9
cortex-r4.md:       (eq_attr "insn" "udiv"))
cortex-r4.md:(define_insn_reservation "cortex_r4_sdiv" 10
cortex-r4.md:       (eq_attr "insn" "sdiv"))
thumb2.md:  "sdiv%?\t%0, %1, %2"
thumb2.md:   (set_attr "insn" "sdiv")]
thumb2.md:(define_insn "udivsi3"
thumb2.md:      (udiv:SI (match_operand:SI 1 "s_register_operand"  "r")
thumb2.md:  "udiv%?\t%0, %1, %2"
thumb2.md:   (set_attr "insn" "udiv")]

gcc-4.7.2/gcc/config/arm$ grep -i [ius]div *.md
arm.md:  "...,sdiv,udiv,other"
arm.md:  "TARGET_IDIV"
arm.md:  "sdiv%?\t%0, %1, %2"
arm.md:   (set_attr "insn" "sdiv")]
arm.md:(define_insn "udivsi3"
arm.md: (udiv:SI (match_operand:SI 1 "s_register_operand"  "r")
arm.md:  "TARGET_IDIV"
arm.md:  "udiv%?\t%0, %1, %2"
arm.md:   (set_attr "insn" "udiv")]
cortex-a15.md:(define_insn_reservation "cortex_a15_udiv" 9
cortex-a15.md:       (eq_attr "insn" "udiv"))
cortex-a15.md:(define_insn_reservation "cortex_a15_sdiv" 10
cortex-a15.md:       (eq_attr "insn" "sdiv"))
cortex-r4.md:;; We guess that division of A/B using sdiv or udiv, on average, 
cortex-r4.md:;; This gives a latency of nine for udiv and ten for sdiv.
cortex-r4.md:(define_insn_reservation "cortex_r4_udiv" 9
cortex-r4.md:       (eq_attr "insn" "udiv"))
cortex-r4.md:(define_insn_reservation "cortex_r4_sdiv" 10
cortex-r4.md:       (eq_attr "insn" "sdiv"))

Note2: 如果gcc传递选项给gas阻止使用udiv/sdiv指令,请参见预处理器作为汇编器。您可以使用asm(" .long <opcode>\n");,其中opcode是一些标记粘贴字符串化的寄存器编码宏输出。此外,您可以注释您的汇编代码以指定更改在machine中的情况。因此,您可以暂时虚假地说您有一个cortex-r4等。

Note3:

gcc-4.7.2/gcc/config/arm$ grep -E 'TARGET_IDIV|arm_arch_arm_hwdiv|FL_ARM_DIV' *
arm.c:#define FL_ARM_DIV    (1 << 23)         /* Hardware divide (ARM mode).  */
arm.c:int arm_arch_arm_hwdiv;
arm.c:  arm_arch_arm_hwdiv = (insn_flags & FL_ARM_DIV) != 0;
arm-cores.def:ARM_CORE("cortex-a7",  cortexa7,  7A, ... FL_ARM_DIV
arm-cores.def:ARM_CORE("cortex-a15", cortexa15, 7A, ... FL_ARM_DIV
arm-cores.def:ARM_CORE("cortex-r5",  cortexr5,  7R, ... FL_ARM_DIV
arm.h:  if (TARGET_IDIV)                                \
arm.h:#define TARGET_IDIV               ((TARGET_ARM && arm_arch_arm_hwdiv) \
arm.h:extern int arm_arch_arm_hwdiv;
arm.md:  "TARGET_IDIV"
arm.md:  "TARGET_IDIV"

谢谢您给予了机器定义方面的勇气,我认为我可以像从armv7-a复制一样定义一个新的机器类型,例如armv7-ad。我认为您不能使用内联汇编,编译器仍然会因指令不匹配而报错。关于mach、mcpu、mtune...因此整数除法是可选的,mach也是可选的...那么我希望有一种类似于fpu的mach变体或一些额外的标志。我期望mcpu/mtune可以为优化器提供一些指令调度信息——这就是为什么我犹豫使用cortex-a15的原因。 - auselen
@auselen 你试过使用-mcpu=cortex-a7吗?还是说它不适用于你的机器?看起来它可以提供与-mcpu=cortex-a15相同的FL_ARM_DIV权限。 - artless noise
1
不行。我们假设我使用带有idiv支持的cortex-a9。也许我可以使用“-mcpu=cortex-a15 -mtune=cortex-a9”,稍后我会测试一下。 - auselen
好的,cortex-a9在gcc-4.7中不支持它。您可以更改arm-cores.def以创建一个新的core,例如cortex-a9-div,然后使用FL_ARM_DIV标志来表示它支持idiv(复制现有的cortex-a9)。然后您可以使用-mcpu=cortex-a9-div。可能还没有gcc支持这个。看起来-mcpu=cortex-a7是一个替代选择。Cortex a7、a9和a15都有不同的调度器。 - artless noise
@auselen 编译器在代码生成方面有三个因素。 op-code是否允许,成本(循环次数)和调度。对于非流水线架构/CPU,没有调度程序。调度程序仅对装入/存储、多重执行、MAC单元等进行建模,并尝试按顺序排列指令,使每个阶段都运转良好。选择cortex-a15cortex-a7都将获得使用idiv的权限。我期望成本(cycle/idiv)是相同的。我认为您关于“-mtune=cortex-a9”的想法可以为您提供正确的调度程序以使用idiv;但是idiv没有调度模型。 - artless noise
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接