Skip to content

Commit

Permalink
microblaze: Add libgcc function directly to kernel
Browse files Browse the repository at this point in the history
Replaced libgcc functions with asm optimized implementation.

Signed-off-by: Michal Simek <[email protected]>
  • Loading branch information
michalsimek committed Oct 21, 2010
1 parent cec0516 commit 4e07dba
Show file tree
Hide file tree
Showing 13 changed files with 607 additions and 28 deletions.
3 changes: 0 additions & 3 deletions arch/microblaze/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,8 @@ KBUILD_CFLAGS += -ffixed-r31 $(CPUFLAGS-1) $(CPUFLAGS-2)
LDFLAGS :=
LDFLAGS_vmlinux :=

LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)

head-y := arch/microblaze/kernel/head.o
libs-y += arch/microblaze/lib/
libs-y += $(LIBGCC)
core-y += arch/microblaze/kernel/
core-y += arch/microblaze/mm/
core-y += arch/microblaze/platform/
Expand Down
25 changes: 0 additions & 25 deletions arch/microblaze/kernel/microblaze_ksyms.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,6 @@
#include <linux/ftrace.h>
#include <linux/uaccess.h>

/*
* libgcc functions - functions that are used internally by the
* compiler... (prototypes are not correct though, but that
* doesn't really matter since they're not versioned).
*/
extern void __ashldi3(void);
EXPORT_SYMBOL(__ashldi3);
extern void __ashrdi3(void);
EXPORT_SYMBOL(__ashrdi3);
extern void __divsi3(void);
EXPORT_SYMBOL(__divsi3);
extern void __lshrdi3(void);
EXPORT_SYMBOL(__lshrdi3);
extern void __modsi3(void);
EXPORT_SYMBOL(__modsi3);
extern void __mulsi3(void);
EXPORT_SYMBOL(__mulsi3);
extern void __muldi3(void);
EXPORT_SYMBOL(__muldi3);
extern void __ucmpdi2(void);
EXPORT_SYMBOL(__ucmpdi2);
extern void __udivsi3(void);
EXPORT_SYMBOL(__udivsi3);
extern void __umodsi3(void);
EXPORT_SYMBOL(__umodsi3);
extern char *_ebss;
EXPORT_SYMBOL_GPL(_ebss);
#ifdef CONFIG_FUNCTION_TRACER
Expand Down
10 changes: 10 additions & 0 deletions arch/microblaze/lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,13 @@ lib-y += memcpy.o memmove.o
endif

lib-y += uaccess_old.o

lib-y += ashldi3.o
lib-y += ashrdi3.o
lib-y += divsi3.o
lib-y += lshrdi3.o
lib-y += modsi3.o
lib-y += muldi3.o
lib-y += mulsi3.o
lib-y += udivsi3.o
lib-y += umodsi3.o
29 changes: 29 additions & 0 deletions arch/microblaze/lib/ashldi3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <linux/module.h>

#include "libgcc.h"

long long __ashldi3(long long u, word_type b)
{
DWunion uu, w;
word_type bm;

if (b == 0)
return u;

uu.ll = u;
bm = 32 - b;

if (bm <= 0) {
w.s.low = 0;
w.s.high = (unsigned int) uu.s.low << -bm;
} else {
const unsigned int carries = (unsigned int) uu.s.low >> bm;

w.s.low = (unsigned int) uu.s.low << b;
w.s.high = ((unsigned int) uu.s.high << b) | carries;
}

return w.ll;
}

EXPORT_SYMBOL(__ashldi3);
31 changes: 31 additions & 0 deletions arch/microblaze/lib/ashrdi3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <linux/module.h>

#include "libgcc.h"

long long __ashrdi3(long long u, word_type b)
{
DWunion uu, w;
word_type bm;

if (b == 0)
return u;

uu.ll = u;
bm = 32 - b;

if (bm <= 0) {
/* w.s.high = 1..1 or 0..0 */
w.s.high =
uu.s.high >> 31;
w.s.low = uu.s.high >> -bm;
} else {
const unsigned int carries = (unsigned int) uu.s.high << bm;

w.s.high = uu.s.high >> b;
w.s.low = ((unsigned int) uu.s.low >> b) | carries;
}

return w.ll;
}

EXPORT_SYMBOL(__ashrdi3);
73 changes: 73 additions & 0 deletions arch/microblaze/lib/divsi3.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <linux/linkage.h>

/*
* Divide operation for 32 bit integers.
* Input : Dividend in Reg r5
* Divisor in Reg r6
* Output: Result in Reg r3
*/
.text
.globl __divsi3
.type __divsi3, @function
.ent __divsi3
__divsi3:
.frame r1, 0, r15

addik r1, r1, -16
swi r28, r1, 0
swi r29, r1, 4
swi r30, r1, 8
swi r31, r1, 12

beqi r6, div_by_zero /* div_by_zero - division error */
beqi r5, result_is_zero /* result is zero */
bgeid r5, r5_pos
xor r28, r5, r6 /* get the sign of the result */
rsubi r5, r5, 0 /* make r5 positive */
r5_pos:
bgei r6, r6_pos
rsubi r6, r6, 0 /* make r6 positive */
r6_pos:
addik r30, r0, 0 /* clear mod */
addik r3, r0, 0 /* clear div */
addik r29, r0, 32 /* initialize the loop count */

/* first part try to find the first '1' in the r5 */
div0:
blti r5, div2 /* this traps r5 == 0x80000000 */
div1:
add r5, r5, r5 /* left shift logical r5 */
bgtid r5, div1
addik r29, r29, -1
div2:
/* left shift logical r5 get the '1' into the carry */
add r5, r5, r5
addc r30, r30, r30 /* move that bit into the mod register */
rsub r31, r6, r30 /* try to subtract (r30 a r6) */
blti r31, mod_too_small
/* move the r31 to mod since the result was positive */
or r30, r0, r31
addik r3, r3, 1
mod_too_small:
addik r29, r29, -1
beqi r29, loop_end
add r3, r3, r3 /* shift in the '1' into div */
bri div2 /* div2 */
loop_end:
bgei r28, return_here
brid return_here
rsubi r3, r3, 0 /* negate the result */
div_by_zero:
result_is_zero:
or r3, r0, r0 /* set result to 0 */
return_here:
/* restore values of csrs and that of r3 and the divisor and the dividend */
lwi r28, r1, 0
lwi r29, r1, 4
lwi r30, r1, 8
lwi r31, r1, 12
rtsd r15, 8
addik r1, r1, 16

.size __divsi3, . - __divsi3
.end __divsi3
25 changes: 25 additions & 0 deletions arch/microblaze/lib/libgcc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef __ASM_LIBGCC_H
#define __ASM_LIBGCC_H

#include <asm/byteorder.h>

typedef int word_type __attribute__ ((mode (__word__)));

#ifdef __BIG_ENDIAN
struct DWstruct {
int high, low;
};
#elif defined(__LITTLE_ENDIAN)
struct DWstruct {
int low, high;
};
#else
#error I feel sick.
#endif

typedef union {
struct DWstruct s;
long long ll;
} DWunion;

#endif /* __ASM_LIBGCC_H */
29 changes: 29 additions & 0 deletions arch/microblaze/lib/lshrdi3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <linux/module.h>

#include "libgcc.h"

long long __lshrdi3(long long u, word_type b)
{
DWunion uu, w;
word_type bm;

if (b == 0)
return u;

uu.ll = u;
bm = 32 - b;

if (bm <= 0) {
w.s.high = 0;
w.s.low = (unsigned int) uu.s.high >> -bm;
} else {
const unsigned int carries = (unsigned int) uu.s.high << bm;

w.s.high = (unsigned int) uu.s.high >> b;
w.s.low = ((unsigned int) uu.s.low >> b) | carries;
}

return w.ll;
}

EXPORT_SYMBOL(__lshrdi3);
73 changes: 73 additions & 0 deletions arch/microblaze/lib/modsi3.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <linux/linkage.h>

/*
* modulo operation for 32 bit integers.
* Input : op1 in Reg r5
* op2 in Reg r6
* Output: op1 mod op2 in Reg r3
*/

.text
.globl __modsi3
.type __modsi3, @function
.ent __modsi3

__modsi3:
.frame r1, 0, r15

addik r1, r1, -16
swi r28, r1, 0
swi r29, r1, 4
swi r30, r1, 8
swi r31, r1, 12

beqi r6, div_by_zero /* div_by_zero division error */
beqi r5, result_is_zero /* result is zero */
bgeid r5, r5_pos
/* get the sign of the result [ depends only on the first arg] */
add r28, r5, r0
rsubi r5, r5, 0 /* make r5 positive */
r5_pos:
bgei r6, r6_pos
rsubi r6, r6, 0 /* make r6 positive */
r6_pos:
addik r3, r0, 0 /* clear mod */
addik r30, r0, 0 /* clear div */
addik r29, r0, 32 /* initialize the loop count */
/* first part try to find the first '1' in the r5 */
div1:
add r5, r5, r5 /* left shift logical r5 */
bgeid r5, div1
addik r29, r29, -1
div2:
/* left shift logical r5 get the '1' into the carry */
add r5, r5, r5
addc r3, r3, r3 /* move that bit into the mod register */
rsub r31, r6, r3 /* try to subtract (r30 a r6) */
blti r31, mod_too_small
/* move the r31 to mod since the result was positive */
or r3, r0, r31
addik r30, r30, 1
mod_too_small:
addik r29, r29, -1
beqi r29, loop_end
add r30, r30, r30 /* shift in the '1' into div */
bri div2 /* div2 */
loop_end:
bgei r28, return_here
brid return_here
rsubi r3, r3, 0 /* negate the result */
div_by_zero:
result_is_zero:
or r3, r0, r0 /* set result to 0 [both mod as well as div are 0] */
return_here:
/* restore values of csrs and that of r3 and the divisor and the dividend */
lwi r28, r1, 0
lwi r29, r1, 4
lwi r30, r1, 8
lwi r31, r1, 12
rtsd r15, 8
addik r1, r1, 16

.size __modsi3, . - __modsi3
.end __modsi3
Loading

0 comments on commit 4e07dba

Please sign in to comment.