// ====================================================================
// Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
// project. Rights for redistribution and usage in source and binary
// forms are granted according to the OpenSSL license.
// ====================================================================
//
// What's wrong with compiler generated code? Compiler never uses
// variable 'shr' which is pairable with 'extr'/'dep' instructions.
// Then it uses 'zxt' which is an I-type, but can be replaced with
// 'and' which in turn can be assigned to M-port [there're double as
// much M-ports as there're I-ports on Itanium 2]. By sacrificing few
// registers for small constants (255, 24 and 16) to be used with
// 'shr' and 'and' instructions I can achieve better ILP, Intruction
// Level Parallelism, and performance. This code outperforms gcc
// generated code by almost factor of 2 (two). Improvement over HP C
// is not that impressive, 20%...
.ident "aes-ia64.S, version 1.0"
.ident "IA-64 ISA artwork by Andy Polyakov <appro@fy.chalmers.se>"
.explicit
.text
rk0=r8; rk1=r9;
prsave=r10;
maskff=r11;
twenty4=r14;
sixteen=r15;
te00=r16; te11=r17; te22=r18; te33=r19;
te01=r20; te12=r21; te23=r22; te30=r23;
te02=r24; te13=r25; te20=r26; te31=r27;
te03=r28; te10=r29; te21=r30; te32=r31;
// these are rotating...
t0=r32; s0=r33;
t1=r34; s1=r35;
t2=r36; s2=r37;
t3=r38; s3=r39;
te0=r40; te1=r41; te2=r42; te3=r43;
#if defined(_HPUX_SOURCE) && !defined(_LP64)
# define ADDP addp4
# define KSZ 4
# define LDKEY ld4
#else
# define ADDP add
#endif
#ifndef KSZ
# define KSZ 8
# define LDKEY ld8
#endif
// void AES_encrypt (const void *in,void *out,const AES_KEY *key);
// measured timing om Itanium 2 is (48 + 14*rounds) cycles
.global AES_encrypt#
.proc AES_encrypt#
.align 32
#if !defined(_HPUX_SOURCE)
.skip 16
#endif
AES_encrypt:
.prologue
.fframe 0
.save ar.pfs,r2
.save ar.lc,r3
{ .mii; alloc r2=ar.pfs,3,10,0,8
mov r3=ar.lc
mov prsave=pr };;
.body
{ .mib; and r40=3,r32
mov pr.rot=7<<16
brp.exit.imp .Le_rounds_cexit,.Le_cexit_insn
};;
#if defined(_HPUX_SOURCE) // HPUX is big-endian, cut 15 cycles...
{ .mib; cmp.ne p6,p0=r40,r0
ADDP r41=4,r32 // 1st arg, borrow teN
(p6) br.dpnt.many .Le_unaligned };;
{ .mmi; ld4 r19=[r32],8
mov r44=r33 // save 2nd arg
mov twenty4=24 }
{ .mmi; ld4 r23=[r41],8
addl te0=@ltoff(Te0#),gp
ADDP r35=KSZ*60,r34 };; // &AES_KEY->rounds, borrow s1
{ .mmi; ld8 te0=[te0]
ld4 r35=[r35] // AES_KEY->rounds
ADDP rk0=0,r34 }//;; // 3rd arg
{ .mmi; ld4 r27=[r32]
ld4 r31=[r41]
ADDP rk1=KSZ,r34 };;
{ .mfi; LDKEY t0=[rk0],2*KSZ
mov sixteen=16 }
{ .mfi; LDKEY t1=[rk1],2*KSZ
mov maskff=0xff };;
{ .mfi; LDKEY t2=[rk0],2*KSZ
add te1=1024,te0 }
{ .mib; LDKEY t3=[rk1],2*KSZ
add te2=2048,te0
br.many .Le_common };;
#endif
.Le_unaligned:
{ .mfi; ADDP r40=0,r32 // 1st arg, borrow teN