// Target: GCC on x86-64. // Using indent = 4. #include #include typedef uint8_t IPv6_Size_t; typedef struct { uint64_t L, H; // Little-endian. } IPv6_Address_t; typedef struct { uint64_t H, L; // Big-endian. } IPv6_Address_BE_t; static inline uint64_t BSwap64(uint64_t v_R_u64) { __asm__( "bswapq %[R]" // Endian-swap R; : [R] "+r" (v_R_u64) // Output operands. ); return(v_R_u64); } // Returns undefined size when Mask is invalid. (For the purpose of conversion to a size an invalid IP mask is defined as having a 1 bit following a 0.) static inline IPv6_Size_t IPv6_Mask_to_Size_BSF_2(uint64_t v_MaskL_u64, uint64_t v_MaskH_u64) { uint64_t Size_u64 = 64, Temp_u64 = 64; __asm__( "bsfq %[MaskH], %[Size] \n" // Size = first 1 bit of MaskH, low -> high; " bsfq %[MaskL], %[Temp] \n" // Temp = first 1 bit of MaskL, low -> high; " subb $128, %b[Size] \n" // Size -= 128; " addb %b[Temp], %b[Size] \n" // Size += Temp; " negb %b[Size]" // Size -= Size; : [Size] "+r" (Size_u64), [Temp] "+r" (Temp_u64) // Output operands. : [MaskL] "r" (v_MaskL_u64), [MaskH] "r" (v_MaskH_u64) // Input operands. : "cc" // Clobbered elements. ); return((IPv6_Size_t) Size_u64); } // Returns undefined size when Mask is invalid. (For the purpose of conversion to a size an invalid IP mask is defined as having a 1 bit following a 0.) static inline IPv6_Size_t IPv6_Mask_to_Size(uint64_t v_MaskL_u64, uint64_t v_MaskH_u64) { uint64_t Size_u64, Temp_u64; __asm__( "popcntq %[MaskH], %[Size] \n" // Size = count of 1s in MaskH; " popcntq %[MaskL], %[Temp] \n" // Temp = count of 1s in MaskL; " addb %b[Temp], %b[Size]" // Size += Temp; : [Size] "=&r" (Size_u64), [Temp] "=&r" (Temp_u64) // Output operands. : [MaskL] "r" (v_MaskL_u64), [MaskH] "r" (v_MaskH_u64) // Input operands. : "cc" // Clobbered elements. ); return((IPv6_Size_t) Size_u64); } // Returns undefined size when Mask is invalid. (For the purpose of conversion to a size an invalid IP mask is defined as having a 1 bit following a 0.) static inline IPv6_Size_t IPv6_Mask_to_Size_2(uint64_t v_MaskL_u64, uint64_t v_MaskH_u64) { uint64_t Size_u64, Temp_u64; __asm__( "xorl %k[Size], %k[Size] \n" " xorl %k[Temp], %k[Temp] \n" " popcntq %[MaskH], %[Size] \n" // Size = count of 1s in MaskH; " popcntq %[MaskL], %[Temp] \n" // Temp = count of 1s in MaskL; " addb %b[Temp], %b[Size]" // Size += Temp; : [Size] "=&r" (Size_u64), [Temp] "=&r" (Temp_u64) // Output operands. : [MaskL] "r" (v_MaskL_u64), [MaskH] "r" (v_MaskH_u64) // Input operands. : "cc" // Clobbered elements. ); return((IPv6_Size_t) Size_u64); } // Mask is undefined when Size > 128. static inline void IPv6_Size_to_Mask(IPv6_Size_t v_Size_u8, uint64_t &r_MaskL_u64, uint64_t &r_MaskH_u64) { __asm__( "xorl %k[MaskL], %k[MaskL] \n" // MaskL = 0; // Clear upper bits for SET. " cmpb $64, %[Size] \n" " setbe %b[MaskL] \n" // MaskL = (Size <= 64); " sbbq %[MaskH], %[MaskH] \n" // MaskH -= MaskH + (Size < 64); " subb $128, %[Size] \n" // Size -= 128; " decq %[MaskL] \n" // MaskL -= 1; " shrq %[Size], %[MaskH] \n" // MaskH >>= Size; " negb %[Size] \n" // Size = -Size; " notq %[MaskH] \n" // MaskH != MaskH; " shlq %[Size], %[MaskL]" // MaskL <<= Size; : [Size] "+c" (v_Size_u8), [MaskL] "=r" (r_MaskL_u64), [MaskH] "=r" (r_MaskH_u64) // Output operands. : : "cc" // Clobbered elements. ); } // Size is undefined on failure. static inline int IPv6_Mask_to_Size_Validate(uint64_t v_MaskL_u64, uint64_t v_MaskH_u64, IPv6_Size_t &r_Size_u8) { int R_i32; __asm__( "popcntq %[MaskH], %q[Size] \n" // Size = count of 1s in MaskH; " xorl %[R], %[R] \n" // R = 0; // Set ZF for shift. " shlq %[Size], %[MaskH] \n" // MaskH <<= Size; // Result discarded; Flags unmodified when count == 0. " jnz 2f \n" // if(ZF != 1) goto Exit; " testq %[MaskL], %[MaskL] \n" " jz 1f \n" // if(MaskL == 0) goto Success; " cmpb $64, %[Size] \n" " jne 2f \n" // if(Size != 64) goto Exit; " popcntq %[MaskL], %q[Size] \n" // Size = count of 1s in MaskL; " xorl %[R], %[R] \n" // R = 0; // Set ZF for shift. " shlq %[Size], %[MaskL] \n" // MaskL <<= Size; // Result discarded; Flags unmodified when count == 0. " jnz 2f \n" // if(ZF != 1) goto Exit; " addb $64, %[Size] \n" // Size += 64; "1: \n" // Success: " movb $1, %b[R] \n" // R = 1; "2:" // Exit: : [MaskL] "+r" (v_MaskL_u64), [MaskH] "+r" (v_MaskH_u64), [Size] "=c" (r_Size_u8), [R] "=q" (R_i32) // Output operands. : : "cc" // Clobbered elements. ); return(R_i32); } static inline uint8_t mask2prefixlen6(uint8_t *ap) { uint8_t l = 0, *ep; ep = (uint8_t *) ap + 16; for (; ap < ep; ap++) { switch (*ap) { case 0xff: l += 8; break; case 0xfe: l += 7; return (l); case 0xfc: l += 6; return (l); case 0xf8: l += 5; return (l); case 0xf0: l += 4; return (l); case 0xe0: l += 3; return (l); case 0xc0: l += 2; return (l); case 0x80: l += 1; return (l); case 0x00: return (l); default: return (0); } } return (l); } static inline uint64_t Read_Time_Stamp_1st(void) { uint64_t R_u64; __asm__ __volatile__( "xorl %k[R], %k[R] \n" // R = 0; // CPUID function 0. " cpuid \n" // Synchronize. " rdtsc \n" // Read Time-Stamp Counter; " shlq $32, %%rdx \n" // rdx <<= 32; " addq %%rdx, %[R]" // rax += rdx; : [R] "=a" (R_u64) // Output operands. : : "cc", "%ebx", "%ecx", "%rdx" // Clobbered elements. ); return(R_u64); } static inline uint64_t Read_Time_Stamp_2nd(void) { uint64_t R_u64, T_u64; __asm__ __volatile__( "rdtscp \n" // Read Time-Stamp Counter and Processor ID; " movl %%eax, %k[R] \n" // R = eax; " movl %%edx, %k[T] \n" // T = edx; " xorl %%eax, %%eax \n" // eax = 0; // CPUID function 0. " cpuid \n" // Synchronize. " shlq $32, %[T] \n" // T <<= 32; " addq %[T], %[R]" // R += T; : [R] "=r" (R_u64), [T] "=r" (T_u64) // Output operands. : : "cc", "%eax", "%ebx", "%ecx", "%edx" // Clobbered elements. ); return(R_u64); } int main() { uint32_t B_u32; uint8_t A_u8; int R_i = 0; uint64_t A_u64, H_u64, L_u64; IPv6_Address_BE_t M_t[200][129]; IPv6_Size_t S1_t[200][129], S2_t[200][129], S3_t[200][129], S4_t[200][129]; printf("Helloooooo world...\n\n"); // Benchmark: IPv6 Mask -> Size routines // Initialize mask array A_u64 = Read_Time_Stamp_1st(); for(B_u32 = 0 ; B_u32 < 200 ; B_u32++) { for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { IPv6_Size_to_Mask(A_u8, L_u64, H_u64); M_t[B_u32][A_u8].H = BSwap64(H_u64); M_t[B_u32][A_u8].L = BSwap64(L_u64); } } A_u64 = Read_Time_Stamp_2nd() - A_u64; printf("Initialize mask array: %u\n\n", A_u64); // Initialize mask array A_u64 = Read_Time_Stamp_1st(); for(B_u32 = 0 ; B_u32 < 200 ; B_u32++) { for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { IPv6_Size_to_Mask(A_u8, L_u64, H_u64); M_t[B_u32][A_u8].H = BSwap64(H_u64); M_t[B_u32][A_u8].L = BSwap64(L_u64); } } A_u64 = Read_Time_Stamp_2nd() - A_u64; printf("Initialize mask array: %u\n\n", A_u64); // Test IPv6_Mask_to_Size A_u64 = Read_Time_Stamp_1st(); for(B_u32 = 0 ; B_u32 < 200 ; B_u32++) { for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { H_u64 = BSwap64(M_t[B_u32][A_u8].H); L_u64 = BSwap64(M_t[B_u32][A_u8].L); S1_t[B_u32][A_u8] = IPv6_Mask_to_Size_2(L_u64, H_u64); } } A_u64 = Read_Time_Stamp_2nd() - A_u64; printf("IPv6_Mask_to_Size: %u\nValues: ", A_u64); for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { printf("%d ",S1_t[0][A_u8]); } printf("\n\n"); // Test IPv6_Mask_to_Size_BSF_2 A_u64 = Read_Time_Stamp_1st(); for(B_u32 = 0 ; B_u32 < 200 ; B_u32++) { for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { H_u64 = BSwap64(M_t[B_u32][A_u8].H); L_u64 = BSwap64(M_t[B_u32][A_u8].L); S2_t[B_u32][A_u8] = IPv6_Mask_to_Size_BSF_2(L_u64, H_u64); } } A_u64 = Read_Time_Stamp_2nd() - A_u64; printf("IPv6_Mask_to_Size_BSF_2: %u\nValues: ", A_u64); for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { printf("%d ",S2_t[0][A_u8]); } printf("\n\n"); // Test IPv6_Mask_to_Size_Validate A_u64 = Read_Time_Stamp_1st(); for(B_u32 = 0 ; B_u32 < 200 ; B_u32++) { for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { H_u64 = BSwap64(M_t[B_u32][A_u8].H); L_u64 = BSwap64(M_t[B_u32][A_u8].L); R_i += IPv6_Mask_to_Size_Validate(L_u64, H_u64, S3_t[B_u32][A_u8]); } } A_u64 = Read_Time_Stamp_2nd() - A_u64; printf("IPv6_Mask_to_Size_Validate: %u\nValues: ", A_u64); for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { printf("%d ",S3_t[0][A_u8]); } printf("\nR: %d\n\n", R_i); // Test mask2prefixlen6 A_u64 = Read_Time_Stamp_1st(); for(B_u32 = 0 ; B_u32 < 200 ; B_u32++) { for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { S4_t[B_u32][A_u8] = mask2prefixlen6((uint8_t *) &M_t[B_u32][A_u8]); } } A_u64 = Read_Time_Stamp_2nd() - A_u64; printf("mask2prefixlen6: %u\nValues: ", A_u64); for(A_u8 = 0 ; A_u8 < 129 ; A_u8++) { printf("%d ",S4_t[0][A_u8]); } printf("\n\n\n"); return(1); }