1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1984-1998 by Symantec
6  *              Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/util2.d, backend/util2.d)
10  */
11 
12 // Only used for DMD
13 
14 module dmd.backend.util2;
15 
16 // Utility subroutines
17 
18 import core.stdc.stdio;
19 import core.stdc.stdlib;
20 import core.stdc.string;
21 import core.stdc.stdint : uint64_t;
22 
23 import dmd.backend.cc;
24 import dmd.backend.cdef;
25 import dmd.backend.global;
26 import dmd.backend.mem;
27 
28 extern (C++):
29 
30 nothrow:
31 
32 void *ph_malloc(size_t nbytes);
33 void *ph_calloc(size_t nbytes);
34 void ph_free(void *p);
35 void *ph_realloc(void *p , size_t nbytes);
36 
37 extern (C) void printInternalFailure(FILE* stream); // from dmd/mars.d
38 
39 
40 void util_exit(int exitcode);
41 
42 void file_progress()
43 {
44 }
45 
46 /*******************************
47  * Alternative assert failure.
48  */
49 
50 void util_assert(const(char)* file, int line)
51 {
52     fflush(stdout);
53     printInternalFailure(stdout);
54     printf("Internal error: %s %d\n",file,line);
55     err_exit();
56 //#if __clang__
57 //    __builtin_unreachable();
58 //#endif
59 }
60 
61 /****************************
62  * Clean up and exit program.
63  */
64 
65 void err_exit()
66 {
67     util_exit(EXIT_FAILURE);
68 }
69 
70 /********************************
71  * Clean up and exit program.
72  */
73 
74 void err_break()
75 {
76     util_exit(255);
77 }
78 
79 
80 /****************************
81  * Clean up and exit program.
82  */
83 
84 void util_exit(int exitcode)
85 {
86     exit(exitcode);                     /* terminate abnormally         */
87 }
88 
89 version (CRuntime_DigitalMars)
90 {
91 
92 extern (C) extern __gshared int controlc_saw;
93 
94 /********************************
95  * Control C interrupts go here.
96  */
97 
98 private extern (C) void controlc_handler()
99 {
100     //printf("saw controlc\n");
101     controlc_saw = 1;
102 }
103 
104 /*********************************
105  * Trap control C interrupts.
106  */
107 
108 version (MARS) { } else
109 {
110 
111 extern (C)
112 {
113 void controlc_open();
114 void controlc_close();
115 alias _controlc_handler_t = void function();
116 extern __gshared _controlc_handler_t _controlc_handler;
117 
118 void _STI_controlc()
119 {
120     //printf("_STI_controlc()\n");
121     _controlc_handler = &controlc_handler;
122     controlc_open();                    /* trap control C               */
123 }
124 
125 void _STD_controlc()
126 {
127     //printf("_STD_controlc()\n");
128     controlc_close();
129 }
130 }
131 
132 }
133 }
134 
135 /***********************************
136  * Send progress report.
137  */
138 
139 void util_progress()
140 {
141     version (MARS) { } else {
142     version (CRuntime_DigitalMars)
143     {
144         if (controlc_saw)
145             err_break();
146     }
147     }
148 }
149 
150 void util_progress(int linnum)
151 {
152     version (MARS) { } else {
153     version (CRuntime_DigitalMars)
154     {
155         if (controlc_saw)
156             err_break();
157     }
158     }
159 }
160 
161 
162 /**********************************
163  * Binary string search.
164  * Input:
165  *      p .    string of characters
166  *      tab     array of pointers to strings
167  *      n =     number of pointers in the array
168  * Returns:
169  *      index (0..n-1) into tab[] if we found a string match
170  *      else -1
171  */
172 
173 version (X86) version (CRuntime_DigitalMars)
174     version = X86asm;
175 
176 int binary(const(char)* p, const(char)*  *table,int high)
177 {
178 version (X86asm)
179 {
180     alias len = high;        // reuse parameter storage
181     asm nothrow
182     {
183 
184 // First find the length of the identifier.
185         xor     EAX,EAX         ; // Scan for a 0.
186         mov     EDI,p           ;
187         mov     ECX,EAX         ;
188         dec     ECX             ; // Longest possible string.
189         repne                   ;
190         scasb                   ;
191         mov     EDX,high        ; // EDX = high
192         not     ECX             ; // length of the id including '/0', stays in ECX
193         dec     EDX             ; // high--
194         js      short Lnotfound ;
195         dec     EAX             ; // EAX = -1, so that eventually EBX = low (0)
196         mov     len,ECX         ;
197 
198         even                    ;
199 L4D:    lea     EBX,[EAX + 1]   ; // low = mid + 1
200         cmp     EBX,EDX         ;
201         jg      Lnotfound       ;
202 
203         even                    ;
204 L15:    lea     EAX,[EBX + EDX] ; // EAX = low + high
205 
206 // Do the string compare.
207 
208         mov     EDI,table       ;
209         sar     EAX,1           ; // mid = (low + high) >> 1
210         mov     ESI,p           ;
211         mov     EDI,[4*EAX+EDI] ; // Load table[mid]
212         mov     ECX,len         ; // length of id
213         repe                    ;
214         cmpsb                   ;
215 
216         je      short L63       ; // return mid if equal
217         jns     short L4D       ; // if (cond < 0)
218         lea     EDX,-1[EAX]     ; // high = mid - 1
219         cmp     EBX,EDX         ;
220         jle     L15             ;
221 
222 Lnotfound:
223         mov     EAX,-1          ; // Return -1.
224 
225         even                    ;
226 L63:                            ;
227     }
228 }
229 else
230 {
231     int low = 0;
232     char cp = *p;
233     high--;
234     p++;
235 
236     while (low <= high)
237     {
238         int mid = (low + high) >> 1;
239         int cond = table[mid][0] - cp;
240         if (cond == 0)
241             cond = strcmp(table[mid] + 1,p);
242         if (cond > 0)
243             high = mid - 1;
244         else if (cond < 0)
245             low = mid + 1;
246         else
247             return mid;                 /* match index                  */
248     }
249     return -1;
250 }
251 }
252 
253 
254 // search table[0 .. high] for p[0 .. len] (where p.length not necessairily equal to len)
255 int binary(const(char)* p, size_t len, const(char)** table, int high)
256 {
257     int low = 0;
258     char cp = *p;
259     high--;
260     p++;
261     len--;
262 
263     while (low <= high)
264     {
265         int mid = (low + high) >> 1;
266         int cond = table[mid][0] - cp;
267 
268         if (cond == 0)
269         {
270             cond = strncmp(table[mid] + 1, p, len);
271             if (cond == 0)
272                 cond = table[mid][len+1]; // same as: if (table[mid][len+1] != '\0') cond = 1;
273         }
274 
275         if (cond > 0)
276             high = mid - 1;
277         else if (cond < 0)
278             low = mid + 1;
279         else
280             return mid;                 /* match index                  */
281     }
282     return -1;
283 }
284 
285 /**********************
286  * If c is a power of 2, return that power else -1.
287  */
288 
289 int ispow2(uint64_t c)
290 {       int i;
291 
292         if (c == 0 || (c & (c - 1)))
293             i = -1;
294         else
295             for (i = 0; c >>= 1; i++)
296             { }
297         return i;
298 }
299 
300 /***************************
301  */
302 
303 enum UTIL_PH = true;
304 
305 version (MEM_DEBUG)
306     enum MEM_DEBUG = false; //true;
307 else
308     enum MEM_DEBUG = false;
309 
310 version (Windows)
311 {
312 void *util_malloc(uint n,uint size)
313 {
314 static if (MEM_DEBUG)
315 {
316     void *p;
317 
318     p = mem_malloc(n * size);
319     //dbg_printf("util_calloc(%d) = %p\n",n * size,p);
320     return p;
321 }
322 else static if (UTIL_PH)
323 {
324     return ph_malloc(n * size);
325 }
326 else
327 {
328     size_t nbytes = cast(size_t)n * cast(size_t)size;
329     void *p = malloc(nbytes);
330     if (!p && nbytes)
331         err_nomem();
332     return p;
333 }
334 }
335 }
336 
337 /***************************
338  */
339 
340 version (Windows)
341 {
342 void *util_calloc(uint n,uint size)
343 {
344 static if (MEM_DEBUG)
345 {
346     void *p;
347 
348     p = mem_calloc(n * size);
349     //dbg_printf("util_calloc(%d) = %p\n",n * size,p);
350     return p;
351 }
352 else static if (UTIL_PH)
353 {
354     return ph_calloc(n * size);
355 }
356 else
357 {
358     size_t nbytes = cast(size_t) n * cast(size_t) size;
359     void *p = calloc(n,size);
360     if (!p && nbytes)
361         err_nomem();
362     return p;
363 }
364 }
365 }
366 
367 /***************************
368  */
369 
370 version (Windows)
371 {
372 void util_free(void *p)
373 {
374     //dbg_printf("util_free(%p)\n",p);
375 static if (MEM_DEBUG)
376 {
377     mem_free(p);
378 }
379 else static if (UTIL_PH)
380 {
381     ph_free(p);
382 }
383 else
384 {
385     free(p);
386 }
387 }
388 }
389 
390 /***************************
391  */
392 
393 version (Windows)
394 {
395 void *util_realloc(void *oldp,size_t n,size_t size)
396 {
397 static if (MEM_DEBUG)
398 {
399     //dbg_printf("util_realloc(%p,%d)\n",oldp,n * size);
400     return mem_realloc(oldp,n * size);
401 }
402 else static if (UTIL_PH)
403 {
404     return ph_realloc(oldp,n * size);
405 }
406 else
407 {
408     const nbytes = n * size;
409     void *p = realloc(oldp,nbytes);
410     if (!p && nbytes)
411         err_nomem();
412     return p;
413 }
414 }
415 }
416 
417 /*****************************
418  */
419 void *mem_malloc2(uint size)
420 {
421     return mem_malloc(size);
422 }