Доступ к массиву на основе указателя в MIPS

Что мы подразумеваем под доступом к массиву на основе указателя в MIPS?


person kamalbhai    schedule 24.08.2010    source источник


Ответы (2)


Существует дополнительное возможное значение или значение «доступа к массиву на основе указателя»:

У вас может быть указатель на массив, а не на массив с фиксированным адресом. На самом деле в 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

т. е. режим адресации может добавить два регистра и смещение (я произвольно добавил поле в пример структуры, чтобы показать это).

Черт возьми, они даже могут масштабировать один из регистров, так называемый индексный регистр:

  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. Но не масштабированный индекс и не третий компонент смещения.


Из-за этих ограниченных режимов адресации код, сгенерированный наивным компилятором для цикла, такого как

   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;
   }

может быть более эффективным, потому что, например. в первых двух будет только одна инструкция для сохранения. (Последнее обычно выигрывает только при обходе нескольких массивов.

Теперь, в простом примере, любой хороший компилятор сделает эту оптимизацию за вас. Но иногда компилятор предпочитает такой доступ на основе указателя.

person Krazy Glew    schedule 02.05.2012
comment
Возможно релевантно: из файла cflops.c в тесте Livermore Loops версии Langer98, aip.org /cip/langer.htm: компилятор C с 1998 года часто создает более быстрый код при доступе к глобальным данным, чем при доступе к данным через указатель. Побочным эффектом использования глобальных структур является то, что производительность, наблюдаемая в этом тесте, может быть выше, чем у многих реальных кодов, которые активно используют указатели. Флаг компилятора, объявляющий, что в программе нет псевдонима указателя, может обойти эту потерю производительности. - person Krazy Glew; 12.05.2012

У вас будет указатель, указывающий на начало массива значений. Для обхода массива вы будете использовать арифметику указателя (обычно добавление/вычитание 1, 2 или 4), чтобы переместить указатель на следующий/предыдущий элемент в массиве.

person Sparafusile    schedule 04.02.2011