/* * 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) 2005, 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); * } * * Flow : * * For small 6 or fewer bytes stores, bytes will be stored. * * For less than 32 bytes stores, align the address on 4 byte boundary. * Then store as many 4-byte chunks, followed by trailing bytes. * * For sizes greater than 32 bytes, align the address on 8 byte boundary. * if (count > 64) { * store as many 8-bytes chunks to block align the address * store using ASI_BLK_INIT_ST_QUAD_LDD_P * } * Store as many 8-byte chunks, followed by trialing bytes. * */ #include #include #include ANSI_PRAGMA_WEAK(memset,function) .section ".text" .align 32 ENTRY(memset) mov %o0, %o5 ! copy sp1 before using it cmp %o2, 7 ! if small counts, just write bytes blu,pn %ncc, .wrchar and %o1, 0xff, %o1 ! o1 is (char)c sll %o1, 8, %o3 or %o1, %o3, %o1 ! now o1 has 2 bytes of c sll %o1, 16, %o3 cmp %o2, 0x20 blu,pn %ncc, .wdalign or %o1, %o3, %o1 ! now o1 has 4 bytes of c sllx %o1, 32, %o3 or %o1, %o3, %o1 ! now o1 has 8 bytes of c .dbalign: andcc %o5, 7, %o3 ! is sp1 aligned on a 8 byte bound bz,pt %ncc, .blkalign ! already double aligned 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) .blkalign: mov ASI_BLK_INIT_ST_QUAD_LDD_P, %asi cmp %o2, 0x40 ! check if there are 64 bytes to set blu,pn %ncc, 5f mov %o2, %o3 andcc %o5, 63, %o3 ! is sp1 block aligned? bz,pt %ncc, .blkwr ! 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 ! Now sp1 is block aligned .blkwr: and %o2, 63, %o3 ! calc bytes left after blk store. andn %o2, 63, %o4 ! calc size of blocks in bytes cmp %o4, 0x100 ! check if there are 256 bytes to set blu,pn %ncc, 3f nop 2: stxa %o1, [%o5+0x0]%asi stxa %o1, [%o5+0x40]%asi stxa %o1, [%o5+0x80]%asi stxa %o1, [%o5+0xc0]%asi stxa %o1, [%o5+0x8]%asi stxa %o1, [%o5+0x10]%asi stxa %o1, [%o5+0x18]%asi stxa %o1, [%o5+0x20]%asi stxa %o1, [%o5+0x28]%asi stxa %o1, [%o5+0x30]%asi stxa %o1, [%o5+0x38]%asi stxa %o1, [%o5+0x48]%asi stxa %o1, [%o5+0x50]%asi stxa %o1, [%o5+0x58]%asi stxa %o1, [%o5+0x60]%asi stxa %o1, [%o5+0x68]%asi stxa %o1, [%o5+0x70]%asi stxa %o1, [%o5+0x78]%asi stxa %o1, [%o5+0x88]%asi stxa %o1, [%o5+0x90]%asi stxa %o1, [%o5+0x98]%asi stxa %o1, [%o5+0xa0]%asi stxa %o1, [%o5+0xa8]%asi stxa %o1, [%o5+0xb0]%asi stxa %o1, [%o5+0xb8]%asi stxa %o1, [%o5+0xc8]%asi stxa %o1, [%o5+0xd0]%asi stxa %o1, [%o5+0xd8]%asi stxa %o1, [%o5+0xe0]%asi stxa %o1, [%o5+0xe8]%asi stxa %o1, [%o5+0xf0]%asi stxa %o1, [%o5+0xf8]%asi sub %o4, 0x100, %o4 cmp %o4, 0x100 bgu,pt %ncc, 2b add %o5, 0x100, %o5 3: cmp %o4, 0x40 ! check if 64 bytes to set blu %ncc, 5f nop 4: stxa %o1, [%o5+0x0]%asi stxa %o1, [%o5+0x8]%asi stxa %o1, [%o5+0x10]%asi stxa %o1, [%o5+0x18]%asi stxa %o1, [%o5+0x20]%asi stxa %o1, [%o5+0x28]%asi stxa %o1, [%o5+0x30]%asi stxa %o1, [%o5+0x38]%asi subcc %o4, 0x40, %o4 bgu,pt %ncc, 4b add %o5, 0x40, %o5 5: ! Set the remaining doubles membar #Sync mov ASI_PNF, %asi ! restore %asi to default ! ASI_PRIMARY_NOFAULT value subcc %o3, 8, %o3 ! Can we store any doubles? blu,pn %ncc, .wrchar and %o2, 7, %o2 ! calc bytes left after doubles 6: stx %o1, [%o5] ! store the doubles subcc %o3, 8, %o3 bgeu,pt %ncc, 6b add %o5, 8, %o5 ba .wrchar nop .wdalign: andcc %o5, 3, %o3 ! is sp1 aligned on a word boundary bz,pn %ncc, .wrword andn %o2, 3, %o3 ! create word sized count in %o3 dec %o2 ! decrement count stb %o1, [%o5] ! clear a byte b .wdalign inc %o5 ! next byte .wrword: st %o1, [%o5] ! 4-byte writing loop subcc %o3, 4, %o3 bnz,pt %ncc, .wrword inc 4, %o5 and %o2, 3, %o2 ! leftover count, if any .wrchar: ! Set the remaining bytes, if any cmp %o2, 0 be %ncc, .exit nop 7: deccc %o2 stb %o1, [%o5] bgu,pt %ncc, 7b inc %o5 .exit: retl ! %o0 was preserved nop SET_SIZE(memset)