【问题标题】:Pointer based array access in MIPSMIPS 中基于指针的数组访问
【发布时间】:2010-08-24 08:28:52
【问题描述】:

MIPS 中基于指针的数组访问是什么意思?

【问题讨论】:

    标签: assembly mips computer-architecture


    【解决方案1】:

    “基于指针的数组访问”还有一个可能的含义或含义:

    你可能有一个指向数组的指针,而不是一个固定地址的数组。实际上,在 C/C++ 中,“指向数组的指针”实际上通常只是指向数组第一个元素的指针。基本上,您有一个作为函数参数的数组,或者一个指向作为结构或类成员的数组的指针:

     void Foo(char a[]); 
       /*or*/ void Foo(char *a);
     struct Bar {  int offset4bytes; char* a; };
    

    通常,当您要使用这样的数组时,数组的基地址将被加载到寄存器中。

    现在说你想访问这样一个数组的元素 i,

     char tmp = a[i];
    

    假设 r1 包含数组地址。 (实际上,可能是调用约定为函数参数指定的不同寄存器。编译器发现可用于其他代码的任何内容。)

    假设我住在寄存器 r2 中。

    并且,为了更好的衡量,让 tmp 为 r3。

    在某些指令集上,例如Intel x86,有一种寻址模式,看起来像

      MOV r3, (r2,r1)4
    

    即寻址模式可以添加两个寄存器和一个偏移量(我在 struct 示例中任意添加了一个字段,以便展示这一点)。

    哎呀,他们甚至可以缩放其中一个寄存器,即所谓的索引寄存器:

      MOV r3, (r2*2,r1)4
    

    或者我更喜欢这样写

      r3 := load( Memory[r2<<1+r1+4]
    

    然而,MIPS 没有这种 base+_index*scale+offset 寻址模式。大多数 MIPS 内存访问指令仅限于寄存器+偏移。因此,对于 MIPS,您可能必须这样做

      ADDU r10, r1,r1    ; dest on left. r10 = 2*r1
      ADDU r11, r2,r10  
      LB r3,(r11)4
    

    即您可能需要添加额外的 RISC 指令来完成 x86 在一条具有复杂寻址模式的 CISC 指令中所做的事情。但是,这种寻址方式并不常见,通常可以避免。


    此外,即使只是对固定地址的数组进行寻址,也可能需要 MIPS 中的额外指令。 x86 指令可以有一个 32 位的内存偏移量——在这种情况下,它实际上可能是一个数组的绝对地址。 MIPS 指令仅限于 16 位偏移量 - MIPS 指令是固定宽度,32 位宽。因此,即使访问固定地址的数组,也可能需要单独的指令,通常是将地址的高位加载到寄存器中。

    还有更多 - MIPS 具有更新的指令,如 LUXC1,具有 reg+reg 寻址模式。但没有缩放索引,也没有第三个偏移分量。


    由于这种受限的寻址模式,天真的编译器为诸如 lop 生成的代码

       for(int i=0;i<N;i++) {
          this->a[i] = 0;
       }
    

    如果循环包含上述多条指令序列,效率会很低。

    这样的循环

       for(char *p=this->a;p<&(this->a[N]);p++) {
          *p=0;
       }
    

    或者,等价

       for(char *p=this->a;p<this->a+N;p++) {
          *p;
       }
    

    甚至有时

       for(i=-N,*p=this->a;i<0;i++,p++) {
          *p=0;
       }
    

    可能更有效,因为,例如在前两个中,只有一条指令来进行存储。 (最后一个通常只有遍历几个数组才能获胜。

    现在,在一个简单的示例中,任何优秀的编译器都会为您执行此优化。但有时编译器更喜欢这种基于指针的访问。

    【讨论】:

    • 可能相关:来自 Livermore Loops 基准的 Langer98 版本中的文件 cflops.c,aip.org/cip/langer.htm:截至 1998 年,C 编译器在访问全局数据时通常生成比访问数据时更快的代码通过指针。使用全局结构的一个副作用是,在此基准测试中看到的性能可能高于许多大量使用指针的现实世界代码。声明程序中没有“指针别名”的编译器标志可能会避免这种性能损失。
    【解决方案2】:

    您将拥有一个指向值数组开头的指针。要遍历数组,您将使用指针算法(通常是加/减 1、2 或 4)将指针前进到数组中的下一个/上一个元素。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-21
      • 1970-01-01
      • 1970-01-01
      • 2014-01-03
      • 1970-01-01
      • 2011-08-14
      • 2016-06-03
      相关资源
      最近更新 更多