CSAPP Architecture Lab
·2974 words·14 mins
📝 상세 정리 # Part A # sum.ys # Y86_64 문법으로 연결리스트의 원소들을 더하는 C 코드를 바꾸자. .pos 0 irmovq stack, %rsp call main halt .align 8 ele1: .quad 0x00a .quad ele2 ele2: .quad 0x0b0 .quad ele3 ele3: .quad 0xc00 .quad 0 main: irmovq ele1, %rdi call sum_list ret sum_list: irmovq $0, %rax sum_list_while: andq %rdi, %rdi je sum_list_while_end mrmovq (%rdi), %rbx addq %rbx, %rax mrmovq 8(%rdi), %rdi jmp sum_list_while sum_list_while_end: ret .pos 0x200 stack: rsum.ys # sum.ys와 같지만, 재귀함수로 구성하자. .pos 0 irmovq stack, %rsp call main halt .align 8 ele1: .quad 0x00a .quad ele2 ele2: .quad 0x0b0 .quad ele3 ele3: .quad 0xc00 .quad 0 main: irmovq ele1, %rdi call rsum_list ret rsum_list: andq %rdi, %rdi jne rsum_list_func irmovq $0, %rax ret rsum_list_func: pushq %rbx mrmovq (%rdi), %rbx mrmovq 8(%rdi), %rdi call rsum_list addq %rbx, %rax popq %rbx ret .pos 0x200 stack: copy.ys # 이번엔 source 블럭에서 destination 블럭으로 값을 복사하는걸 수행하자 .pos 0 irmovq stack, %rsp call main halt .align 8 src: .quad 0x00a .quad 0x0b0 .quad 0xc00 dest: .quad 0x111 .quad 0x222 .quad 0x333 main: irmovq src, %rdi irmovq dest, %rsi irmovq $3, %rdx call copy_block ret copy_block: xorq %rax, %rax // result = 0 copy_block_while: andq %rdx, %rdx je copy_block_end irmovq $8, %rcx mrmovq (%rdi), %rbx // val = *src addq %rcx, %rdi // src++ rmmovq %rbx, (%rsi) // *dest = val addq %rcx, %rsi // dest++ xorq %rbx, %rax // result ^= val irmovq $1, %rbx subq %rbx, %rdx jmp copy_block_while copy_block_end: ret .pos 0x200 stack: Part B # SEQ 프로세서 (seq-full.hcl)에 iaddq 명령어를 추가하자. Fetch / Decode / Execute / Mmory / Write-back를 잘 처리해야겠네… 천천히 해보자 Fetch # ################ Fetch Stage ################################### # Determine instruction code word icode = [ imem_error: INOP; 1: imem_icode; # Default: get from instruction memory ]; # Determine instruction function word ifun = [ imem_error: FNONE; 1: imem_ifun; # Default: get from instruction memory ]; bool instr_valid = icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Does fetched instruction require a regid byte? bool need_regids = icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; iaddq를 뭐가 필요할까? 일단 icode, ifun 은 물론 잘 있다고 생각하고, 아래를 생각해보자. instr_valid를 true로 만들기 위해 저기에다가 IIADDQ를 추가하고, 레지스터가 필요한가? 아무래도 레지스터에 더해야한다. val_C도 필요한가? 아무래도 상수값을 더하려면 필요하다. 다 추가해주자. Decode # ################ Decode Stage ################################### ## What register should be used as the A source? word srcA = [ icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : rA; icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word srcB = [ icode in { IOPQ, IRMMOVQ, IMRMOVQ } : rB; icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word dstE = [ icode in { IRRMOVQ } && Cnd : rB; icode in { IIRMOVQ, IOPQ} : rB; icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word dstM = [ icode in { IMRMOVQ, IPOPQ } : rA; 1 : RNONE; # Don't write any register ]; srcA, srcB, dstE, dstM중에선 뭐가 필요할까? 아무래도 가져올필요 없으니 srcA, srcB는 필요 없는거같고, dst만 있으면 될것같다. 아니지, srcB에다가 더해야하는거니까 srcB도 가져와야한다. 메모리에서 긁어온게 아니라 Execute에서 얻을 수 있는 값이니, dstE에 추가하면 되겠다. 근데 Cnd는 뭐지? condition중에 하나인거같은데, 일단 무조건 rB는 되어야하니 두번째줄에 넣자. Execute # ################ Execute Stage ################################### ## Select input A to ALU word aluA = [ icode in { IRRMOVQ, IOPQ } : valA; icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : valC; icode in { ICALL, IPUSHQ } : -8; icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : valB; icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ icode == IOPQ : ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = icode in { IOPQ }; 계산이랑 조건비트 설정까지 다 해야하는 Execute 단계이다. aluA에 valC를, aluB에 valB를 넣어야겠지? alufun은 아니고, setcc는 켜야겠다. Memory # 여기선 뭐 할게 없죠 메모리에 접근을 안하는디 Write back # 에? 원본 코드에는 여기가 없다. 알아서 되는 영역인듯? Program Counter Update # 이것도 자연스럽게 처리되어있다. Test # 위의것들을 추가하면 간단하게 완료된다! 생각보다 쉽네 Y86-64 Processor: seq-full.hcl 137 bytes of code read IF: Fetched irmovq at 0x0. ra=----, rb=%rsp, valC = 0x100 IF: Fetched call at 0xa. ra=----, rb=----, valC = 0x38 Wrote 0x13 to address 0xf8 IF: Fetched irmovq at 0x38. ra=----, rb=%rdi, valC = 0x18 IF: Fetched irmovq at 0x42. ra=----, rb=%rsi, valC = 0x4 IF: Fetched call at 0x4c. ra=----, rb=----, valC = 0x56 Wrote 0x55 to address 0xf0 IF: Fetched xorq at 0x56. ra=%rax, rb=%rax, valC = 0x0 IF: Fetched andq at 0x58. ra=%rsi, rb=%rsi, valC = 0x0 IF: Fetched jmp at 0x5a. ra=----, rb=----, valC = 0x83 IF: Fetched jne at 0x83. ra=----, rb=----, valC = 0x63 IF: Fetched mrmovq at 0x63. ra=%r10, rb=%rdi, valC = 0x0 IF: Fetched addq at 0x6d. ra=%r10, rb=%rax, valC = 0x0 IF: Fetched iaddq at 0x6f. ra=----, rb=%rdi, valC = 0x8 IF: Fetched iaddq at 0x79. ra=----, rb=%rsi, valC = 0xffffffffffffffff IF: Fetched jne at 0x83. ra=----, rb=----, valC = 0x63 IF: Fetched mrmovq at 0x63. ra=%r10, rb=%rdi, valC = 0x0 IF: Fetched addq at 0x6d. ra=%r10, rb=%rax, valC = 0x0 IF: Fetched iaddq at 0x6f. ra=----, rb=%rdi, valC = 0x8 IF: Fetched iaddq at 0x79. ra=----, rb=%rsi, valC = 0xffffffffffffffff IF: Fetched jne at 0x83. ra=----, rb=----, valC = 0x63 IF: Fetched mrmovq at 0x63. ra=%r10, rb=%rdi, valC = 0x0 IF: Fetched addq at 0x6d. ra=%r10, rb=%rax, valC = 0x0 IF: Fetched iaddq at 0x6f. ra=----, rb=%rdi, valC = 0x8 IF: Fetched iaddq at 0x79. ra=----, rb=%rsi, valC = 0xffffffffffffffff IF: Fetched jne at 0x83. ra=----, rb=----, valC = 0x63 IF: Fetched mrmovq at 0x63. ra=%r10, rb=%rdi, valC = 0x0 IF: Fetched addq at 0x6d. ra=%r10, rb=%rax, valC = 0x0 IF: Fetched iaddq at 0x6f. ra=----, rb=%rdi, valC = 0x8 IF: Fetched iaddq at 0x79. ra=----, rb=%rsi, valC = 0xffffffffffffffff IF: Fetched jne at 0x83. ra=----, rb=----, valC = 0x63 IF: Fetched ret at 0x8c. ra=----, rb=----, valC = 0x0 IF: Fetched ret at 0x55. ra=----, rb=----, valC = 0x0 IF: Fetched halt at 0x13. ra=----, rb=----, valC = 0x0 32 instructions executed Status = HLT Condition Codes: Z=1 S=0 O=0 Changed Register State: %rax: 0x0000000000000000 0x0000abcdabcdabcd %rsp: 0x0000000000000000 0x0000000000000100 %rdi: 0x0000000000000000 0x0000000000000038 %r10: 0x0000000000000000 0x0000a000a000a000 Changed Memory State: 0x00f0: 0x0000000000000000 0x0000000000000055 0x00f8: 0x0000000000000000 0x0000000000000013 ISA Check Succeeds ./optest.pl -s ../seq/ssim -i Simulating with ../seq/ssim All 58 ISA Checks Succeed ./jtest.pl -s ../seq/ssim -i Simulating with ../seq/ssim All 96 ISA Checks Succeed ./ctest.pl -s ../seq/ssim -i Simulating with ../seq/ssim All 22 ISA Checks Succeed ./htest.pl -s ../seq/ssim -i Simulating with ../seq/ssim All 756 ISA Checks Succeed Part C # ncopy.ys가 최대한 빠르게 실행대도록 최적화하는 단계이다. CPE가 7.5 이하로 가도록! pipe-full.hcl를 수정하고, ncopy.ys를 수정하자. make VERSION=full GUIMODE="" # pipe-full.hcl 수정 후 make drivers # ncopy.ys 수정 후 ./correctness.pl # 정확성 확인 ./benchmark.pl # CPE 확인 처음 CPE는 15.18이다. 힘내보자고 pipe-full.hcl # 일단 CPU부터 손보자. 여기서도 IIADDQ를 추가해야하는것 같다. Fetch # 일단 f_PC는 상관 없을 것 같다. f_icode, f_ifun도 문제 없고.. instr_valid는 추가해야겠지. 위와 같이 need_regids, need_valC도 다 추가해야겠다. f_predPC는 점프할일 없으니까 f_valP 그대로! Decode # 똑같이 d_srcB, d_dstE 두개를 남겨야할 것 같다. valA를 가져올때 이슈인데… 포워딩을 해야되는데. valA에는 Execute 단계에서 valC를 가져오면 되고, valB는 땡겨올텐데… 아 이미 코딩이 되어있다. e_dstE, M_dstM, M_dstE, W_dstM, W_dstE 순서에서 땡겨온다. 안건드려도 될듯 Execute # aluA는 E_valC에서 데려오는거니, 거기다가 IIADDQ를 넣어주자. aluB에는 E_valB에서 가져오게. alufun은 상관없고, setcc가 좀 이슈인데… ## Should the condition codes be updated? bool set_cc = E_icode == IOPQ && # State changes only during normal operation !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; 원래 코드가 이렇게 되어있는데, E_icode == IOPQ 부분을 in 문법으로 바꾸면 될까? bool set_cc = E_icode in { IOPQ, IIADDQ} && 이렇게 한번 바꿔보자. Memory # 할일 없지 않을까? Pipeline Register conrtrol # 버블을 넣을까 말까인데, IADDQ는 뭐 상관 없었지. stall도 할 필요 없고. test # ❯ cd ../y86-code; make testpsim Makefile:42: warning: ignoring prerequisites on suffix rule definition Makefile:45: warning: ignoring prerequisites on suffix rule definition Makefile:48: warning: ignoring prerequisites on suffix rule definition Makefile:51: warning: ignoring prerequisites on suffix rule definition ../pipe/psim -t asum.yo > asum.pipe ../pipe/psim -t asumr.yo > asumr.pipe ../pipe/psim -t cjr.yo > cjr.pipe ../pipe/psim -t j-cc.yo > j-cc.pipe ../pipe/psim -t poptest.yo > poptest.pipe ../pipe/psim -t pushquestion.yo > pushquestion.pipe ../pipe/psim -t pushtest.yo > pushtest.pipe ../pipe/psim -t prog1.yo > prog1.pipe ../pipe/psim -t prog2.yo > prog2.pipe ../pipe/psim -t prog3.yo > prog3.pipe ../pipe/psim -t prog4.yo > prog4.pipe ../pipe/psim -t prog5.yo > prog5.pipe ../pipe/psim -t prog6.yo > prog6.pipe ../pipe/psim -t prog7.yo > prog7.pipe ../pipe/psim -t prog8.yo > prog8.pipe ../pipe/psim -t ret-hazard.yo > ret-hazard.pipe grep "ISA Check" *.pipe asum.pipe:ISA Check Succeeds asumr.pipe:ISA Check Succeeds cjr.pipe:ISA Check Succeeds j-cc.pipe:ISA Check Succeeds poptest.pipe:ISA Check Succeeds prog1.pipe:ISA Check Succeeds prog2.pipe:ISA Check Succeeds prog3.pipe:ISA Check Succeeds prog4.pipe:ISA Check Succeeds prog5.pipe:ISA Check Succeeds prog6.pipe:ISA Check Succeeds prog7.pipe:ISA Check Succeeds prog8.pipe:ISA Check Succeeds pushquestion.pipe:ISA Check Succeeds pushtest.pipe:ISA Check Succeeds ret-hazard.pipe:ISA Check Succeeds rm asum.pipe asumr.pipe cjr.pipe j-cc.pipe poptest.pipe pushquestion.pipe pushtest.pipe prog1.pipe prog2.pipe prog3.pipe prog4.pipe prog5.pipe prog6.pipe prog7.pipe prog8.pipe ret-hazard.pipe ❯ cd ../ptest; make SIM=../pipe/psim TFLAGS=-i ./optest.pl -s ../pipe/psim -i Simulating with ../pipe/psim All 58 ISA Checks Succeed ./jtest.pl -s ../pipe/psim -i Simulating with ../pipe/psim All 96 ISA Checks Succeed ./ctest.pl -s ../pipe/psim -i Simulating with ../pipe/psim All 22 ISA Checks Succeed ./htest.pl -s ../pipe/psim -i Simulating with ../pipe/psim All 756 ISA Checks Succeed 구웃 잘 돌아간다 ncopy.ys # 일단 아무래도 CPE는 그대로 15.18이다. 이걸 잘 바꿔보자. # You can modify this portion # Loop header xorq %rax,%rax # count = 0; andq %rdx,%rdx # len <= 0? jle Done # if so, goto Done: Loop: mrmovq (%rdi), %r10 # read val from src... rmmovq %r10, (%rsi) # ...and store it to dst andq %r10, %r10 # val <= 0? jle Npos # if so, goto Npos: irmovq $1, %r10 addq %r10, %rax # count++ Npos: irmovq $1, %r10 subq %r10, %rdx # len-- irmovq $8, %r10 addq %r10, %rdi # src++ addq %r10, %rsi # dst++ andq %rdx,%rdx # len > 0? jg Loop # if so, goto Loop: 우리가 바꿀 수 있는건 이부분인데.. IIADDQ # irmovq 를 이용해서 레지스트리에 값을 넣고, 그걸 addq로 연산하는 부분이 두군데 보인다. 이걸 iaddq로 줄일 수 있겠다. 이걸 수행했더니 CPE가 15.18 -> 13.70으로 줄었다. 갈길이 멀어보인다.. 어라, Npos에도 $-1로 len–를 구현할 수 있었다. 딱 하나 줄어서 12.70이 됐다. 순서 바꾸기? # mmmovq가 없으니, mrmovq, rmmovq로 데이터를 복사하고 있다. 그런데 이때 메모리 참조에서 하자드가 일어나서, bubble / stall이 들어가지 않았던가? 이 사이에 andq를 넣어볼까? 아 이것만으로는 같다… 안되넹 Loop: mrmovq (%rdi), %r10 # read val from src... andq %r10, %r10 # val <= 0? rmmovq %r10, (%rsi) # ...and store it to dst jle Npos # if so, goto Npos: iaddq $1, %rax # count++ 아하, 안되는게 아니라 이렇게 수정한거였는데, andq에서도 결국 %r10이 필요해서 이슈가 생긴다. 그런데 사이에 더 끼울수있는게 없는데.. 어셈블리 최적화 # 코드 자체를 최적화해볼까? 점프같은걸 잘 없앨 수 있을거같은데. 점프 적중률을 올려보자. Y86-64는 언제나 점프를 안한다고 생각하고 움직인다. ncopy: xorq %rax,%rax # count = 0; andq %rdx,%rdx # len <= 0? jle Done # if so, goto Done: Loop: mrmovq (%rdi), %r10 # read val from src... andq %r10, %r10 # val <= 0? rmmovq %r10, (%rsi) # ...and store it to dst # jle Npos # if so, goto Npos: # iaddq $1, %rax # count++ jg plus1 Npos: iaddq $-1, %rdx # len-- iaddq $8, %rdi # src++ iaddq $8, %rsi # dst++ andq %rdx,%rdx # len > 0? jle Done jmp Loop # if so, goto Loop: plus1: iaddq $1, %rax jmp Npos 쩝 이런느낌으로 해볼까 했는데, 오히려 명령어가 늘어서 15를 넘겨버렸다. 어떻게 하면 좋지? 점프를 덜타야할거같은데 버킷질 # 제곱근분할법에서 하는것처럼, 버킷질로 묶어서 처리할 수 있지 않을까? 그렇게하면 mrmovq 해저드도 없앨 수 있지 않을까? Loop: mrmovq (%rdi), %r10 # read val from src... mrmovq 8(%rdi), %r11 # src+1 rmmovq %r10, (%rsi) # ...and store it to dst rmmovq %r11, 8(%rsi) # src+1 to dst+1 andq %r10, %r10 # val <= 0? jle Npos # if so, goto Npos: iaddq $1, %rax # count++ Npos: andq %r11, %r11 jle Npos2 iaddq $1, %rax Npos2: iaddq $-2, %rdx # len-- iaddq $16, %rdi # src++ iaddq $16, %rsi # dst++ andq %rdx,%rdx # len > 0? jg Loop # if so, goto Loop: 아 다 좋은데.. 이게 짝수개일때만 동작한다. 홀수개이면 어카지? Loop2를 만들까? Loop로는 len > 1일때만 보내자. ncopy: xorq %rax,%rax # count = 0; iaddq $-1, %rdx jl Done Loop: je move1 mrmovq (%rdi), %r10 # read val from src... mrmovq 8(%rdi), %r11 # src+1 rmmovq %r10, (%rsi) # ...and store it to dst rmmovq %r11, 8(%rsi) # src+1 to dst+1 andq %r10, %r10 # val <= 0? jle Npos # if so, goto Npos: iaddq $1, %rax # count++ Npos: andq %r11, %r11 jle Npos2 iaddq $1, %rax Npos2: iaddq $16, %rdi # src += 2 iaddq $16, %rsi # dst += 2 iaddq $-2, %rdx # len -= 2 jge Loop jmp Done move1: mrmovq (%rdi), %r10 # read val from src... rmmovq %r10, (%rsi) # ...and store it to dst andq %r10, %r10 # val <= 0? jle Done # if so, goto Npos: iaddq $1, %rax # count++ 오!! 이렇게하니까 된다!! CPE 10.08까지 줄였다. 배치가 0~64개까지 있으니까, 대충 8개정도가 제곱근 분할법상 맞는거같지만.. %r10부터 시작하니, %r10~r15까지 6개를 써서 해볼까? 하아 코드가 개길어진다 ncopy: xorq %rax,%rax # count = 0; isbig: iaddq $-6, %rdx jge Loop iaddq $6, %rdx router: # check remainder 0 to 5 iaddq $-1, %rdx jl Done je move1 iaddq $-2, %rdx jl move2 je move3 iaddq $-2, %rdx jl move4 je move5 Loop: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 mrmovq 16(%rdi), %r12 mrmovq 24(%rdi), %r13 mrmovq 32(%rdi), %r14 mrmovq 40(%rdi), %r9 rmmovq %r10, (%rsi) rmmovq %r11, 8(%rsi) rmmovq %r12, 16(%rsi) rmmovq %r13, 24(%rsi) rmmovq %r14, 32(%rsi) rmmovq %r9, 40(%rsi) Npos_loop1: andq %r10, %r10 jle Npos_loop2 iaddq $1, %rax Npos_loop2: andq %r11, %r11 jle Npos_loop3 iaddq $1, %rax Npos_loop3: andq %r12, %r12 jle Npos_loop4 iaddq $1, %rax Npos_loop4: andq %r13, %r13 jle Npos_loop5 iaddq $1, %rax Npos_loop5: andq %r14, %r14 jle Npos_loop6 iaddq $1, %rax Npos_loop6: andq %r9, %r9 jle Loop_end iaddq $1, %rax Loop_end: iaddq $48, %rdi iaddq $48, %rsi iaddq $-6, %rdx jge Loop iaddq $6, %rdx jmp router move1: mrmovq (%rdi), %r10 rmmovq %r10, (%rsi) jmp move_check10 move2: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 rmmovq %r10, (%rsi) rmmovq %r11, 8(%rsi) jmp move_check11 move3: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 mrmovq 16(%rdi), %r12 rmmovq %r10, (%rsi) rmmovq %r11, 8(%rsi) rmmovq %r12, 16(%rsi) jmp move_check12 move4: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 mrmovq 16(%rdi), %r12 mrmovq 24(%rdi), %r13 rmmovq %r10, (%rsi) rmmovq %r11, 8(%rsi) rmmovq %r12, 16(%rsi) rmmovq %r13, 24(%rsi) jmp move_check13 move5: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 mrmovq 16(%rdi), %r12 mrmovq 24(%rdi), %r13 mrmovq 32(%rdi), %r14 rmmovq %r10, (%rsi) rmmovq %r11, 8(%rsi) rmmovq %r12, 16(%rsi) rmmovq %r13, 24(%rsi) rmmovq %r14, 32(%rsi) move_check14: andq %r14, %r14 jle move_check13 iaddq $1, %rax move_check13: andq %r13, %r13 jle move_check12 iaddq $1, %rax move_check12: andq %r12, %r12 jle move_check11 iaddq $1, %rax move_check11: andq %r11, %r11 jle move_check10 iaddq $1, %rax move_check10: andq %r10, %r10 jle Done iaddq $1, %rax 열심히 했더니 8.01까지 줄었다!! 이분 탐색 # router_tree: # now 0 <= rdx <= 5 iaddq $-3, %rdx je move3 jg router_tree_R router_tree_L: # rdx < 3 iaddq $2, %rdx jl Done je move1 jg move2 router_tree_R: # rdx > 3 iaddq $-1, %rdx je move4 jg move5 라우터를 이분탐색으로 해봤고, 7.80까지 줄일 수 있었다. move 로직도 좀 수정했다. ################################################################## # You can modify this portion # Loop header xorq %rax,%rax # count = 0; isbig: iaddq $-6, %rdx jge Loop router: iaddq $3, %rdx jl router_L je move3 jg router_R router_L: iaddq $2, %rdx jl Done je move1 jmp move2 router_R: iaddq $-1, %rdx je move4 jmp move5 Loop: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 mrmovq 16(%rdi), %r12 mrmovq 24(%rdi), %r13 mrmovq 32(%rdi), %r14 mrmovq 40(%rdi), %r9 Npos_loop1: andq %r10, %r10 rmmovq %r10, (%rsi) jle Npos_loop2 iaddq $1, %rax Npos_loop2: andq %r11, %r11 rmmovq %r11, 8(%rsi) jle Npos_loop3 iaddq $1, %rax Npos_loop3: andq %r12, %r12 rmmovq %r12, 16(%rsi) jle Npos_loop4 iaddq $1, %rax Npos_loop4: andq %r13, %r13 rmmovq %r13, 24(%rsi) jle Npos_loop5 iaddq $1, %rax Npos_loop5: andq %r14, %r14 rmmovq %r14, 32(%rsi) jle Npos_loop6 iaddq $1, %rax Npos_loop6: andq %r9, %r9 rmmovq %r9, 40(%rsi) jle Loop_end iaddq $1, %rax Loop_end: iaddq $48, %rdi iaddq $48, %rsi iaddq $-6, %rdx jge Loop jmp router move1: mrmovq (%rdi), %r10 jmp move_check10 move2: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 jmp move_check11 move3: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 mrmovq 16(%rdi), %r12 jmp move_check12 move4: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 mrmovq 16(%rdi), %r12 mrmovq 24(%rdi), %r13 jmp move_check13 move5: mrmovq (%rdi), %r10 mrmovq 8(%rdi), %r11 mrmovq 16(%rdi), %r12 mrmovq 24(%rdi), %r13 mrmovq 32(%rdi), %r14 move_check14: andq %r14, %r14 rmmovq %r14, 32(%rsi) jle move_check13 iaddq $1, %rax move_check13: andq %r13, %r13 rmmovq %r13, 24(%rsi) jle move_check12 iaddq $1, %rax move_check12: andq %r12, %r12 rmmovq %r12, 16(%rsi) jle move_check11 iaddq $1, %rax move_check11: andq %r11, %r11 rmmovq %r11, 8(%rsi) jle move_check10 iaddq $1, %rax move_check10: andq %r10, %r10 rmmovq %r10, (%rsi) jle Done iaddq $1, %rax 7.73정도까지 줄였는데.. 진짜 더는 못하겠다. 멀 해도 안줄어든다 ㅠ.ㅠ 여기서 포기 ❔질문 사항 # 🔗 참고 자료 #