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:
Xavier Claessens 2018-04-06 15:57:53 -04:00 committed by Jussi Pakkanen
parent 23a7fe06e9
commit 8a70e7cff5
5 changed files with 66 additions and 19 deletions

View File

@ -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:

View File

@ -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

View File

@ -1,2 +1,4 @@
#define INTSIZE @INTSIZE@
#define FOOBAR_IN_CONFIG_H @FOOBAR@
#define MAXINT @MAXINT@
#define MININT @MININT@

View File

@ -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)

View File

@ -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;
}