File: prime.S

package info (click to toggle)
hxtools 20180301-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 4,600 kB
  • sloc: ansic: 5,926; perl: 3,905; sh: 1,638; cpp: 342; makefile: 191; asm: 173
file content (155 lines) | stat: -rw-r--r-- 3,007 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 *	prime.S - check if a number is prime
 *	x86 assembler demonstration program
 *	use with GNU AS
 *
 *	written by Jan Engelhardt, 2003-2006
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the WTF Public License version 2 or
 *	(at your option) any later version.
 */
.intel_syntax noprefix;
.section .rodata;
.L_LC0:
	.string "%u is a prime\n";
.L_LC1:
	.string "%u is not a prime (split by %u)\n";

.text;

.global main;
	.type   main, @function;
main:
	push    ebp;
	mov     ebp, esp;

	push    dword ptr [ebp+12];
	push    dword ptr [ebp+8];
	call    GetPrime;
	add     esp, 8;
	mov     edi, eax;

	mov     esi, eax;
	call    IsPrime;
	test    eax, eax;
	push    eax;
	jne     .L_main_noprime;

.L_main_isprime:
	push    edi;
	push    offset flat:.L_LC0;
	call    printf;
	add     esp, 8;
	jmp     .L_main_end;

.L_main_noprime:
	push    eax;
	push    edi;
	push    offset flat:.L_LC1;
	call    printf;
	add     esp, 12;

.L_main_end:
	pop     eax;
	leave;
	ret;

.globl GetPrime;
	.type   GetPrime, @function;
GetPrime:
	push    ebp;
	mov     ebp, esp;

	cmp     dword ptr [ebp+8], 2;
	jae     .L_GetArgs_run;
	mov     eax, 13;
	jmp     .L_GetArgs_end;

.L_GetArgs_run:
	mov     ebx, dword ptr [ebp+12];
	push    0;
	push    0;
	push    dword ptr [ebx+4];
	call    strtoul;
	add     esp, 12;

.L_GetArgs_end:
	leave;
	ret;

/*
 * In an attempt to improve IsPrime2 further, this function only runs up to
 * sqrt(N) rather than N/2. This is possible since if you split the number in
 * two integral factors, the maximum value of either (see them independently)
 * can be sqrt(N):
 *
 * Imagine we take 100 as the number to check:
 *        100 = x * y      |T	    y strives to 0, while y >= x
 *    =>  100 = x ** 2     |sqrt()
 *   <=>    x = 10
 *
 * Checking a prime near 2^31 thus only takes about 3 secs instead on a modest
 * CPU. (15+ secs for IsPrime2 on *that* modest CPU.)
 */

.globl IsPrime;
	.type   IsPrime, @function
IsPrime:
	push    ebp;
	mov     ebp, esp;
	sub     esp, 8;

	/* Early case exclusion */
	cmp     esi, 3;
	jbe     .L_IsPrime_IsPrime;

	mov     ecx, 2;
	test    si, 1;
	je      .L_IsPrime_NoPrime;

	cmp     esi, 7;
	jbe     .L_IsPrime_IsPrime;

	/* Set up FPU to round up */
	fstcw   word ptr [ebp-8];
	mov     ax, word ptr [ebp-8];
	and     ax, 0xF0FF;
	or      ax, 0x0B00;
	mov     word ptr [ebp-8], ax;
	fldcw   /* word ptr */ [ebp-8];

	/* Maximum count is ceil(sqrt(esi)) */
	mov     dword ptr [ebp-4], esi;
	fild    dword ptr [ebp-4];
	fsqrt;
	fistp   dword ptr [ebp-4];
	mov     ebx, dword ptr [ebp-4];

	/* Iterative loop */
	cmp     ebx, 3;
	jb      .L_IsPrime_IsPrime;
	mov     ecx, 3;

.L_IsPrime_loop:
	mov     eax, esi;
	xor     edx, edx;
	div     ecx;
	test    edx, edx;
	je      .L_IsPrime_NoPrime;
	add     ecx, 2;

	cmp     ecx, ebx;
	jbe     .L_IsPrime_loop;

.L_IsPrime_IsPrime:
	add     esp, 8;
	mov     eax, 0;
	leave;
	ret;

.L_IsPrime_NoPrime:
	add     esp, 8;
	mov     eax, ecx;
	leave;
	ret;