Remove arbitrary [-1024,1024] limit in cross_compute_int()
Copy the algorithm used by autoconf. It computes the upper and lower limits by starting at [-1,1] and multiply by 2 at each iteration. This is even faster for small numbers (the common case), for example it finds value 0 in just 2 compilations where old algorithm would check for 1024, 512, ..., 0.
This commit is contained in:
parent
23a7fe06e9
commit
8a70e7cff5
|
@ -367,24 +367,52 @@ class CCompiler(Compiler):
|
|||
return self.compiles(t.format(**fargs), env, extra_args, dependencies)
|
||||
|
||||
def cross_compute_int(self, expression, low, high, guess, prefix, env, extra_args, dependencies):
|
||||
# Try user's guess first
|
||||
if isinstance(guess, int):
|
||||
if self._compile_int('%s == %d' % (expression, guess), prefix, env, extra_args, dependencies):
|
||||
return guess
|
||||
|
||||
cur = low
|
||||
while low < high:
|
||||
cur = int((low + high) / 2)
|
||||
if cur == low:
|
||||
break
|
||||
|
||||
if self._compile_int('%s >= %d' % (expression, cur), prefix, env, extra_args, dependencies):
|
||||
low = cur
|
||||
else:
|
||||
# If no bounds are given, compute them in the limit of int32
|
||||
maxint = 0x7fffffff
|
||||
minint = -0x80000000
|
||||
if not isinstance(low, int) or not isinstance(high, int):
|
||||
if self._compile_int('%s >= 0' % (expression), prefix, env, extra_args, dependencies):
|
||||
low = cur = 0
|
||||
while self._compile_int('%s > %d' % (expression, cur), prefix, env, extra_args, dependencies):
|
||||
low = cur + 1
|
||||
if low > maxint:
|
||||
raise EnvironmentException('Cross-compile check overflowed')
|
||||
cur = cur * 2 + 1
|
||||
if cur > maxint:
|
||||
cur = maxint
|
||||
high = cur
|
||||
else:
|
||||
low = cur = -1
|
||||
while self._compile_int('%s < %d' % (expression, cur), prefix, env, extra_args, dependencies):
|
||||
high = cur - 1
|
||||
if high < minint:
|
||||
raise EnvironmentException('Cross-compile check overflowed')
|
||||
cur = cur * 2
|
||||
if cur < minint:
|
||||
cur = minint
|
||||
low = cur
|
||||
else:
|
||||
# Sanity check limits given by user
|
||||
if high < low:
|
||||
raise EnvironmentException('high limit smaller than low limit')
|
||||
condition = '%s <= %d && %s >= %d' % (expression, high, expression, low)
|
||||
if not self._compile_int(condition, prefix, env, extra_args, dependencies):
|
||||
raise EnvironmentException('Value out of given range')
|
||||
|
||||
if self._compile_int('%s == %d' % (expression, cur), prefix, env, extra_args, dependencies):
|
||||
return cur
|
||||
raise EnvironmentException('Cross-compile check overflowed')
|
||||
# Binary search
|
||||
while low != high:
|
||||
cur = low + int((high - low) / 2)
|
||||
if self._compile_int('%s <= %d' % (expression, cur), prefix, env, extra_args, dependencies):
|
||||
high = cur
|
||||
else:
|
||||
low = cur + 1
|
||||
|
||||
return low
|
||||
|
||||
def compute_int(self, expression, low, high, guess, prefix, env, extra_args=None, dependencies=None):
|
||||
if extra_args is None:
|
||||
|
@ -416,7 +444,7 @@ class CCompiler(Compiler):
|
|||
}}'''
|
||||
if not self.compiles(t.format(**fargs), env, extra_args, dependencies):
|
||||
return -1
|
||||
return self.cross_compute_int('sizeof(%s)' % typename, 1, 1024, None, prefix, env, extra_args, dependencies)
|
||||
return self.cross_compute_int('sizeof(%s)' % typename, None, None, None, prefix, env, extra_args, dependencies)
|
||||
|
||||
def sizeof(self, typename, prefix, env, extra_args=None, dependencies=None):
|
||||
if extra_args is None:
|
||||
|
@ -454,7 +482,7 @@ class CCompiler(Compiler):
|
|||
char c;
|
||||
{type} target;
|
||||
}};'''
|
||||
return self.cross_compute_int('offsetof(struct tmp, target)', 1, 1024, None, t.format(**fargs), env, extra_args, dependencies)
|
||||
return self.cross_compute_int('offsetof(struct tmp, target)', None, None, None, t.format(**fargs), env, extra_args, dependencies)
|
||||
|
||||
def alignment(self, typename, prefix, env, extra_args=None, dependencies=None):
|
||||
if extra_args is None:
|
||||
|
|
|
@ -984,20 +984,20 @@ class CompilerHolder(InterpreterObject):
|
|||
check_stringlist(args)
|
||||
expression = args[0]
|
||||
prefix = kwargs.get('prefix', '')
|
||||
l = kwargs.get('low', -1024)
|
||||
h = kwargs.get('high', 1024)
|
||||
low = kwargs.get('low', None)
|
||||
high = kwargs.get('high', None)
|
||||
guess = kwargs.get('guess', None)
|
||||
if not isinstance(prefix, str):
|
||||
raise InterpreterException('Prefix argument of compute_int must be a string.')
|
||||
if not isinstance(l, int):
|
||||
if low is not None and not isinstance(low, int):
|
||||
raise InterpreterException('Low argument of compute_int must be an int.')
|
||||
if not isinstance(h, int):
|
||||
if high is not None and not isinstance(high, int):
|
||||
raise InterpreterException('High argument of compute_int must be an int.')
|
||||
if guess is not None and not isinstance(guess, int):
|
||||
raise InterpreterException('Guess argument of compute_int must be an int.')
|
||||
extra_args = self.determine_args(kwargs)
|
||||
deps = self.determine_dependencies(kwargs)
|
||||
res = self.compiler.compute_int(expression, l, h, guess, prefix, self.environment, extra_args, deps)
|
||||
res = self.compiler.compute_int(expression, low, high, guess, prefix, self.environment, extra_args, deps)
|
||||
mlog.log('Computing int of "%s": %d' % (expression, res))
|
||||
return res
|
||||
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
#define INTSIZE @INTSIZE@
|
||||
#define FOOBAR_IN_CONFIG_H @FOOBAR@
|
||||
#define MAXINT @MAXINT@
|
||||
#define MININT @MININT@
|
||||
|
|
|
@ -7,11 +7,15 @@ cc = meson.get_compiler('c')
|
|||
|
||||
intsize = cc.compute_int('sizeof(int)', low : 1, high : 16, guess : 4)
|
||||
foobar = cc.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc)
|
||||
maxint = cc.compute_int('INT_MAX', prefix: '#include <limits.h>')
|
||||
minint = cc.compute_int('INT_MIN', prefix: '#include <limits.h>')
|
||||
|
||||
cd = configuration_data()
|
||||
cd.set('INTSIZE', intsize)
|
||||
cd.set('FOOBAR', foobar)
|
||||
cd.set('CONFIG', 'config.h')
|
||||
cd.set('MAXINT', maxint)
|
||||
cd.set('MININT', minint)
|
||||
configure_file(input : 'config.h.in', output : 'config.h', configuration : cd)
|
||||
s = configure_file(input : 'prog.c.in', output : 'prog.c', configuration : cd)
|
||||
|
||||
|
@ -23,11 +27,15 @@ cpp = meson.get_compiler('cpp')
|
|||
|
||||
intsize = cpp.compute_int('sizeof(int)')
|
||||
foobar = cpp.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc)
|
||||
maxint = cpp.compute_int('INT_MAX', prefix: '#include <limits.h>')
|
||||
minint = cpp.compute_int('INT_MIN', prefix: '#include <limits.h>')
|
||||
|
||||
cdpp = configuration_data()
|
||||
cdpp.set('INTSIZE', intsize)
|
||||
cdpp.set('FOOBAR', foobar)
|
||||
cdpp.set('CONFIG', 'config.hpp')
|
||||
cdpp.set('MAXINT', maxint)
|
||||
cdpp.set('MININT', minint)
|
||||
configure_file(input : 'config.h.in', output : 'config.hpp', configuration : cdpp)
|
||||
spp = configure_file(input : 'prog.c.in', output : 'prog.cc', configuration : cdpp)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "@CONFIG@"
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <limits.h>
|
||||
#include "foobar.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -12,5 +13,13 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Mismatch: computed int %d, should be %d.\n", FOOBAR_IN_CONFIG_H, FOOBAR_IN_FOOBAR_H);
|
||||
return 1;
|
||||
}
|
||||
if(MAXINT != INT_MAX) {
|
||||
fprintf(stderr, "Mismatch: computed max int %d, should be %d.\n", MAXINT, INT_MAX);
|
||||
return 1;
|
||||
}
|
||||
if(MININT != INT_MIN) {
|
||||
fprintf(stderr, "Mismatch: computed min int %d, should be %d.\n", MININT, INT_MIN);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue