From 6ad7fc3c833837713405b64a50e62dd128cb7a30 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Sat, 5 Jul 2014 13:56:01 +0800 Subject: [PATCH] Inner step of multiplication in x64 assembly Just does the multiplication of the array by one digit, taking into account overflows. I hope. It's kind of difficult to test. What I need is a VM with equivelant instruction set but magically uses decimals instead of binary 64 bit, so I can test with numbers that my feeble human brain understands directly... --- src/Makefile | 2 +- src/mul_digits_asm.s | 31 +++++++++++++++++++++++++++++++ src/tests/arb.cpp | 16 ++++++++++++---- 3 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 src/mul_digits_asm.s diff --git a/src/Makefile b/src/Makefile index d92c969..9dfda08 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,7 +3,7 @@ ARCH := $(shell uname -m) # TODO: stb_truetype doesn't compile with some of these warnings. CXX = g++ -std=gnu++0x -g -Wall -Werror -Wshadow -pedantic -rdynamic MAIN = main.o -OBJ = log.o real.o bezier.o document.o objectrenderer.o view.o screen.o vfpu.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o add_digits_asm.o sub_digits_asm.o arbint.o +OBJ = log.o real.o bezier.o document.o objectrenderer.o view.o screen.o vfpu.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o add_digits_asm.o sub_digits_asm.o mul_digits_asm.o arbint.o LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL diff --git a/src/mul_digits_asm.s b/src/mul_digits_asm.s new file mode 100644 index 0000000..fb11765 --- /dev/null +++ b/src/mul_digits_asm.s @@ -0,0 +1,31 @@ +.section .text +.globl mul_digits +.type mul_digits, @function + +# Multiply an array of 64 bit digits by *one* 64 bit digit, modifies the array in place +mul_digits: + movq %rdx, %rcx # rdx is reserved for mulq, use rcx as counter + movq $0, %r12 # Overflow register + loop: + movq %rsi, %rax # Value to multiply in %rax + mulq (%rdi) # Multiply, stored in %rdx:%rax (ie: we get TWO digits) + + # Add overflow from previous operation + add %r12, %rax + # Upper digit gets saved as next overflow + movq %rdx, %r12 + + # Lower digit goes in current array position + movq %rax, (%rdi) + + dec %rcx # Decrement counter + jz end_loop # We are done + + # Move to next element in the array + leaq 8(,%rdi,1), %rdi + jmp loop # Repeat + + end_loop: + end: + movq %r12, %rax # Return overflow + ret # We are done diff --git a/src/tests/arb.cpp b/src/tests/arb.cpp index c867a8f..354c337 100644 --- a/src/tests/arb.cpp +++ b/src/tests/arb.cpp @@ -9,9 +9,17 @@ using namespace IPDF; int main(int argc, char ** argv) { - Arbint a(100L); - Arbint b(200L); + int64_t test[] = {12L, 5L}; + test[1] = 0xE000000000000000; + int64_t size = sizeof(test)/sizeof(int64_t); - Arbint c(b-a); - printf("(%d), %s\n",c.Sign(), c.DigitStr().c_str()); + int64_t mul = 2L; + + int64_t overflow = mul_digits(test, mul, size); + + for (int64_t i = 0; i < size; ++i) + { + printf("digit[%li] = %.16lx\n", i, test[i]); + } + printf("Overflow is %.16lx\n", overflow); } -- 2.20.1