/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ .file "memset.s" /* * char *memset(sp, c, n) * * Set an array of n chars starting at sp to the character c. * Return sp. * * Fast assembler language version of the following C-program for memset * which represents the `standard' for the C-library. * * void * * memset(void *sp1, int c, size_t n) * { * if (n != 0) { * char *sp = sp1; * do { * *sp++ = (char)c; * } while (--n != 0); * } * return (sp1); * } */ #include #include ANSI_PRAGMA_WEAK(memset,function) #define ALIGN8(X) (((X) + 7) & ~7) .section ".text" .align 32 ENTRY(memset) cmp %o2, 12 ! if small counts, just write bytes bgeu,pn %ncc, .wrbig mov %o0, %o5 ! copy sp1 before using it .wrchar: deccc %o2 ! byte clearing loop inc %o5 bgeu,a,pt %ncc, .wrchar stb %o1, [%o5 + -1] ! we've already incremented the address retl .empty ! next instruction is safe, %o0 still good .wrbig: andcc %o5, 7, %o3 ! is sp1 aligned on a 8 byte bound bz,pt %ncc, .blkchk ! already double aligned and %o1, 0xff, %o1 ! o1 is (char)c sub %o3, 8, %o3 ! -(bytes till double aligned) add %o2, %o3, %o2 ! update o2 with new count ! Set -(%o3) bytes till sp1 double aligned 1: stb %o1, [%o5] ! there is at least 1 byte to set inccc %o3 ! byte clearing loop bl,pt %ncc, 1b inc %o5 ! Now sp1 is double aligned (sp1 is found in %o5) .blkchk: sll %o1, 8, %o3 or %o1, %o3, %o1 ! now o1 has 2 bytes of c sll %o1, 16, %o3 or %o1, %o3, %o1 ! now o1 has 4 bytes of c cmp %o2, 4095 ! if large count use Block ld/st sllx %o1, 32, %o3 or %o1, %o3, %o1 ! now o1 has 8 bytes of c bgu,a,pn %ncc, .blkwr ! Do block write for large count andcc %o5, 63, %o3 ! is sp1 block aligned? and %o2, 24, %o3 ! o3 is {0, 8, 16, 24} 1: subcc %o3, 8, %o3 ! double-word loop add %o5, 8, %o5 bgeu,a,pt %ncc, 1b stx %o1, [%o5 - 8] ! already incremented the address andncc %o2, 31, %o4 ! o4 has 32 byte aligned count bz,pn %ncc, 3f ! First instruction of icache line 2: subcc %o4, 32, %o4 ! main loop, 32 bytes per iteration stx %o1, [%o5 - 8] stx %o1, [%o5] stx %o1, [%o5 + 8] stx %o1, [%o5 + 16] bnz,pt %ncc, 2b add %o5, 32, %o5 3: and %o2, 7, %o2 ! o2 has the remaining bytes (<8) 4: deccc %o2 ! byte clearing loop inc %o5 bgeu,a,pt %ncc, 4b stb %o1, [%o5 - 9] ! already incremented the address retl nop ! %o0 still preserved .blkwr: bz,pn %ncc, .blalign ! now block aligned sub %o3, 64, %o3 ! o3 is -(bytes till block aligned) add %o2, %o3, %o2 ! o2 is the remainder ! Store -(%o3) bytes till dst is block (64 byte) aligned. ! Use double word stores. ! Recall that dst is already double word aligned 1: stx %o1, [%o5] addcc %o3, 8, %o3 bl,pt %ncc, 1b add %o5, 8, %o5 ! sp1 is block aligned .blalign: rd %fprs, %g1 ! g1 = fprs and %o2, 63, %o3 ! calc bytes left after blk store. andcc %g1, 0x4, %g1 ! fprs.du = fprs.dl = 0 bz,a %ncc, 2f ! Is fprs.fef == 0 wr %g0, 0x4, %fprs ! fprs.fef = 1 2: brnz,pn %o1, 3f ! %o1 is safe to check all 64-bits andn %o2, 63, %o4 ! calc size of blocks in bytes fzero %d0 fzero %d2 fzero %d4 fzero %d6 fmuld %d0, %d0, %d8 fzero %d10 ba 4f fmuld %d0, %d0, %d12 3: ! allocate 8 bytes of scratch space on the stack add %sp, -SA(16), %sp stx %o1, [%sp + STACK_BIAS + ALIGN8(MINFRAME)] ! move %o1 to %d0 ldd [%sp + STACK_BIAS + ALIGN8(MINFRAME)], %d0 fmovd %d0, %d2 add %sp, SA(16), %sp ! deallocate the scratch space fmovd %d0, %d4 fmovd %d0, %d6 fmovd %d0, %d8 fmovd %d0, %d10 fmovd %d0, %d12 4: fmovd %d0, %d14 ! 1st quadrant has 64 bytes of c ! instructions 32-byte aligned here stda %d0, [%o5]ASI_BLK_P subcc %o4, 64, %o4 bgu,pt %ncc, 4b add %o5, 64, %o5 ! Set the remaining doubles subcc %o3, 8, %o3 ! Can we store any doubles? blu,pn %ncc, 6f and %o2, 7, %o2 ! calc bytes left after doubles 5: std %d0, [%o5] ! store the doubles subcc %o3, 8, %o3 bgeu,pt %ncc, 5b add %o5, 8, %o5 6: ! Set the remaining bytes brz %o2, .exit ! safe to check all 64-bits #if 0 ! Terminate the copy with a partial store. (bug 1200071 does not apply) ! The data should be at d0 dec %o2 ! needed to get the mask right edge8n %g0, %o2, %o4 stda %d0, [%o5]%o4, ASI_PST8_P #else 7: deccc %o2 stb %o1, [%o5] bgu,pt %ncc, 7b inc %o5 #endif .exit: membar #StoreLoad|#StoreStore retl ! %o0 was preserved wr %g1, %g0, %fprs ! fprs = g1 restore fprs SET_SIZE(memset)