// SORTINT      Bubble sort integers from a file

// This program will read 100 or fewer integers from a
// text file, sort them using the bubble sort algorithm,
// and write the sorted list into a text file.
        FLEN    = 40              // File name allowance
        CASES   = 100             // Array length
        NUML    = 8               // Integer size
        .global gets, perror, printf
        .global fopen, fclose, fscanf, fprintf
        .data                     // Declare storage
        .align  8                 // Desirable alignment
ARRAY:  .skip   CASES*NUML        // Room for integers
IFILE:  .skip   FLEN              // Input file name
OFILE:  .skip   FLEN              // Output file name
IPRMT:  stringz "Input from? "
OPRMT:  stringz "Output to? "
IMODE:  stringz "r"               // Read from input file
OMODE:  stringz "w"               // Create output file
TELL:   stringz "The program has processed %d numbers.\n"
PFORM:  stringz "%s"              // Prompts are strings
IFORM:  stringz "%lld"            // Scan for a "word"
OFORM:  stringz "%18lld\n"        // Print number & newline
ERROR:  stringz "Error"
         .text                    // Section for code
        .align  32                // Desirable alignment
        .global main              // These three lines
        .proc   main              //  mark the mandatory
main:                             //   'main' program entry
        .prologue 12,r32          // Mask for rp, ar.pfs only
        alloc   loc0 = ar.pfs,0,8,3,0  // ins, locals, outs
        .save   rp,loc1           // Must save return address
        mov     loc1 = b0;;       //  to our caller
        .body
first:  add     out0 = @gprel(IPRMT),gp  // out0 -> format
        mov     loc2 = gp         // Save gp
        br.call.sptk.many b0 = printf  // Ask about input
        mov     gp = loc2         // Restore gp
        cmp4.lt p6,p0 = ret0,r0   // If any error,
   (p6) br.cond.sptk.few stop0;;  //  go to handler (null)
        add     out0 = @gprel(IFILE),gp  // out0 -> filename
        br.call.sptk.many b0 = gets  // Unformatted input
        mov     gp = loc2         // Restore gp
        cmp.eq  p6,p0 = ret0,r0   // If any error,
   (p6) br.cond.sptk.few stop1;;  //  go to handler (null)
        add     out0 = @gprel(IFILE),gp // out0 -> filename
        add     out1 = @gprel(IMODE),gp // out1 -> mode
        br.call.sptk.many b0 = fopen  // Find input file
        mov     gp = loc2         // Restore gp
        cmp.eq  p6,p0 = ret0,r0   // If any error,
   (p6) br.cond.sptk.few stop2;;  //  go to handler (null)
        mov     loc3 = r8         // loc3 = file pointer
        add     out0 = @gprel(OPRMT),gp  // out0 -> format
        br.call.sptk.many b0 = printf  // Ask about input
        mov     gp = loc2         // Restore gp
        cmp4.lt p6,p0 = ret0,r0   // If any error,
   (p6) br.cond.sptk.few stop0;;  //  go to handler (null)
        add     out0 = @gprel(OFILE),gp  // out0 -> filename
        br.call.sptk.many b0 = gets  // Unformatted input
        mov     gp = loc2         // Restore gp
        cmp.eq  p6,p0 = ret0,r0   // If any error,
   (p6) br.cond.sptk.few stop1;;  //  go to handler (null)
        add     out0 = @gprel(OFILE),gp // out0 -> filename
        add     out1 = @gprel(OMODE),gp // out1 -> mode
        br.call.sptk.many b0 = fopen  // Find output file
        mov     gp = loc2         // Restore gp
        cmp.eq  p6,p0 = ret0,r0   // If any error,
   (p6) br.cond.sptk.few stop4;;  //  go to handler (null)
        mov     loc4 = ret0       // loc4 = file pointer
        mov     loc5 = 0          // loc5 counts numbers
        add     loc6 = @gprel(ARRAY),gp;; // loc6 -> buffer
loop:   mov     out0 = loc3       // out0 = IPTR
        add     out1 = @gprel(IFORM),gp // out1 -> format
        mov     out2 = loc6       // out2 -> ARRAY
        br.call.sptk.many b0 = fscanf // Read a number
        mov     gp = loc2         // Restore gp
        cmp4.ne p6,p0 = 1,ret0    // Expect one %d item
   (p6) br.cond.sptk.few eof;;    // No - maybe it's EOF
        add     loc6 = NUML,loc6  // Bump storage pointer
        add     loc5 = 1,loc5;;   // Count one number
        cmp.gt  p6,p0 = CASES,loc5 // If storage is ok,
   (p6) br.cond.sptk.few loop;;   //  go back for more
eof:    cmp4.ne p6,p0 = -1,ret0   // If not EOF,
   (p6) br.cond.sptk.few stop6;;  //  then exit
        mov     out0 = loc3       // out0 = input pointer
        br.call.sptk.many b0 = fclose // Close input
        mov     gp = loc2         // Restore gp
        cmp4.ne p6,p0 = 0,ret0    // If not successful,
   (p6) br.cond.sptk.few stop3;;  //  then exit
sort:   add     r20 = -1,loc5;;   // r20 = outer count-down
o_loop: mov     r21 = r20         // r21 = inner count-down
        add     r20 = -1,r20      // Count down for o_loop
        add     r22 = @gprel(ARRAY),gp;; // r22 -> 1st
        add     r23 = NUML,r22;;  // r23 -> 2nd number
i_loop: mov     r2 = r22          // r2 -> 1st number (temp)
        mov     r3 = r23          // r3 -> 2nd number (temp)
        add     r21 = -1,r21;;    // Count down for i_loop
look:   ld8     r24 = [r2]        // r24 = 1st number
        ld8     r25 = [r3];;      // r25 = 2nd number
why:    cmp.le p6,p0 = r24,r25    // If 1,2 order is ok,
   (p6) br.cond.spnt.many adjust;;  //  go on to next numbers
swap:   st8     [r2] = r25        // Swap the data
        st8     [r3] = r24        //  between the locations
adjust: add     r22 = NUML,r22    // Advance to next 1st
        add     r23 = NUML,r23    // Advance to next 2nd
        cmp.gt  p6,p0 = r21,r0    // Still more work
   (p6) br.cond.sptk.many i_loop;;  //  for inner loop to do?
        cmp.gt  p6,p0 = r20,r0    // Still more work
   (p6) br.cond.sptk.many o_loop  //  for outer loop to do?
        add     loc6 = @gprel(ARRAY),gp // loc6 -> ARRAY
        mov     loc7 = loc5;;     // Copy of the count
p_loop: mov     out0 = loc4       // out0 = output pointer
        add     out1 = @gprel(OFORM),gp // out1 -> format
        ld8     out2 = [loc6],NUML // out2 = what to print
        add     loc7 = -1,loc7    // Count down for p_loop
        br.call.sptk.many b0 = fprintf // C print function
        mov     gp = loc2         // Restore gp
        cmp4.lt p6,p0 = ret0,r0   // If any error,
   (p6) br.cond.sptk.few stop7;;  //  go to handler (null)
        cmp.gt  p6,p0 = loc7,r0   // Still more work
   (p6) br.cond.sptk.few p_loop   //  for print loop to do?
        mov     out0 = loc4       // out0 = OPTR
        br.call.sptk.many b0 = fclose // Close output
        mov     gp = loc2         // Restore gp
        cmp4.ne p6,p0 = 0,ret0    // If not successful,
   (p6) br.cond.sptk.few stop5;;  //  then exit
        add     out0 = @gprel(TELL),gp // out0 -> format
        mov     out1 = loc5       // out1 = number of words
        br.call.sptk.many b0 = printf  // C print function
        mov     gp = loc2         // Restore gp
        cmp4.lt p6,p0 = ret0,r0   // If any error,
   (p6) br.cond.sptk.few stop0;;  //  go to handler (null)
        br.cond.sptk.many done    // That is all
stop0:                            // Terminal output error
stop1:                            // Terminal input error
stop2:                            // Problem opening IFILE
stop3:                            // Problem closing IFILE
stop4:                            // Problem opening OFILE
stop5:                            // Problem closing OFILE
stop6:                            // Problem getting input
stop7:                            // Problem doing output
        add     out0 = @gprel(ERROR),gp // out0 -> format
        br.call.sptk.many b0 = perror // C error function
        mov     gp = loc2         // Restore gp
done:   mov     ret0 = 0          // Signal all is normal
        mov     b0 = loc1         // Restore return address
        mov     ar.pfs = loc0     // Restore caller's ar.pfs
        br.ret.sptk.many b0;;     // Back to command line
        .endp   main              // Mark end of procedure