/* * User string length functions for kernel * * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #define isrc r0 #define max r1 /* Do not change! */ #define end r2 #define tmp1 r3 #define obo r6 /* off-by-one */ #define start r7 #define mod8 r8 #define dbuf r15:14 #define dcmp r13:12 /* * The vector mask version of this turned out *really* badly. * The hardware loop version also turned out *really* badly. * Seems straight pointer arithmetic basically wins here. */ #define fname __strnlen_user .text .global fname .type fname, @function .p2align 5 /* why? */ fname: { mod8 = and(isrc,#7); end = add(isrc,max); start = isrc; } { P0 = cmp.eq(mod8,#0); mod8 = and(end,#7); dcmp = #0; if (P0.new) jump:t dw_loop; /* fire up the oven */ } alignment_loop: fail_1: { tmp1 = memb(start++#1); } { P0 = cmp.eq(tmp1,#0); if (P0.new) jump:nt exit_found; P1 = cmp.gtu(end,start); mod8 = and(start,#7); } { if (!P1) jump exit_error; /* hit the end */ P0 = cmp.eq(mod8,#0); } { if (!P0) jump alignment_loop; } dw_loop: fail_2: { dbuf = memd(start); obo = add(start,#1); } { P0 = vcmpb.eq(dbuf,dcmp); } { tmp1 = P0; P0 = cmp.gtu(end,start); } { tmp1 = ct0(tmp1); mod8 = and(end,#7); if (!P0) jump end_check; } { P0 = cmp.eq(tmp1,#32); if (!P0.new) jump:nt exit_found; if (!P0.new) start = add(obo,tmp1); } { start = add(start,#8); jump dw_loop; } /* might be nice to combine these jumps... */ end_check: { P0 = cmp.gt(tmp1,mod8); if (P0.new) jump:nt exit_error; /* neverfound! */ start = add(obo,tmp1); } exit_found: { R0 = sub(start,isrc); jumpr R31; } exit_error: { R0 = add(max,#1); jumpr R31; } /* Uh, what does the "fixup" return here? */ .falign fix_1: { R0 = #0; jumpr R31; } .size fname,.-fname .section __ex_table,"a" .long fail_1,fix_1 .long fail_2,fix_1 .previous