Указатель доступа к массиву в MIPS - PullRequest
3 голосов
/ 24 августа 2010

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

Ответы [ 2 ]

1 голос
/ 02 мая 2012

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

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

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

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

0 голосов
/ 04 февраля 2011

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

...