ARC64工具链中FPU寄存器分配问题的分析与解决

ARC64工具链中FPU寄存器分配问题的分析与解决

问题背景

在构建ARC64架构的嵌入式工具链时,开发团队遇到了一个关于浮点运算单元(FPU)寄存器分配的关键问题。当使用arc64-snps-elf工具链编译newlib数学库中的多个函数时,编译器报告了"unable to find a register to spill"的错误,导致编译失败。这个问题主要出现在包含复杂浮点运算的函数中,如k_rem_pio2.c、e_log.c等数学函数实现。

问题现象

编译过程中出现的错误信息表明,编译器在处理64位浮点常数时遇到了寄存器分配困难。具体表现为:

  1. 编译器无法为特定的指令找到可用的寄存器进行溢出(spill)
  2. 错误发生在将64位常量(如0x3fc0000000000000)移动到FPU寄存器的过程中
  3. 问题在启用多库支持(--enable-multilib)的配置下出现

技术分析

经过深入分析,开发团队发现问题的根源在于ARC64架构中处理64位浮点常量的方式存在缺陷。当编译器需要将64位浮点常量加载到FPU寄存器时,原有的实现存在以下问题:

  1. 直接使用整数模式(DImode)处理双精度浮点(DFmode)常量
  2. 缺少从整数到浮点的显式转换指令
  3. 寄存器分配器在处理这种特殊情况时无法正确工作

解决方案

开发团队针对此问题提出了以下修复方案:

  1. 在arc64_prepare_move_operands函数中增加显式的浮点转换
  2. 使用gen_floatdidf2指令生成从整数到双精度浮点的转换
  3. 添加断言确保只在DImode和DFmode组合下执行此操作
  4. 考虑到当前ARC32+FPUDF配置不受支持,暂时不做兼容处理

修复的核心代码修改如下:

gcc_assert (imode == DImode && mode == DFmode);
...
emit_insn (gen_floatdidf2 (op0, tmp));

验证测试

为了验证修复效果,开发团队创建了一个精简测试用例,模拟了原始问题中的关键操作:

int *a;
int b, c, d;
double e, g;
double f[0];
double *h;
int i[0];
void l() {
  int j;
k:
  for (; g; b++, g--)
    i[b] = 1.67772160000000000000e07 * e;
  if (b) {
    for (; b <= d; b++) {
      f[b] = a[b];
      c = 0.0;
      for (; c <= j; c++)
        e = h[c] * f[c];
    }
    goto k;
  }
}

该测试用例成功验证了修复方案的有效性,确认了编译器现在能够正确处理64位浮点常量的加载和寄存器分配。

影响范围

此修复影响以下方面:

  1. 所有使用ARC64架构FPU双精度浮点运算的代码
  2. 特别是数学库中涉及复杂浮点计算的函数
  3. 使用-mfpu=fpud选项编译的代码

总结

这个问题的解决确保了ARC64工具链能够正确编译包含复杂浮点运算的代码,特别是标准数学库的实现。通过显式处理64位浮点常量的加载和转换,编译器现在能够更可靠地分配FPU寄存器,为ARC64架构的高性能浮点运算提供了坚实基础。这一修复已合并到arc-2024.06和arc64分支中,成为工具链稳定性的重要改进。

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值