1: /* $Header: bigmath.c 1.4 83/06/09 00:50:06 sklower Exp $ */ 2: 3: #include "config.h" 4: 5: .globl _dmlad 6: /* 7: routine for destructive multiplication and addition to a bignum by 8: two fixnums. 9: 10: from C, the invocation is dmlad(sdot,mul,add); 11: where sdot is the address of the first special cell of the bignum 12: mul is the multiplier, add is the fixnum to be added (The latter 13: being passed by value, as is the usual case. 14: 15: 16: Register assignments: 17: 18: r11 = current sdot 19: r10 = carry 20: r9 = previous sdot, for relinking. 21: */ 22: _dmlad: .word 0x0e00 23: movl 4(ap),r11 #initialize cell pointer 24: movl 12(ap),r10 #initialize carry 25: loop: emul 8(ap),(r11),r10,r0 #r0 gets cell->car times mul + carry 26: /* ediv $0x40000000,r0,r10,(r11)#cell->car gets prod % 2**30 27: #carry gets quotient 28: */ 29: extzv $0,$30,r0,(r11) 30: extv $30,$32,r0,r10 31: movl r11,r9 #save last cell for fixup at end. 32: movl 4(r11),r11 #move to next cell 33: bneq loop #done indicated by 0 for next sdot 34: tstl r10 #if carry zero no need to allocate 35: beql done #new bigit 36: mcoml r10,r3 #test to see if neg 1. 37: bneq alloc #if not must allocate new cell. 38: tstl (r9) #make sure product isn't -2**30 39: beql alloc 40: movl r0,(r9) #save old lower half of product. 41: brb done 42: alloc: jsb _qnewdot #otherwise allocate new bigit 43: movl r10,(r0) #store carry 44: movl r0,4(r9) #save new link cell 45: done: movl 4(ap),r0 46: ret 47: .globl _dodiv 48: /* 49: routine to destructively divide array representation of a bignum by 50: 1000000000 51: 52: invocation: 53: remainder = dodiv(top,bottom) 54: int *top, *bottom; 55: where *bottom is the address of the biggning of the array, *top is 56: the top of the array. 57: 58: register assignments: 59: r0 = carry 60: r1 & r2 = 64bit temporary 61: r3 = pointer 62: */ 63: _dodiv: .word 0 64: clrl r0 #no carry to begin. 65: movl 8(ap),r3 #get pointer to array. 66: loop2: emul $0x40000000,r0,(r3),r1 67: ediv $1000000000,r1,(r3),r0 68: acbl 4(ap),$4,r3,loop2 69: ret 70: .globl _dsneg 71: /* 72: dsneg(top, bot); 73: int *top, *bot; 74: 75: routine to destructively negate a bignum stored in array format 76: lower order stuff at higher addresses. It is assume that the 77: result will be positive. 78: */ 79: _dsneg: .word 0 80: movl 4(ap),r1 #load up address. 81: clrl r2 #set carry 82: loop3: mnegl (r1),r0 #negate and take carry into account. 83: addl2 r2,r0 84: extzv $0,$30,r0,(r1) 85: extv $30,$2,r0,r2 86: acbl 8(ap),$-4,r1,loop3 87: #decrease r1, and branch back if appropriate. 88: ret 89: 90: /* 91: bignum add routine 92: basic data representation is each bigit is a positive number 93: less than 2^30, except for the leading bigit, which is in 94: the range -2^30 < x < 2^30. 95: */ 96: 97: .globl _adbig 98: .globl Bexport 99: .globl backfr 100: /* 101: Initialization section 102: */ 103: _adbig: .word 0x0fc0 #save registers 6-11 104: movl 4(ap),r1 #arg1 = addr of 1st bignum 105: movl 8(ap),r2 #arg2 = addr of 2nd bignum 106: clrl r5 #r5 = carry 107: movl $0xC0000000,r4 #r4 = clear constant. 108: movl sp,r10 #save start address of bignum on stack. 109: #note well that this is 4 above the actual 110: #low order word. 111: /* 112: first loop is to waltz through both bignums adding 113: bigits, pushing them onto stack. 114: */ 115: loop4: addl3 (r1),(r2),r0 #add bigits 116: addl2 r5,r0 #add carry 117: bicl3 r4,r0,-(sp) #save sum, no overflow possible 118: extv $30,$2,r0,r5 #sign extend two high order bits 119: #to be next carry. 120: movl 4(r1),r1 #get cdr 121: bleq out1 #negative indicates end of list. 122: movl 4(r2),r2 #get cdr of second bignum 123: bgtr loop4 #if neither list at end, do it again 124: /* 125: second loop propagates carries through higher order words. 126: It assumes remaining list in r1. 127: */ 128: loop5: addl3 (r1),r5,r0 #add bigits and carry 129: bicl3 r4,r0,-(sp) #save sum, no overflow possible 130: extv $30,$2,r0,r5 #sign extend two high order bits 131: #to be next carry. 132: movl 4(r1),r1 #get cdr 133: out2: bgtr loop5 #negative indicates end of list. 134: out2a: pushl r5 135: /* 136: suppress unnecessary leading zeroes and -1's 137: 138: WARNING: this code is duplicated in C in divbig.c 139: */ 140: iexport:movl sp,r11 #more set up for output routine 141: ckloop: 142: Bexport:tstl (r11) #look at leading bigit 143: bgtr copyit #if positive, can allocate storage etc. 144: blss negchk #if neg, still a chance we can get by 145: cmpl r11,r10 #check to see that 146: bgeq copyit #we don't pop everything off of stack 147: tstl (r11)+ #incr r11 148: brb ckloop #examine next 149: negchk: 150: mcoml (r11),r3 #r3 is junk register 151: bneq copyit #short test for -1 152: tstl 4(r11) #examine next bigit 153: beql copyit #if zero must must leave as is. 154: cmpl r11,r10 #check to see that 155: bgeq copyit #we don't pop everything off of stack 156: tstl (r11)+ #incr r11 157: bisl2 r4,(r11) #set high order two bits 158: brb negchk #try to supress more leading -1's 159: /* 160: The following code is an error exit from the first loop 161: and is out of place to avoid a jump around a jump. 162: */ 163: out1: movl 4(r2),r1 #get next addr of list to continue. 164: brb out2 #if second list simult. exhausted, do 165: #right thing. 166: /* 167: loop6 is a faster version of loop5 when carries are no 168: longer necessary. 169: */ 170: loop6a: pushl (r1) #get datum 171: loop6: movl 4(r1),r1 #get cdr 172: bgtr loop6a #if not at end get next cell 173: brb out2a 174: 175: /* 176: create linked list representation of bignum 177: */ 178: copyit: subl3 r11,r10,r2 #see if we can get away with allocating an int 179: bneq on1 #test for having popped everything 180: subl3 $4,r10,r11 #if so, fix up pointer to bottom 181: brb intout #and allocate int. 182: on1: cmpl r2,$4 #if = 4, then can do 183: beql intout 184: calls $0,_newsdot #get new cell for new bignum 185: backfr: 186: #ifdef PORTABLE 187: movl r0,*_np 188: addl2 $4,_np 189: #else 190: movl r0,(r6)+ #push address of cell on 191: #arg stack to save from garbage collection. 192: #There is guaranteed to be slop for a least 1 193: #push without checking. 194: #endif 195: loop7: movl -(r10),(r0) #save bigit 196: movl r0,r9 #r9 = old cell, to link 197: cmpl r10,r11 #have we copy'ed all the bigits? 198: bleq Edone 199: jsb _qnewdot #get new cell for new bignum 200: movl r0,4(r9) #link new cell to old 201: brb loop7 202: Edone: 203: clrl 4(r9) #indicate end of list with 0 204: #ifdef PORTABLE 205: subl2 $4,_np 206: movl *_np,r0 207: #else 208: movl -(r6),r0 #give resultant address. 209: #endif 210: ret 211: /* 212: export integer 213: */ 214: intout: pushl (r11) 215: calls $1,_inewint 216: ret 217: .globl _mulbig 218: /* 219: bignum multiplication routine 220: 221: Initialization section 222: */ 223: _mulbig:.word 0x0fc0 #save regs 6-11 224: movl 4(ap),r1 #get address of first bignum 225: movl sp,r11 #save top of 1st bignum 226: mloop1: pushl (r1) #get bigit 227: movl 4(r1),r1 #get cdr 228: bgtr mloop1 #repeat if not done 229: movl sp,r10 #save bottom of 1st bignum, top of 2nd bignum 230: 231: movl 8(ap),r1 #get address of 2nd bignum 232: mloop2: pushl (r1) #get bigit 233: movl 4(r1),r1 #get cdr 234: bgtr mloop2 #repeat if not done 235: movl sp,r9 #save bottom of 2nd bignum 236: subl3 r9,r11,r6 #r6 contains sum of lengths of bignums 237: subl2 r6,sp 238: movl sp,r8 #save bottom of product bignum 239: /* 240: Actual multiplication 241: */ 242: m1: movc5 $0,(r8),$0,r6,(r8)#zap out stack space 243: movl r9,r7 #r7 = &w[j +n] (+4 for a.d.) through calculation 244: subl3 $4,r10,r4 #r4 = &v[j] 245: 246: m3: movl r7,r5 #r7 = &w[j+n] 247: subl3 $4,r11,r3 #r3 = &u[i] 248: clrl r2 #clear carry. 249: 250: m4: addl2 -(r5),r2 #add w[i + j] to carry (no ofl poss) 251: emul (r3),(r4),r2,r0 #r0 = u[i] * v[j] + sext(carry) 252: extzv $0,$30,r0,(r5) #get new bigit 253: extv $30,$32,r0,r2 #get new carry 254: 255: m5: acbl r10,$-4,r3,m4 #r3 =- 4; if(r3 >= r10) goto m4; r10 = &[u1]; 256: movl r2,-(r5) #save w[j] = carry 257: 258: m6: subl2 $4,r7 #add just &w[j+n] (+4 for autodec) 259: acbl r9,$-4,r4,m3 #r4 =- 4; if(r4>=r9) goto m5; r9 = &v[1] 260: 261: movl r9,r10 #set up for output routine 262: movl $0xC0000000,r4 #r4 = clear constant. 263: movq 20(fp),r6 #restor _np and _lbot ! 264: brw iexport #do it! 265: /* 266: The remainder of this file are routines used in bignum division. 267: Interested parties should consult Knuth, Vol 2, and divbig.c. 268: These files are here only due to an optimizer bug. 269: */ 270: .align 1 271: .globl _calqhat 272: _calqhat: 273: .word 0xf00 274: movl 4(ap),r11 # &u[j] into r11 275: movl 8(ap),r10 # &v[1] into r10 276: cmpl (r10),(r11) # v[1] == u[j] ?? 277: beql L102 278: # calculate qhat and rhat simultaneously, 279: # qhat in r0 280: # rhat in r1 281: emul (r11),$0x40000000,4(r11),r4 # u[j]b+u[j+1] into r4,r5 282: ediv (r10),r4,r0,r1 # qhat = ((u[j]b+u[j+1])/v[1]) into r0 283: # (u[j]b+u[j+1] -qhat*v[1]) into r1 284: # called rhat 285: L101: 286: # check if v[2]*qhat > rhat*b+u[j+2] 287: emul r0,4(r10),$0,r2 # qhat*v[2] into r3,r2 288: emul r1,$0x40000000,8(r11),r8 #rhat*b + u[j+2] into r9,r8 289: # give up if r3,r2 <= r9,r8, otherwise iterate 290: subl2 r8,r2 # perform r3,r2 - r9,r8 291: sbwc r9,r3 292: bleq L103 # give up if negative or equal 293: decl r0 # otherwise, qhat = qhat - 1 294: addl2 (r10),r1 # since dec'ed qhat, inc rhat by v[1] 295: jbr L101 296: L102: 297: # get here if v[1]==u[j] 298: # set qhat to b-1 299: # rhat is easily calculated since if we substitute b-1 for qhat in 300: # the formula, then it simplifies to (u[j+1] + v[1]) 301: # 302: addl3 4(r11),(r10),r1 # rhat = u[j+1] + v[1] 303: movl $0x3fffffff,r0 # qhat = b-1 304: jbr L101 305: 306: L103: 307: ret 308: 309: .align 1 310: .globl _mlsb 311: _mlsb: 312: .word .R2 313: movl 4(ap),r11 314: movl 8(ap),r10 315: movl 12(ap),r9 316: movl 16(ap),r8 317: clrl r0 318: loop8: addl2 (r11),r0 319: emul r8,-(r9),r0,r2 320: extzv $0,$30,r2,(r11) 321: extv $30,$32,r2,r0 322: acbl r10,$-4,r11,loop8 323: ret 324: .set .R2,0xf00 325: .align 1 326: .globl _adback 327: _adback: 328: .word .R3 329: movl 4(ap),r11 330: movl 8(ap),r10 331: movl 12(ap),r9 332: clrl r0 333: loop9: addl2 -(r9),r0 334: addl2 (r11),r0 335: extzv $0,$30,r0,(r11) 336: extv $30,$2,r0,r0 337: acbl r10,$-4,r11,loop9 338: ret 339: .set .R3,0xe00 340: .align 1 341: .globl _dsdiv 342: _dsdiv: 343: .word .R4 344: movl 8(ap),r11 345: clrl r0 346: loopa: emul r0,$0x40000000,(r11),r1 347: ediv 12(ap),r1,(r11),r0 348: acbl 4(ap),$4,r11,loopa 349: ret 350: .set .R4,0x800 351: .align 1 352: .globl _dsmult 353: _dsmult: 354: .word .R5 355: movl 4(ap),r11 356: clrl r0 357: loopb: emul 12(ap),(r11),r0,r1 358: extzv $0,$30,r1,(r11) 359: extv $30,$32,r1,r0 360: acbl 8(ap),$-4,r11,loopb 361: movl r1,4(r11) 362: ret 363: .set .R5,0x800 364: .align 1 365: .globl _dsrsh 366: _dsrsh: 367: .word .R7 368: movl 8(ap),r11 # bot 369: movl 16(ap),r5 # mask 370: movl 12(ap),r4 # shift count 371: clrl r0 372: L201: emul r0,$0x40000000,(r11),r1 373: bicl3 r5,r1,r0 374: ashq r4,r1,r1 375: movl r1,(r11) 376: acbl 4(ap),$4,r11,L201 377: ret 378: .set .R7,0x800 379: .align 1 380: .globl _dsadd1 381: _dsadd1: 382: .word .R8 383: movl 4(ap),r11 384: movl $1,r0 385: L501: emul $1,(r11),r0,r1 386: extzv $0,$30,r1,(r11) 387: extv $30,$32,r1,r0 388: acbl 8(ap),$-4,r11,L501 389: movl r1,4(r11) 390: ret 391: .set .R8,0x800 392: /* 393: myfrexp (value, exp, hi, lo) 394: double value; 395: int *exp, *hi, *lo; 396: 397: myfrexp returns three values, exp, hi, lo, 398: Such that value = 2**exp*tmp, where tmp = (hi*2**-23+lo*2**-53) 399: is uniquely determined subect to .5< abs(tmp) <= 1.0 400: 401: 402: Entry point 403: */ 404: .text 405: .globl _myfrexp 406: _myfrexp: 407: .word 0x0000 # We use r2, but do not save it 408: 409: clrl *12(ap) # Make for easy exit later 410: clrl *16(ap) # 411: clrl *20(ap) # 412: movd 4(ap),r0 # Fetch "value" 413: bneq L301 # if zero return zero exponent + mantissa 414: ret 415: L301: 416: extzv $7,$8,r0,r2 # r2 := biased exponent 417: movab -129(r2),*12(ap)# subtract bias, store exp 418: insv $154,$7,$8,r0 # lie about exponent to get out 419: # high 24 bits easily with emodd. 420: /* 421: This instruction does the following: 422: 423: Extend the long floating value in r0 with 0, and 424: multiply it by 1.0. Store the integer part of the result 425: in hi, and the fractional part of the result in r0-r1. 426: */ 427: emodd r0,$0,$0f1.0,*16(ap),r0 # How did you like 428: # THAT, sports fans? [jfr's comment] 429: 430: tstd r0 # if zero, exit; 431: bneq L401 432: ret 433: L401: 434: insv $158,$7,$8,r0 # lie about exponent to get out 435: # next 30 bits easily with emodd. 436: # (2^29 takes 30 bits). 437: emodd r0,$0,$0f1.0,*20(ap),r0 # Get last bits out likewise! 438: ret # (r0 should be zero by now!) 439: .globl _inewint 440: _inewint:.word 0 441: movl 4(ap),r0 442: cmpl r0,$1024 443: jgeq Ialloc 444: cmpl r0,$-1024 445: jlss Ialloc 446: moval _Fixzero[r0],r0 447: ret 448: Ialloc: 449: calls $0,_newint 450: movl 4(ap),0(r0) 451: ret 452: .globl _blzero 453: _blzero: # blzero(where,howmuch) 454: # char *where; 455: # zeroes a block of length howmuch 456: # beginning at where. 457: .word 0 458: movc5 $0,*4(ap),$0,8(ap),*4(ap) 459: ret