Sunteți pe pagina 1din 9

P ONTIFICIA U NIVERSIDAD C AT ÓLICA DEL P ER Ú

FACULTAD DE CIENCIAS E INGENIER ÍA


2019-1

GUÍA TEÓRICA PARA EL LABORATORIO DE


ARQUITECTURA DE COMPUTADORAS

SESIÓN N˝ : 3 TEMA: PUNTO FLOTANTE Y CALLING CONVENTIONS

INDICACIONES GENERALES
Revisar este material antes del desarrollo de la sesión de laboratorio
correspondiente.
Para un mejor desempeño, complementar el estudio de esta guı́a con el material del
curso y la bibliografı́a indicada.
Consultas puntuales sobre el contenido de esta guı́a se deben realizar a los
profesores del curso.
Revisar y desarrollar los ejemplos por su cuenta y comparar su solución con la
presentada en esta guı́a.

OBJETIVOS .
Manejar instrucciones SSE para operandos en coma flotante.
Distinguir los registros que se emplean para pasar parámetros en una función en C.

ÍNDICE

PUNTO FLOTANTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Valores en Punto Flotante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Registros de Punto Flotante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Instrucciones de Punto Flotante . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Instruciones de Transferencia de Datos . . . . . . . . . . . . . . . . . . . . . . . 3
Instruciones de Conversión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Instruciones Aritméticas de Punto Flotante . . . . . . . . . . . . . . . . . . . . . 3
Instruciones de Control de Punto Flotante . . . . . . . . . . . . . . . . . . . . . . 4

CALLING CONVENTIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Transmisión de Argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Paso de Parámetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

EJEMPLOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1IEE06 LABORATORIO DE ARQUITECTURA DE COMPUTADORAS 1


P ONTIFICIA U NIVERSIDAD C AT ÓLICA DEL P ER Ú
FACULTAD DE CIENCIAS E INGENIER ÍA
2019-1

PUNTO FLOTANTE

Los primeros CPUs (8086/8088) no podı́an ejecutar operaciones en punto flotante por
sı́ mismos, y para poder hacerlo hacı́an uso de un coprocesador externo llamado 8087.
Cuando un procesador no disponı́a del 8087 podı́a desarrollar operaciones en punto
flotante mediante el software. Esta disposición se mantuvo hasta que llegó la familia 486,
y el coprocesador se integró al procesador. El 8087 manejaba un conjunto de
instrucciones que manipulaban una pila de registros de 80 bits. Estas instrucciones aún
forman parte de los CPUs actuales; sin embargo, ahora existe un nuevo conjunto de
instrucciones más eficiente llamado SSE (Streaming SIMD Extensions) que permite
ejecutar operaciones en punto flotante con 16 registros dedicados.
Si el lector revisa los manuales Intel-64 o IA-32, se encontrará con instrucciones como
fadd, y con registros como ST(0), ST(1), ST(2), ... Estos elementos son del coprocesador
matemático, sin embargo, la presente guı́a se enfocará en presentar los elementos de
trabajo, instrucciones y registros, relacionados con la unidad SIMD (”Single Instruction
Multiple Data”) del procesador.

Valores en Punto Flotante

Los valores numéricos en punto flotante se pueden representar en precisión simple (32
bits) o en precisión doble (64 bits). En C, las variables con precisión simple son
declaradas como float y las variables con precisión doble son declaradas como double.
1 float a // a es una variable float de 32 bits
2 double b // b es una variable double de 64 bits
3 float * c // c es un puntero a una variable float
4 double * d // d es un puntero a una variable double

Registros de Punto Flotante

Hay un conjunto dedicado de registros, referidos como registros XMM, empleados para
dar soporte a las instrucciones en punto flotante. Las instrucciones en punto flotante
necesariamente se tienen que usar con estos registros. Los XMM son de 128 bits, pero en
los últimos procesadores son de 256 bits. Hay 16 registros XMM que van desde xmm0
hasta xmm15. Estos registros pueden ser empleados para instrucciones que operan
sobre un único valor (escalares) o en un conjunto de elementos (vectoriales), pero para
esta oportunidad solo emplearemos los últimos 32 o 64 bits de estos registros pues solo
se van a realizar operaciones escalares.

Instrucciones de Punto Flotante

La presentación de las instrucciones para operaciones de punto flotante será breve. Solo
serán cubiertas las más básicas y serán presentadas en el siguiente orden:
Instruciones de Transferencia de Datos.
Instrucciones de Conversión.

1IEE06 LABORATORIO DE ARQUITECTURA DE COMPUTADORAS 2


P ONTIFICIA U NIVERSIDAD C AT ÓLICA DEL P ER Ú
FACULTAD DE CIENCIAS E INGENIER ÍA
2019-1

Instrucciones Aritméticas de Punto Flotante.


Intrucciones de Control de Punto Flotante.
Para una lista completa de las instrucciones se puede revisar el siguiente enlace:
https://www.felixcloutier.com/x86/index.html

Instruciones de Transferencia de Datos

Estas instrucciones permiten transferir datos de una posición de memoria a un registro, y


de un registro a una posición de memoria y de un registro a otro registro.

Instruciones de Transferencia de Escalares

Hay dos instrucciones para mover escalares en punto flotante: movss para mover valores
de 32 bits (float) y movsd para mover valores de 64 bits (double).
1 movss xmm0 , [ a ] ; mover el valor en a al registro xmm0
2 movsd [ b ] , xmm1 ; mover el valor en el registro xmm1 a b
3 movss xmm2 , xmm0 ; mover el valor en xmm0 a xmm2

Instruciones de Conversión

Cuando se requiere emplear enteros en una operación en punto flotante, los enteros
deben ser convertidos primero a punto flotante. De igual manera, si se requieren en una
misma operación valores de precisión simple y precisión doble, se deberá realizar
previamente una operación de conversión para que ambos operandos compartan el
mismo tipo de dato.

Conversión entre Operandos Punto Flotante de distinto tamaño

Hay dos instrucciones para convertir operandos escalares en punto flotante: cvtss2sd
para convertir valores de 32 bits a 64 bits y cvtsd2ss para convertir valores de 64 bits a
32 bits.
1 cvtss2sd xmm0 , [ x ] ; convertir el float en x a double en xmm0
2 cvtsd2ss xmm0 , xmm0 ; el float en xmm0 a double en xmm0

Conversión de/a Punto Flotante de/a Entero

Cuando el método para convertir números en punto flotante a enteros es por redondeo
hay dos intrucciones: cvtss2si para convertir un float a entero y cvtsd2si para convertir
un double a entero. Cuando el método de conversión es por truncamiento hay otras dos
instrucciones: cvttss2si y cvttsd2si. Asimismo, para convertir números enteros a punto
flotante hay dos instrucciones: cvtsi2ss y cvtsi2sd.
1 cvtss2si eax , xmm0 ; float en xmm0 a int en eax
2 cvtsi2sd xmm0 , rax ; long en rax a double en xmm0
3 cvtsi2sd xmm0 , [ x ] ; int en x a double en xmm0

1IEE06 LABORATORIO DE ARQUITECTURA DE COMPUTADORAS 3


P ONTIFICIA U NIVERSIDAD C AT ÓLICA DEL P ER Ú
FACULTAD DE CIENCIAS E INGENIER ÍA
2019-1

Instruciones Aritméticas de Punto Flotante

Estas intrucciones permiten ejecutar operaciones de suma, resta, multiplicación, división y


raı́z cuadrada con operandos en punto flotante de 32 o 64 bits.
1 addss xmm0 , [a] ; xmm0 <- xmm0 + [ a ] ( float )
2 addss xmm0 , xmm1 ; xmm0 <- xmm0 + xmm1 ( float )
3 addsd xmm0 , [b] ; xmm0 <- xmm0 + [ b ] ( double )
4 addsd xmm0 , xmm1 ; xmm0 <- xmm0 + xmm1 ( double )
5 subss xmm0 , [a] ; xmm0 <- xmm0 - [ a ] ( float )
6 subss xmm0 , xmm1 ; xmm0 <- xmm0 - xmm1 ( float )
7 subsd xmm0 , [b] ; xmm0 <- xmm0 - [ b ] ( double )
8 subsd xmm0 , xmm1 ; xmm0 <- xmm0 - xmm1 ( double )
9 mulss xmm0 , [a] ; xmm0 <- xmm0 * [ a ] ( float )
10 mulss xmm0 , xmm1 ; xmm0 <- xmm0 * xmm1 ( float )
11 mulsd xmm0 , [b] ; xmm0 <- xmm0 * [ b ] ( double )
12 mulsd xmm0 , xmm1 ; xmm0 <- xmm0 * xmm1 ( double )
13 divss xmm0 , [a] ; xmm0 <- xmm0 / [ a ] ( float )
14 divss xmm0 , xmm1 ; xmm0 <- xmm0 / xmm1 ( float )
15 divsd xmm0 , [b] ; xmm0 <- xmm0 / [ b ] ( double )
16 divsd xmm0 , xmm1 ; xmm0 <- xmm0 / xmm1 ( double )
17 sqrtss xmm0 , [a] ; xmm0 <- ([ a ])^0 .5 ( float )
18 sqrtss xmm0 , xmm1 ; xmm0 <- ( xmm1 )^0 .5 ( float )
19 sqrtsd xmm0 , [b] ; xmm0 <- ([ b ])^0 .5 ( double )
20 sqrtsd xmm0 , xmm1 ; xmm0 <- ( xmm1 )^0 .5 ( double )
Notar que el operando de destino siempre es un registro.

Instruciones de Control de Punto Flotante

Las instrucciones de control son aquellas que permiten implementar estructuras selectivas
(IF - ELSE) e iterativas (FOR - WHILE). La instrucción cmp que se empleaba con enteros
no funcionará con operandos en punto flotante. Las instrucciones de comparación tendrán
ambos operandos en punto flotante, y al igual que en el caso de los enteros el resultado
será almacenado el registro de banderas.

Comparaciones en Punto Flotante

La forma general de las operaciones de comparación es una de las siguientes:


1 ucomiss Rxmm , op2
2 ucomisd Rxmm , op2
Donde Rxmm y op2 son operandos en punto flotante y deben ser del mismo tamaño.
Ninguno de los operandos será alterado por las operaciones de comparación. El operando
Rxmm debe ser un registro xmm, y el operando op2 puede ser un registro xmm o el
contenido de una posición de memoria.
En los siguientes ejemplos se pueden apreciar algunas de las operaciones de saltos de
control que se pueden realizar:
1 je label ; jump equal si op1 == op2
2 jne label ; jump not equal si op1 != op2

1IEE06 LABORATORIO DE ARQUITECTURA DE COMPUTADORAS 4


P ONTIFICIA U NIVERSIDAD C AT ÓLICA DEL P ER Ú
FACULTAD DE CIENCIAS E INGENIER ÍA
2019-1

3 jb label ; jump below than si op1 < op2


4 jbe label ; jump below or equal si op1 <= op2
5 ja label ; jump above than si op1 > op2
6 jae label ; jump above or equal si op1 >= op2
Se debe tener en cuenta que las últimas cuatro instrucciones operarán como si fueran
números sin signo.

CALLING CONVENTIONS

La mayorı́a de funciones tienen parámetros. Los parámetros nos permiten que una
función opere con datos distintos en cada llamada que se realiza. Adicionalmente, una
función puede tener un valor de retorno como indicador de éxito o error. Los sistemas
operativos Linux x86-64 un protocolo de llamadas a función llamado ”System V
Application Binary Interface”, o también ”System V ABI”. El protocolo que se emplea
depende del sistema operativo, pero todos los protocolos tienen en común que juntan el
uso de registros de propósito general con el uso ocasional de la pila. Los sistemas
operativos Linux permiten que se pasen hasta 6 parámetros enteros en registros y 8
parámetros en coma flotante mediante registros, mientras que Windows solo permite 4
enteros y 4 en coma flotante. Un elemento común de ambos protocolos es que emplean
rax como valor de retorno para enteros y xmm0 para coma flotante.

Transmisión de Argumentos

Es como se le denomina al envı́o de información a una función y a la obtención adecuada


de un resultado de dicha función. La terminologı́a estándar para transmitir valores a una
función es call-by-value, mientras que para transmitir direcciones es call-by-refernce.
Hay varias maneras de pasar argumentos a una función, pero las más usadas son las
siguientes:
Colocar valores o direcciones en un registro.
Definir variables globales.
Colocar valores o direcciones en la pila.

Paso de Parámetros

Como se mencionó anteriormente los parámetros pueden ser pasados a una función
mendiante el uso de registros o de la pila. La siguiente tabla muestra cuales son los
registros que se usan cuando enteros (char, short, int, long) o flotantes (float, double).
En la tabla se puede apreciar los registros que se corresponden con los argumentos de
una función:

1IEE06 LABORATORIO DE ARQUITECTURA DE COMPUTADORAS 5


P ONTIFICIA U NIVERSIDAD C AT ÓLICA DEL P ER Ú
FACULTAD DE CIENCIAS E INGENIER ÍA
2019-1

Tipo de dato
Posición según su tipo
Entero Flotante
Primero rdi xmm0
Segundo rsi xmm1
Tercero rdx xmm2
Cuarto rcx xmm3
Quinto r8 xmm4
Sexto r9 xmm5
Séptimo - xmm6
Octavo - xmm7

En caso la función tenga más de seis parámetros enteros y de 8 parámetros flotantes, los
parámetros adicionales serán pasados a la función por de la pila.
En el siguiente ejemplo se muestra una función con sus argumentos. En el comentario se
indica en que registro va cada parámetro de la función.
1 extern void my_function ( char a , short b , float c , double *d , double e )
2 // a en rdi , b en rsi , c en xmm0 , d en rdx , e en xmm1

EJEMPLOS

Lista 1: Example

1 ; Programa en ensamblador que calcula el producto interno


2 ; de dos vectores que contienen valores en punto flotante simple
3 ; Nombre del program : asmFl oatInn erProd
4 ; Para ensamblar ejecutar :
5 ; nasm -f elf64 a s m F l o a t I n n e r P r o d . a s m -o a s m Fl o a tI n n er P r od . o
6
7 global as mFloat InnerP rod ; nombre del programa
8 section .text
9
10 asmF loatI nnerPr od :
11 xorpd xmm0 , xmm0 ; xmm0 <- 0
12 xorpd xmm1 , xmm1 ; xmm1 <- 0
13 xorpd xmm2 , xmm2 ; xmm2 <- 0
14 cmp rdx , 0 ; si N == 0
15 je done ; terminar el programa
16 next :
17 movss xmm0 , [ rdi ] ; xmm0 <- [ rsi ]
18 movss xmm1 , [ rsi ] ; xmm1 <- [ rdi ]
19 mulss xmm0 , xmm1 ; xmm0 <- xmm0 * xmm1
20 addss xmm2 , xmm0 ; xmm2 <- xmm2 + xmm0
21 add rdi , 4 ; siguiente elemento
22 add rsi , 4 ; siguiente elemento
23 sub rdx , 1 ; disminuir contador

1IEE06 LABORATORIO DE ARQUITECTURA DE COMPUTADORAS 6


P ONTIFICIA U NIVERSIDAD C AT ÓLICA DEL P ER Ú
FACULTAD DE CIENCIAS E INGENIER ÍA
2019-1

24 jnz next
25 done :
26 movss [ rcx ] , xmm2 ; [ rcx ] <- xmm2
27 ret

Lista 2: Example

1 // Programa que compara el resultado en C y en ensamblador


2 // de calcular el producto punto de dos vectores
3 // de elementos en punto flotante simple
4 // Nombre del programa float_inner_prod
5 // Para compilar ejecutar el siguiente comando :
6 // gcc as mFloat InnerP rod . o float_inner_prod . c -o float_inner_prod
7
8 # include < stdio .h >
9 # include < stdlib .h >
10
11 extern void asm Float InnerP rod ( float * v1 , float * v2 , int N , float * ip );
12 void cFloatInnerProd ( float * v1 , float * v2 , int N , float * ip );
13
14 int main () {
15
16 float * v1 , * v2 , ipC , ipAsm ;
17 int N = 1024;
18
19 v1 = malloc ( N * sizeof ( float ));
20
21 v2 = malloc ( N * sizeof ( float ));
22
23 int i = 0;
24
25 for ( i = 0; i < N ; i ++){
26 v1 [ i ] = ( float ) i ;
27 v2 [ i ] = ( float ) i ;
28 }
29
30 cFloatInnerProd ( v1 , v2 , N , & ipC );
31
32 asmF loatIn nerPro d ( v1 , v2 , N , & ipAsm );
33
34 printf ( " %f \ n %f \ n " ,ipC , ipAsm );
35
36 return 0;
37 };
38
39 void cFloatInnerProd ( float * v1 , float * v2 , int N , float * ip ) {
40 int i = 0;
41 float sum = 0;
42 for ( i = 0; i < N ; i ++) {
43 sum += v1 [ i ] * v2 [ i ];
44 }

1IEE06 LABORATORIO DE ARQUITECTURA DE COMPUTADORAS 7


P ONTIFICIA U NIVERSIDAD C AT ÓLICA DEL P ER Ú
FACULTAD DE CIENCIAS E INGENIER ÍA
2019-1

45 ip [0] = sum ;
46 }

Lista 3: Example

1 ; Programa en ensamblador que calcula la norma 2


2 ; de un vector de valores en punto flotante simple
3 ; Nombre del program : asmFloatNormTwo
4 ; Para ensamblar ejecutar :
5 ; nasm -f elf64 a s m Fl o a tN o r mT w o .a s m -o asmFl oatNor mTwo.o
6
7 global asmFloatNormTwo
8 section .text
9
10 asmFloatNormTwo :
11 xorpd xmm0 , xmm0 ; xmm0 <- 0
12 xorpd xmm1 , xmm1 ; xmm1 <- 0
13 cmp rdx , 0 ; si N == 0
14 je done ; terminar el programa
15 next :
16 movss xmm0 , [ rdi ] ; xmm0 <- [ rdi ]
17 mulss xmm0 , xmm0 ; xmm0 <- xmm0 * xmm0
18 addss xmm1 , xmm0 ; xmm1 <- xmm1 + xmm0
19 add rdi , 4 ; siguiente elemento
20 sub rsi , 1 ; disminuir contador
21 jnz next
22 done :
23 sqrtss xmm1 , xmm1
24 movss [ rdx ] , xmm1
25 ret

Lista 4: Example

1 // Programa que compara el resultado en C y en ensamblador


2 // de calcular la norma dos de un vector
3 // de elementos en punto flotante simple
4 // Nombre del programa float_norm_two
5 // Para compilar ejecutar el siguiente comando :
6 // gcc asmFloatNormTwo . o float_norm_two . c -o float_norm_two - lm
7
8 # include < stdio .h >
9 # include < stdlib .h >
10 # include < math .h >
11
12 extern void asmFloatNormTwo ( float * v1 , int N , float * n2 );
13 void cFloatNormTwo ( float * v1 , int N , float * n2 );
14
15 int main () {
16
17 float * v1 , n2C , n2Asm ;
18 int N = 1024;

1IEE06 LABORATORIO DE ARQUITECTURA DE COMPUTADORAS 8


P ONTIFICIA U NIVERSIDAD C AT ÓLICA DEL P ER Ú
FACULTAD DE CIENCIAS E INGENIER ÍA
2019-1

19
20 v1 = malloc ( N * sizeof ( float ));
21
22 int i = 0;
23
24 for ( i = 0; i < N ; i ++){
25 v1 [ i ] = ( float ) i ;
26 }
27
28 cFloatNormTwo ( v1 , N , & n2C );
29
30 asmFloatNormTwo ( v1 , N , & n2Asm );
31
32 printf ( " %f \ n %f \ n " ,n2C , n2Asm );
33
34 return 0;
35 };
36
37 void cFloatNormTwo ( float * v1 , int N , float * n2 ) {
38 int i = 0;
39 float sum = 0;
40 for ( i = 0; i < N ; i ++) {
41 sum += v1 [ i ] * v1 [ i ];
42 }
43 n2 [0] = sqrtl ( sum );
44 }

1IEE06 LABORATORIO DE ARQUITECTURA DE COMPUTADORAS 9

S-ar putea să vă placă și