【问题标题】:Stupid Sort of uint16_t halfwords?uint16_t 半字的愚蠢排序?
【发布时间】:2021-12-07 12:53:09
【问题描述】:

这是对整个有符号单词(int32_t)进行排序的第一个代码:

sort:   SUB     R1,R1,#1        //--n           void StupidSort(int a[], int n)
        ADD     R12,R0,#4       //нач.адрес+4   {
        ADD     R1,R0,R1,LSL#2  //краен адрес       int tmp, i = 0;
L1:     LDR     R3,[R0]         //*a                do {
        LDR     R2,[R0,#4]!     //*++a ___              if (a[i] > a[i+1]) {
        CMP     R3,R2           //        \                 tmp = a[i+1];
        BLE     L2              //         \                a[i+1] = a[i];
        STMDA   R0,{R2,R3}      //          \               a[i] = tmp;
        CMP     R0,R12          //           \              if (i) i--;
        SUBHI   R0,R0,#8        //            \___      } else i++;
L2:     CMP     R0,R1           //                  } while (i < n - 1);
        BLT     L1              //              }
        BX      LR

这是我到目前为止所做的:

sort:   SUB     R1,R1,#1        //--n           void StupidSort(int a[], int n)
                ADD     R12,R0,#2       //нач.адрес+4   {
                ADD     R1,R0,R1,LSL#1  //краен адрес       int tmp, i = 0;
        L1:     LDRH    R3,[R0]         //*a                do {
                LDRH    R2,[R0,#2]!     //*++a ___              if (a[i] > a[i+1]) {
                CMP     R3,R2           //        \                 tmp = a[i+1];
                BLE     L2              //         \                a[i+1] = a[i];
                STRH    R2,[R0,#2]
                STRH    R3,[R0]         //          \               a[i] = tmp;
                CMP     R0,R12          //           \              if (i) i--;
                SUBHI   R0,R0,#4        //            \___      } else i++;
        L2:     CMP     R0,R1           //                  } while (i < n - 1);
                BLT     L1              //              }
                BX      LR

    

我尝试将其更改为对 uint16_t 无符号半字进行排序。我快完成了,但有些事情是 代码中缺失。问题是排序,架构是ARM(在ARM模式下,不是 拇指);另外我不知道标志是什么!在 LDRH 功能后面我也认为 ldrd r3 和 r2 应该轮换他们的位置。

【问题讨论】:

  • @AlexF 我的意思是缺少一些东西,因为当我编译然后运行它时,它显示了 10 个完全相同的数字
  • @AlexF 并且在第二个 ldrh 的末尾还有!我不知道它是做什么用的
  • 请不要做傻事。代码聪明。但! 代表预索引。 ldrh r2,[r0, #2]! 在内存访问之前更新 r0 = r0 + 2ldrh r2, [r0], #2 会更新后,顺便说一句。
  • Insertion Sort of uint16_t halfwords? 非常相似的问题,尽管那里的 32 位排序使用条件谓词存储,而不是使用分支来跳过 stm。 (并且使用ldm 进行负载;有趣的事实:您不能使用both LDM 和STM 进行有效交换,因为没有办法让寄存器列表以不同的顺序排列;这是一个位图。)
  • @AkiSuihkonen 你认为我应该改变 ldrh 中 r3 和 r2 的位置

标签: sorting assembly arm


【解决方案1】:

! 代表预增量,与注释 *++a 完全相同。 因此,偏移量#2 在内存访问之前被添加到基址r0,而且寄存器r0 也被更新。

L1:     LDRH    R3,[R0]         //*a                do {
        LDRH    R2,[R0,#2]!     //*++a ___              if (a[i] > a[i+1]) {
        CMP     R3,R2           //        \                 tmp = a[i+1];
        BLE     L2              //         \                a[i+1] = a[i];
        STRH    R2,[R0,#-2]     // ***      \
        STRH    R3,[R0]         // ***       \               a[i] = tmp;
        CMP     R0,R12          //            \              if (i) i--;
        SUBHI   R0,R0,#4        //             \___     } else i++;
L2:     CMP     R0,R1           //                  } while (i < n - 1);

标有***的部分进行了修改,以补偿*++a的影响;

通常可能有更好的方法来实现插入或冒泡排序;这种算法例如在下一轮中读取上一次迭代中写入的相同元素。此外,使用条件交换/移动而不是显式分支可能更有意义。

相应的 32 位代码使用 STMDA R0,{R2,R3} 以巧妙(混淆)的方式写入交换的值,这依赖于已按 R3, R2 的顺序读取的 R2, R3。该指令代表存储倍数,减量后,将 R2 写入R0 - 4,将 R3 写入R0。但由于该变体不适用于 16 位寄存器,因此需要将 R2 写入 R0 - 2 并将 R3 写入 R0

【讨论】:

  • “! 代表预增量”。 Nitpick:! 代表回写。预增量(或预index)部分是通过在括号内有一个偏移量给出的(即,#2],而不是],#2)。
  • 是回写,但],#2 也是回写。因此,将它们区分为 pre-incrementindexedpost-increment 也是有意义的。
  • @chaikataaaaa:我在r2, r3的回写顺序上确实犯了一个错误。它在我原来的帖子中的方式,实际上并没有交换订单。现在该部分也已修复。
  • @AkiSuihkonen 我认为它也应该是 #-2 而不是 -#2
  • 您对这段代码和原始代码的期望是输出具有与输入相同的所有元素。此外,此代码只会对数据进行部分排序。没有充分。使用这种排序算法最多需要 N-1 次对数据进行排序。
猜你喜欢
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 2016-03-01
  • 1970-01-01
  • 2021-07-07
  • 2011-08-24
  • 2012-05-09
  • 1970-01-01
相关资源
最近更新 更多