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