diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/IntegralValueTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/IntegralValueTests.java index 48160677923..7b0d1f26ce3 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/IntegralValueTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/IntegralValueTests.java @@ -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); + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/GCCBuiltinSymbolProvider.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/GCCBuiltinSymbolProvider.java index b5ab4d3b5df..407c02e1d05 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/GCCBuiltinSymbolProvider.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/GCCBuiltinSymbolProvider.java @@ -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"); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecBuiltin.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecBuiltin.java index 338ef00240f..3e2df54fa63 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecBuiltin.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecBuiltin.java @@ -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