首页 文章

如何防止ARM编译器5 armcc内联汇编程序中的LDM / STM指令扩展?

提问于
浏览
2

我正在尝试使用ARM编译器5 armcc编译的.c文件中的内联汇编中的STM / LDM指令生成AXI总线突发访问 .

inline void STMIA2(uint32_t addr, uint32_t w0, uint32_t w1)
{
    __asm {
        STMIA addr!, { w0, w1 }
    }
}

但ARM编译器armcc用户指南第7.18段说:“所有LDM和STM指令都扩展为LDR和STR指令序列,效果相同 . 但是,编译器可能会在优化期间将单独的指令重新组合成LDM或STM . “

这就是实践中真正发生的事情,LDM / STM在某些情况下会扩展为一组LDR / STR,这些指令的顺序是任意的 . 这会影响性能,因为我们使用的HW针对突发处理进行了优化 . 这也打破了功能正确性,因为我们使用的HW考虑了单词序列并忽略了偏移(但编译器认为更改指令的顺序是安全的) .

要解决这个问题,可以使用嵌入式汇编程序而不是内联汇编程序,但这会导致额外的函数调用 - 返回影响性能的因素 .

所以我想知道是否有办法在不损失性能的情况下正确生成LDM / STM?我们能够在GCC中做到这一点,但没有找到任何armcc的解决方案 .

目标CPU:Cortex M0(ARMv6-M) .

Edit: 从设备都是片上设备,大多数都是非内存设备 . 对于支持地址空间的突发访问区域的每个非存储器从站寄存器(例如[0x10000..0x10100]),I 'm not completely sure why, maybe CPU or bus doesn' t支持固定(非增量)地址 . HW忽略该区域内的偏移 . 例如,完整请求可以是16字节,并且完整请求的第一个字是第一个字写入的(即使偏移是非零) .

1 回答

  • 1

    所以我想知道是否有办法在不损失性能的情况下正确生成LDM / STM?我们能够在GCC中做到这一点,但没有找到任何armcc的解决方案 .

    关于编译器优化的一点点 . Register allocation是其中之一's toughest jobs. The heart of any compiler'代码生成可能在它分配物理CPU寄存器时 . 大多数编译器使用Single static assignment or SSA将'C'变量重命名为一堆伪变量(或时间顺序变量) .

    为了使您的STMIA和LDMIA工作,您需要加载和存储保持一致 . 即,如果它是 stmia [rx], {r3,r7} 并且恢复像 ldmia [rx], {r4,r8} ,'r3'映射到新的'r4'并且存储的'r7'映射到恢复的'r8' . 对于任何编译器来说,这一点并不简单,因为'C'变量将根据需要进行分配 . 同一变量的不同版本可能在不同的寄存器中 . 要使 stm/ldm 工作,必须分配这些变量,以便寄存器以正确的顺序递增 . 即,对于上面的 ldmia ,如果编译器想要在 r0 中存储 r7 (可能是返回值?),则无法在不生成其他代码的情况下创建良好的 ldm 指令 .

    你可能已经获得了gcc来生成这个,但它可能是运气 . 如果你只进行gcc,你可能会发现它不起作用 .

    有关GCC stm / ldm的问题,请参阅:ldm/stm and gcc .

    举个例子,

    inline void STMIA2(uint32_t addr, uint32_t w0, uint32_t w1)
    {
        __asm {
            STMIA addr!, { w0, w1 }
        }
    }
    

    inline 的值是整个函数体可以放在代码中 . 调用者可能在寄存器R8和R4中具有 w0w1 . 如果函数不是 inline ,那么编译必须将它们放在R1和R2中,但可能产生了额外的移动 . 任何编译器都难以一般地满足 ldm/stm 的要求 .

    这会影响性能,因为我们使用的HW针对突发处理进行了优化 . 这也打破了功能正确性,因为我们使用的HW考虑了单词序列并忽略了偏移(但编译器认为更改指令的顺序是安全的) .

    如果硬件是总线上的特定非存储器从外设,那么您可以在外部包装器中包装写入该从器件的功能并强制进行寄存器分配(请参阅AAPCS)以便 ldm/stm 可以工作 . 这将导致性能损失,可以通过设备驱动程序中的某个自定义汇编程序来缓解 .

    但是,听起来设备可能是内存?在这种情况下,您遇到了问题 . 通常,像这样的内存设备只会使用缓存吗?如果您的CPU具有MPU(内存保护单元)并且可以启用数据和代码缓存,那么您可以解决这个问题 . 高速缓存行将始终是突发访问 . 只需要在代码中注意设置MPU和数据缓存 . OP Cortex-M0没有缓存,设备是非内存,所以这是不可能的(也不需要) .

    如果您的设备是内存并且您没有数据缓存,那么您的问题可能无法解决(无需大量工作)并且您需要不同的硬件 . 或者你可以像外围设备一样包装它并获得性能提升;失去了存储设备随机存取的好处 .

相关问题