1
0
Fork 0
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:
Davin McCall 2022-05-29 20:50:33 +10:00 committed by Jonah Graham
parent d01a15f013
commit 7e59306985
3 changed files with 170 additions and 18 deletions

View file

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

View file

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

View file

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