mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-03 22:35:43 +02:00
Bug 580037 - constexpr evaluation of additional builtins: ctz, etc
Provide constexpr evaluation for: __builtin_ctz, __builtin_popcount, __builtin_parity, __builtin_abs, and the variants which take a long int or long long int. Change-Id: I6088e2d41a161059ce0a64443a1d1126952ff905
This commit is contained in:
parent
d01a15f013
commit
7e59306985
3 changed files with 170 additions and 18 deletions
|
@ -274,4 +274,44 @@ public abstract class IntegralValueTests extends TestBase {
|
|||
public void testBuiltinFfs() throws Exception {
|
||||
assertEvaluationEquals(5);
|
||||
}
|
||||
|
||||
// constexpr int x = __builtin_ctz(16);
|
||||
public void testBuiltinCtz() throws Exception {
|
||||
assertEvaluationEquals(4);
|
||||
}
|
||||
|
||||
// constexpr int x = __builtin_popcount(128 + 32 + 8 + 4 + 2);
|
||||
public void testBuiltinPopcount() throws Exception {
|
||||
assertEvaluationEquals(5);
|
||||
}
|
||||
|
||||
// constexpr int x = __builtin_popcountl(0x80000001);
|
||||
public void testBuiltinPopcountHighBitSet() throws Exception {
|
||||
assertEvaluationEquals(2);
|
||||
}
|
||||
|
||||
// constexpr int x = __builtin_popcountl(0x8000000000000001);
|
||||
public void testBuiltinPopcountlHighBitSet() throws Exception {
|
||||
assertEvaluationEquals(2);
|
||||
}
|
||||
|
||||
// constexpr int x = __builtin_popcountll(0x8000000000000001);
|
||||
public void testBuiltinPopcountllHighBitSet() throws Exception {
|
||||
assertEvaluationEquals(2);
|
||||
}
|
||||
|
||||
// constexpr int x = __builtin_parity(128 + 32 + 8 + 4 + 2) + __builtin_parity(64) + __builtin_parity(0);
|
||||
public void testBuiltinParity() throws Exception {
|
||||
assertEvaluationEquals(2);
|
||||
}
|
||||
|
||||
// constexpr int x = __builtin_abs(700) + __builtin_abs(50);
|
||||
public void testBuiltinAbs() throws Exception {
|
||||
assertEvaluationEquals(750);
|
||||
}
|
||||
|
||||
// constexpr int x = __builtin_abs(-1);
|
||||
public void testBuiltinAbsNegativeInput() throws Exception {
|
||||
assertEvaluationEquals(1);
|
||||
}
|
||||
}
|
|
@ -191,10 +191,24 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
|
|||
function("bool", "__atomic_is_lock_free", "size_t", "void*");
|
||||
|
||||
ICPPExecution builtinFfs = new ExecBuiltin(ExecBuiltin.BUILTIN_FFS);
|
||||
ICPPExecution builtinFfsl = new ExecBuiltin(ExecBuiltin.BUILTIN_FFSL);
|
||||
ICPPExecution builtinFfsll = new ExecBuiltin(ExecBuiltin.BUILTIN_FFSLL);
|
||||
ICPPExecution builtinCtz = new ExecBuiltin(ExecBuiltin.BUILTIN_CTZ);
|
||||
ICPPExecution builtinCtzl = new ExecBuiltin(ExecBuiltin.BUILTIN_CTZL);
|
||||
ICPPExecution builtinCtzll = new ExecBuiltin(ExecBuiltin.BUILTIN_CTZLL);
|
||||
ICPPExecution builtinPopcount = new ExecBuiltin(ExecBuiltin.BUILTIN_POPCOUNT);
|
||||
ICPPExecution builtinPopcountl = new ExecBuiltin(ExecBuiltin.BUILTIN_POPCOUNTL);
|
||||
ICPPExecution builtinPopcountll = new ExecBuiltin(ExecBuiltin.BUILTIN_POPCOUNTLL);
|
||||
ICPPExecution builtinParity = new ExecBuiltin(ExecBuiltin.BUILTIN_PARITY);
|
||||
ICPPExecution builtinParityl = new ExecBuiltin(ExecBuiltin.BUILTIN_PARITYL);
|
||||
ICPPExecution builtinParityll = new ExecBuiltin(ExecBuiltin.BUILTIN_PARITYLL);
|
||||
ICPPExecution builtinAbs = new ExecBuiltin(ExecBuiltin.BUILTIN_ABS);
|
||||
ICPPExecution builtinLabs = new ExecBuiltin(ExecBuiltin.BUILTIN_LABS);
|
||||
ICPPExecution builtinLlabs = new ExecBuiltin(ExecBuiltin.BUILTIN_LLABS);
|
||||
|
||||
// Other Builtins (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) [incomplete]
|
||||
function("void", "__builtin_abort");
|
||||
function("int", "__builtin_abs", "int");
|
||||
function("int", "__builtin_abs", builtinAbs, "int");
|
||||
function("double", "__builtin_acos", "double");
|
||||
function("float", "__builtin_acosf", "float");
|
||||
function("long double", "__builtin_acosl", "long double");
|
||||
|
@ -251,9 +265,9 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
|
|||
function("double", "__builtin_creal", "complex double");
|
||||
function("float", "__builtin_crealf", "complex float");
|
||||
function("long double", "__builtin_creall", "complex long double");
|
||||
function("int", "__builtin_ctz", "unsigned int");
|
||||
function("int", "__builtin_ctzl", "unsigned long");
|
||||
function("int", "__builtin_ctzll", "unsigned long long");
|
||||
function("int", "__builtin_ctz", builtinCtz, "unsigned int");
|
||||
function("int", "__builtin_ctzl", builtinCtzl, "unsigned long");
|
||||
function("int", "__builtin_ctzll", builtinCtzll, "unsigned long long");
|
||||
function("double", "__builtin_erf", "double");
|
||||
function("float", "__builtin_erff", "float");
|
||||
function("long double", "__builtin_erfl", "long double");
|
||||
|
@ -282,8 +296,8 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
|
|||
function("float", "__builtin_fdimf", "float", "float");
|
||||
function("long double", "__builtin_fdiml", "long double", "long double");
|
||||
function("int", "__builtin_ffs", builtinFfs, "unsigned int");
|
||||
function("int", "__builtin_ffsl", builtinFfs, "unsigned long");
|
||||
function("int", "__builtin_ffsll", builtinFfs, "unsigned long long");
|
||||
function("int", "__builtin_ffsl", builtinFfsl, "unsigned long");
|
||||
function("int", "__builtin_ffsll", builtinFfsll, "unsigned long long");
|
||||
function("double", "__builtin_floor", "double");
|
||||
function("float", "__builtin_floorf", "float");
|
||||
function("long double", "__builtin_floorl", "long double");
|
||||
|
@ -334,7 +348,7 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
|
|||
function("bool", "__builtin_isnan", "double");
|
||||
function("bool", "__builtin_isnormal", "double");
|
||||
function("bool", "__builtin_isunordered", "float", "float");
|
||||
function("long", "__builtin_labs", "long");
|
||||
function("long", "__builtin_labs", builtinLabs, "long");
|
||||
function("double", "__builtin_ldexp", "double", "int");
|
||||
function("float", "__builtin_ldexpf", "float", "int");
|
||||
function("long double", "__builtin_ldexpl", "long double", "int");
|
||||
|
@ -344,7 +358,7 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
|
|||
function("int", "__builtin_LINE"); //TODO: This should technically be a constant integer expression
|
||||
function("const char *", "__builtin_FUNCTION");
|
||||
function("const char *", "__builtin_FILE");
|
||||
function("long long", "__builtin_llabs", "long long");
|
||||
function("long long", "__builtin_llabs", builtinLlabs, "long long");
|
||||
function("long long", "__builtin_llrint", "double");
|
||||
function("long long", "__builtin_llrintf", "float");
|
||||
function("long long", "__builtin_llrintl", "long double");
|
||||
|
@ -397,12 +411,12 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
|
|||
function("double", "__builtin_nexttoward", "double", "long double");
|
||||
function("float", "__builtin_nexttowardf", "float", "long double");
|
||||
function("long double", "__builtin_nexttowardl", "long double", "long double");
|
||||
function("int", "__builtin_parity", "unsigned int");
|
||||
function("int", "__builtin_parityl", "unsigned long");
|
||||
function("int", "__builtin_parityll", "unsigned long long");
|
||||
function("int", "__builtin_popcount", "unsigned int");
|
||||
function("int", "__builtin_popcountl", "unsigned long");
|
||||
function("int", "__builtin_popcountll", "unsigned long long");
|
||||
function("int", "__builtin_parity", builtinParity, "unsigned int");
|
||||
function("int", "__builtin_parityl", builtinParityl, "unsigned long");
|
||||
function("int", "__builtin_parityll", builtinParityll, "unsigned long long");
|
||||
function("int", "__builtin_popcount", builtinPopcount, "unsigned int");
|
||||
function("int", "__builtin_popcountl", builtinPopcountl, "unsigned long");
|
||||
function("int", "__builtin_popcountll", builtinPopcountll, "unsigned long long");
|
||||
function("double", "__builtin_pow", "double", "double");
|
||||
function("float", "__builtin_powf", "float", "float");
|
||||
function("long double", "__builtin_powl", "long double", "long double");
|
||||
|
|
|
@ -31,9 +31,13 @@ import org.eclipse.core.runtime.CoreException;
|
|||
* Constexpr-evaluation for compiler builtin functions.
|
||||
*/
|
||||
public class ExecBuiltin implements ICPPExecution {
|
||||
public final static short BUILTIN_FFS = 0;
|
||||
public final static short BUILTIN_FFS = 0, BUILTIN_FFSL = 1, BUILTIN_FFSLL = 2, BUILTIN_CTZ = 3, BUILTIN_CTZL = 4,
|
||||
BUILTIN_CTZLL = 5, BUILTIN_POPCOUNT = 6, BUILTIN_POPCOUNTL = 7, BUILTIN_POPCOUNTLL = 8, BUILTIN_PARITY = 9,
|
||||
BUILTIN_PARITYL = 10, BUILTIN_PARITYLL = 11, BUILTIN_ABS = 12, BUILTIN_LABS = 13, BUILTIN_LLABS = 14;
|
||||
|
||||
private static IType intType = new CPPBasicType(Kind.eInt, 0);
|
||||
private static IType longType = new CPPBasicType(Kind.eInt, CPPBasicType.IS_LONG);
|
||||
private static IType longlongType = new CPPBasicType(Kind.eInt, CPPBasicType.IS_LONG_LONG);
|
||||
|
||||
private short funcId;
|
||||
|
||||
|
@ -51,12 +55,34 @@ public class ExecBuiltin implements ICPPExecution {
|
|||
|
||||
switch (funcId) {
|
||||
case BUILTIN_FFS:
|
||||
case BUILTIN_FFSL:
|
||||
case BUILTIN_FFSLL:
|
||||
return executeBuiltinFfs(record, context);
|
||||
case BUILTIN_CTZ:
|
||||
case BUILTIN_CTZL:
|
||||
case BUILTIN_CTZLL:
|
||||
return executeBuiltinCtz(record, context);
|
||||
case BUILTIN_POPCOUNT:
|
||||
case BUILTIN_POPCOUNTL:
|
||||
case BUILTIN_POPCOUNTLL:
|
||||
return executeBuiltinPopcount(record, context);
|
||||
case BUILTIN_PARITY:
|
||||
case BUILTIN_PARITYL:
|
||||
case BUILTIN_PARITYLL:
|
||||
return executeBuiltinParity(record, context);
|
||||
case BUILTIN_ABS:
|
||||
case BUILTIN_LABS:
|
||||
case BUILTIN_LLABS:
|
||||
return executeBuiltinAbs(record, context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ICPPExecution executeBuiltinFfs(ActivationRecord record, ConstexprEvaluationContext context) {
|
||||
/*
|
||||
* Return an execution representing __builtin_ffs or __builtin_ctz
|
||||
*/
|
||||
private ICPPExecution executeBuiltinFfsCtz(ActivationRecord record, ConstexprEvaluationContext context,
|
||||
boolean isCtz) {
|
||||
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
|
||||
|
||||
IValue argValue = arg0.getValue();
|
||||
|
@ -64,16 +90,88 @@ public class ExecBuiltin implements ICPPExecution {
|
|||
return null;
|
||||
|
||||
// __builtin_ffs returns 0 if arg is 0, or 1+count where count is the number of trailing 0 bits
|
||||
// __builtin_ctz is undefined if arg is 0, or returns count
|
||||
long arg = argValue.numberValue().longValue();
|
||||
if (arg == 0) {
|
||||
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(0)));
|
||||
if (isCtz) {
|
||||
return null;
|
||||
} else {
|
||||
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(0)));
|
||||
}
|
||||
}
|
||||
int count = 0;
|
||||
while ((arg & 1) == 0) {
|
||||
arg >>= 1;
|
||||
count++;
|
||||
}
|
||||
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(count + 1)));
|
||||
int increment = isCtz ? 0 : 1;
|
||||
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(count + increment)));
|
||||
}
|
||||
|
||||
private ICPPExecution executeBuiltinFfs(ActivationRecord record, ConstexprEvaluationContext context) {
|
||||
return executeBuiltinFfsCtz(record, context, false /* ffs */);
|
||||
}
|
||||
|
||||
private ICPPExecution executeBuiltinCtz(ActivationRecord record, ConstexprEvaluationContext context) {
|
||||
return executeBuiltinFfsCtz(record, context, true /* ctz */);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an execution representing __builtin_popcount
|
||||
*/
|
||||
private ICPPExecution executeBuiltinPopcountParity(ActivationRecord record, ConstexprEvaluationContext context,
|
||||
boolean isParity) {
|
||||
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
|
||||
|
||||
IValue argValue = arg0.getValue();
|
||||
if (!(argValue instanceof IntegralValue))
|
||||
return null;
|
||||
|
||||
long arg = argValue.numberValue().longValue();
|
||||
int count = 0;
|
||||
while (arg != 0) {
|
||||
if ((arg & 1) != 0)
|
||||
count++;
|
||||
arg >>>= 1;
|
||||
}
|
||||
if (isParity) {
|
||||
count = count & 1;
|
||||
}
|
||||
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(count)));
|
||||
}
|
||||
|
||||
private ICPPExecution executeBuiltinPopcount(ActivationRecord record, ConstexprEvaluationContext context) {
|
||||
return executeBuiltinPopcountParity(record, context, false);
|
||||
}
|
||||
|
||||
private ICPPExecution executeBuiltinParity(ActivationRecord record, ConstexprEvaluationContext context) {
|
||||
return executeBuiltinPopcountParity(record, context, true);
|
||||
}
|
||||
|
||||
private ICPPExecution executeBuiltinAbs(ActivationRecord record, ConstexprEvaluationContext context) {
|
||||
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
|
||||
|
||||
IValue argValue = arg0.getValue();
|
||||
if (!(argValue instanceof IntegralValue))
|
||||
return null;
|
||||
|
||||
long arg = argValue.numberValue().longValue();
|
||||
long result = Math.abs(arg);
|
||||
|
||||
IType resultType = null;
|
||||
switch (funcId) {
|
||||
case BUILTIN_ABS:
|
||||
resultType = intType;
|
||||
break;
|
||||
case BUILTIN_LABS:
|
||||
resultType = longType;
|
||||
break;
|
||||
case BUILTIN_LLABS:
|
||||
resultType = longlongType;
|
||||
break;
|
||||
}
|
||||
|
||||
return new ExecReturn(new EvalFixed(resultType, ValueCategory.PRVALUE, IntegralValue.create(result)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Reference in a new issue