Commit | Line | Data |
---|---|---|
1c3d4cf5 MW |
1 | dnl -*-autoconf-*- |
2 | ||
3 | ### SYNOPSIS | |
4 | ### | |
5 | ### mdw_PROBE_CONSTANT(VAR, EXPR, [PREAMBLE], [IF-FAILED]) | |
6 | ### | |
7 | ### DESCRIPTION | |
8 | ### | |
9 | ### Extracts the value of a a constant integer expression from the | |
10 | ### compiler. This works even if the compiler in question doesn't target | |
11 | ### the current architecture. The value must be in the range -10^244 < x < | |
12 | ### 10^244; this is probably fair enough. In the extraordinarily unliklely | |
13 | ### event that the constant value is outside these bounds, the macro will | |
14 | ### fail rather than silently giving a wrong answer. | |
15 | ### | |
16 | ### The result of the macro is that the shell variable VAR has the value of | |
17 | ### the expression EXPR, in decimal. The PREAMBLE, if given, is inserted | |
18 | ### before EXPR is evaluated; it should contain #include and #define | |
19 | ### directives which are used to compute the value of the expression. | |
20 | ### | |
21 | ### The idea for this macro came from the AC_C_COMPILE_VALUE macro by | |
22 | ### Ilguiz Latypov; this implementation has a number of advantages: | |
23 | ### | |
b14f3203 MW |
24 | ### * it has an immense range of representable values, notably including |
25 | ### negative numbers; and | |
1c3d4cf5 | 26 | ### |
b14f3203 MW |
27 | ### * it returns the value directly in a shell variable rather than |
28 | ### inventing an AC_DEFINE for it. | |
1c3d4cf5 MW |
29 | ### |
30 | ### LICENSE | |
31 | ### | |
32 | ### Copyright (c) 2013 Mark Wooding <mdw@distorted.org.uk> | |
33 | ### | |
34 | ### This program is free software: you can redistribute it and/or modify it | |
35 | ### under the terms of the GNU General Public License as published by the | |
36 | ### Free Software Foundation, either version 2 of the License, or (at your | |
37 | ### option) any later version. | |
38 | ### | |
39 | ### This program is distributed in the hope that it will be useful, but | |
40 | ### WITHOUT ANY WARRANTY; without even the implied warranty of | |
41 | ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
42 | ### General Public License for more details. | |
43 | ### | |
44 | ### You should have received a copy of the GNU General Public License along | |
45 | ### with this program. If not, see <http://www.gnu.org/licenses/>. | |
46 | ### | |
47 | ### In particular, no exception to the GPL is granted regarding generated | |
48 | ### `configure' scripts which are the output of Autoconf. | |
49 | ||
50 | # Serial 1 | |
51 | AC_COPYRIGHT([ | |
52 | Portions copyright (c) 2013 Mark Wooding. | |
53 | ||
54 | This configure script is free software: you can redistribute it and/or | |
55 | modify it under he terms of the GNU General Public License as published | |
56 | by the Free Software Foundation, either version 2 of the License, or | |
57 | (at your option) any later version.]) | |
58 | ||
59 | AC_DEFUN([mdw__PROBE_CONSTANT_SETUP], | |
60 | [mdw__probe_constant_body="[ | |
61 | ||
62 | /* The following program is copyright (c) 2013 Mark Wooding. It is free | |
63 | * software: you can redistribute it and/or modify it under the terms of the | |
64 | * GNU General Public License as published by the Free Software Foundation, | |
65 | * either version 2 of the License, or (at your option) any later version. | |
66 | * | |
67 | * This program is distributed in the hope that it will be useful, but | |
68 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
69 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
70 | * for more details. | |
71 | * | |
72 | * You should have received a copy of the GNU General Public License along | |
73 | * with this program. If not, see <http://www.gnu.org/licenses/>. | |
74 | */ | |
75 | ||
76 | /* The constant: 1 billion. We'll pull digits out in groups of nine, since | |
77 | * we can work with constants of at least the size of a C \`long'. | |
78 | */ | |
79 | #define MDW__G 1000000000 | |
80 | ||
81 | /* An empty macro, used as an argument sometimes. */ | |
82 | #define MDW__E | |
83 | ||
84 | /* A cheesy compile-time assertion. If X is zero, then we try to declare | |
85 | * an array with a negative number of elements. Wrap this up in an anonymous | |
86 | * struct so that we don't have to worry about naming things if we make | |
87 | * more than one assertion. | |
88 | */ | |
89 | #define MDW__ASSERT(x) struct { int v[1 - 2*!(x)]; } | |
90 | ||
91 | /* Return the value of X/DIV, with further divisions D applied, truncating | |
92 | * towards zero. DIV must be greater than one. This works even if X is | |
93 | * negative, never tries to divide negative numbers, and doesn't try to | |
94 | * negate the most-negative value. There are three cases: if X <= -DIV then | |
95 | * X/DIV = -(X + DIV)/DIV - 1, and X + DIV is less negative than X so this is | |
96 | * a safe negation; if -DIV < X < 0 then the result is zero; otherwise, X | |
97 | * is nonnegative so the straightforward division is safe. Because DIV > 1, | |
98 | * X/DIV is safe to negate, and we can apply the remaining divisions to it. | |
99 | */ | |
100 | #define MDW__SHIFT(x, div, d) \\ | |
101 | ((x) >= 0 ? ((x)/div d) : \\ | |
102 | (x) <= -(div) ? -((-((x) + (div))/(div) + 1) d) : 0) | |
103 | ||
104 | /* Extract the bottommost digit of X, as an integer: i.e., the value of | |
105 | * abs(X) mod 10. This works even if X is negative, never tries to divide | |
106 | * negative numbers, and doesn't try to divide the most-negative value. | |
107 | */ | |
108 | #define MDW__RAW_DIGIT(x) (((x) < 0 ? -((x) + 1) % 10 + 1 : (x)) % 10) | |
109 | ||
110 | /* Extract the bottommost digit of X, as a character; if X is zero, then | |
111 | * produce a space instead. This avoids leading zeroes which can be | |
112 | * misinterpreted by callers. | |
113 | */ | |
114 | #define MDW__TEXT_DIGIT(x) ((x) ? '0' + MDW__RAW_DIGIT(x) : ' ') | |
115 | ||
116 | /* Extract the bottommost digit of the probe value, after dividing by DIV | |
117 | * and applying the divisons D. | |
118 | */ | |
119 | #define MDW__DIGIT(div, d) \\ | |
120 | MDW__TEXT_DIGIT(MDW__SHIFT(MDW__PROBE_EXPR, div, d)) | |
121 | ||
122 | /* Extract the bottommost six digits of the probe value after dividing by 10 | |
123 | * and then applying the divisions D. | |
124 | */ | |
125 | #define MDW__9DIGITS(d) \\ | |
126 | MDW__DIGIT(1000000000, d), \\ | |
127 | MDW__DIGIT( 100000000, d), \\ | |
128 | MDW__DIGIT( 10000000, d), \\ | |
b14f3203 MW |
129 | MDW__DIGIT( 1000000, d), \\ |
130 | MDW__DIGIT( 100000, d), \\ | |
131 | MDW__DIGIT( 10000, d), \\ | |
132 | MDW__DIGIT( 1000, d), \\ | |
133 | MDW__DIGIT( 100, d), \\ | |
134 | MDW__DIGIT( 10, d) | |
1c3d4cf5 MW |
135 | |
136 | /* Increasingly huge divisions. PN divides by 10^(9*2^N). */ | |
137 | #define MDW__P0 /MDW__G | |
138 | #define MDW__P1 MDW__P0 MDW__P0 | |
139 | #define MDW__P2 MDW__P1 MDW__P1 | |
140 | #define MDW__P3 MDW__P2 MDW__P2 | |
141 | #define MDW__P4 MDW__P3 MDW__P3 | |
142 | #define MDW__P5 MDW__P4 MDW__P4 | |
143 | ||
144 | /* Increasingly long sequences of digits. DN(P) produces the 9 * 2^N | |
145 | * digits after applying divisions P. | |
146 | */ | |
147 | #define MDW__D0(p) MDW__9DIGITS(p MDW__P0), MDW__9DIGITS(p MDW__E) | |
148 | #define MDW__D1(p) MDW__D0(p MDW__P1), MDW__D0(p) | |
149 | #define MDW__D2(p) MDW__D1(p MDW__P2), MDW__D1(p) | |
150 | #define MDW__D3(p) MDW__D2(p MDW__P3), MDW__D2(p) | |
151 | #define MDW__D4(p) MDW__D3(p MDW__P4), MDW__D3(p) | |
152 | ||
153 | /* Ensure that our exponential cascade is sufficient to represent the | |
154 | * expression. | |
155 | */ | |
156 | MDW__ASSERT(MDW__SHIFT(MDW__PROBE_EXPR, 10, MDW__P5) == 0); | |
157 | ||
158 | /* Format the output. Everything is taken care of except the bottommost | |
159 | * digit, which we handle seaprately because we actually want a \`leading' | |
160 | * zero here if the constant value is actually zero. Format it so that | |
161 | * we can extract it from the object file. | |
162 | */ | |
163 | const char mdw__probe_output[] = { | |
164 | '\\n', | |
165 | 'm', 'd', 'w', '-', | |
166 | 'p', 'r', 'o', 'b', 'e', '-', | |
167 | 'v', 'a', 'l', 'u', 'e', '=', '\"', | |
168 | (MDW__PROBE_EXPR < 0 ? '-' : ' '), | |
169 | MDW__D4(MDW__E), | |
170 | '0' + MDW__RAW_DIGIT(MDW__PROBE_EXPR), | |
171 | '\"', '\\n' | |
172 | };]"]) | |
173 | ||
174 | AC_DEFUN([mdw_PROBE_CONSTANT], | |
175 | [AC_REQUIRE([mdw__PROBE_CONSTANT_SETUP]) | |
176 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([[$3 | |
177 | #define MDW__PROBE_EXPR ($2) | |
178 | $mdw__probe_constant_body]])], | |
179 | [$1=$(sed -n \ | |
180 | 's:^mdw-probe-value="\(-\|\) *\([[0-9]]*\)"$:\1\2:p' conftest.o)], | |
181 | [m4_if([$4], [], | |
182 | [AC_MSG_FAILURE([failed to evaluate expression])], | |
183 | [$4])])]) |