linux/arch/hexagon/mm/strnlen_user.S
<<
>>
Prefs
   1/*
   2 * User string length functions for kernel
   3 *
   4 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 and
   8 * only version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18 * 02110-1301, USA.
  19 */
  20
  21#define isrc    r0
  22#define max     r1      /*  Do not change!  */
  23
  24#define end     r2
  25#define tmp1    r3
  26
  27#define obo     r6      /*  off-by-one  */
  28#define start   r7
  29#define mod8    r8
  30#define dbuf    r15:14
  31#define dcmp    r13:12
  32
  33/*
  34 * The vector mask version of this turned out *really* badly.
  35 * The hardware loop version also turned out *really* badly.
  36 * Seems straight pointer arithmetic basically wins here.
  37 */
  38
  39#define fname __strnlen_user
  40
  41        .text
  42        .global fname
  43        .type fname, @function
  44        .p2align 5  /*  why?  */
  45fname:
  46        {
  47                mod8 = and(isrc,#7);
  48                end = add(isrc,max);
  49                start = isrc;
  50        }
  51        {
  52                P0 = cmp.eq(mod8,#0);
  53                mod8 = and(end,#7);
  54                dcmp = #0;
  55                if (P0.new) jump:t dw_loop;     /*  fire up the oven  */
  56        }
  57
  58alignment_loop:
  59fail_1: {
  60                tmp1 = memb(start++#1);
  61        }
  62        {
  63                P0 = cmp.eq(tmp1,#0);
  64                if (P0.new) jump:nt exit_found;
  65                P1 = cmp.gtu(end,start);
  66                mod8 = and(start,#7);
  67        }
  68        {
  69                if (!P1) jump exit_error;  /*  hit the end  */
  70                P0 = cmp.eq(mod8,#0);
  71        }
  72        {
  73                if (!P0) jump alignment_loop;
  74        }
  75
  76
  77
  78dw_loop:
  79fail_2: {
  80                dbuf = memd(start);
  81                obo = add(start,#1);
  82        }
  83        {
  84                P0 = vcmpb.eq(dbuf,dcmp);
  85        }
  86        {
  87                tmp1 = P0;
  88                P0 = cmp.gtu(end,start);
  89        }
  90        {
  91                tmp1 = ct0(tmp1);
  92                mod8 = and(end,#7);
  93                if (!P0) jump end_check;
  94        }
  95        {
  96                P0 = cmp.eq(tmp1,#32);
  97                if (!P0.new) jump:nt exit_found;
  98                if (!P0.new) start = add(obo,tmp1);
  99        }
 100        {
 101                start = add(start,#8);
 102                jump dw_loop;
 103        }       /*  might be nice to combine these jumps...   */
 104
 105
 106end_check:
 107        {
 108                P0 = cmp.gt(tmp1,mod8);
 109                if (P0.new) jump:nt exit_error; /*  neverfound!  */
 110                start = add(obo,tmp1);
 111        }
 112
 113exit_found:
 114        {
 115                R0 = sub(start,isrc);
 116                jumpr R31;
 117        }
 118
 119exit_error:
 120        {
 121                R0 = add(max,#1);
 122                jumpr R31;
 123        }
 124
 125        /*  Uh, what does the "fixup" return here?  */
 126        .falign
 127fix_1:
 128        {
 129                R0 = #0;
 130                jumpr R31;
 131        }
 132
 133        .size fname,.-fname
 134
 135
 136.section __ex_table,"a"
 137.long fail_1,fix_1
 138.long fail_2,fix_1
 139.previous
 140