Bug 580325 - constexpr evaluation of builtins for clrsb, clz (#52)

Adds constexpr evaluation for some additional compiler builtins. This is
probably the last lot few builtins that can reasonably be
constexpr-evaluated in CDT.
This commit is contained in:
Davin McCall 2022-08-23 02:18:26 +10:00 committed by GitHub
parent ef195dbb73
commit 6445ec4890
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 116 additions and 8 deletions

View file

@ -340,4 +340,24 @@ public abstract class IntegralValueTests extends TestBase {
public void testBuiltinAbsNarrowing() throws Exception { public void testBuiltinAbsNarrowing() throws Exception {
assertEvaluationEquals(1); assertEvaluationEquals(1);
} }
// constexpr int x = __builtin_clrsb(0xFFFFFFFF);
public void testBuiltinClrsb() throws Exception {
assertEvaluationEquals(31);
}
// constexpr int x = __builtin_clrsb(555);
public void testBuiltinClrsbPositive() throws Exception {
assertEvaluationEquals(21);
}
// constexpr int x = __builtin_clz(0x8000);
public void testBuiltinClz() throws Exception {
assertEvaluationEquals(16);
}
// constexpr int x = __builtin_clz(-17);
public void testBuiltinClzNegative() throws Exception {
assertEvaluationEquals(0);
}
} }

View file

@ -205,6 +205,12 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
ICPPExecution builtinAbs = new ExecBuiltin(ExecBuiltin.BUILTIN_ABS); ICPPExecution builtinAbs = new ExecBuiltin(ExecBuiltin.BUILTIN_ABS);
ICPPExecution builtinLabs = new ExecBuiltin(ExecBuiltin.BUILTIN_LABS); ICPPExecution builtinLabs = new ExecBuiltin(ExecBuiltin.BUILTIN_LABS);
ICPPExecution builtinLlabs = new ExecBuiltin(ExecBuiltin.BUILTIN_LLABS); ICPPExecution builtinLlabs = new ExecBuiltin(ExecBuiltin.BUILTIN_LLABS);
ICPPExecution builtinClrsb = new ExecBuiltin(ExecBuiltin.BUILTIN_CLRSB);
ICPPExecution builtinClrsbl = new ExecBuiltin(ExecBuiltin.BUILTIN_CLRSBL);
ICPPExecution builtinClrsbll = new ExecBuiltin(ExecBuiltin.BUILTIN_CLRSBLL);
ICPPExecution builtinClz = new ExecBuiltin(ExecBuiltin.BUILTIN_CLZ);
ICPPExecution builtinClzl = new ExecBuiltin(ExecBuiltin.BUILTIN_CLZL);
ICPPExecution builtinClzll = new ExecBuiltin(ExecBuiltin.BUILTIN_CLZLL);
// Other Builtins (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) [incomplete] // Other Builtins (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) [incomplete]
function("void", "__builtin_abort"); function("void", "__builtin_abort");
@ -243,12 +249,12 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
function("float", "__builtin_cimagf", "complex float"); function("float", "__builtin_cimagf", "complex float");
function("long double", "__builtin_cimagl", "complex long double"); function("long double", "__builtin_cimagl", "complex long double");
function("void", "__builtin___clear_cache", "void*", "void*"); function("void", "__builtin___clear_cache", "void*", "void*");
function("int", "__builtin_clrsb", "int"); function("int", "__builtin_clrsb", builtinClrsb, "int");
function("int", "__builtin_clrsbl", "long"); function("int", "__builtin_clrsbl", builtinClrsbl, "long");
function("int", "__builtin_clrsbll", "long long"); function("int", "__builtin_clrsbll", builtinClrsbll, "long long");
function("int", "__builtin_clz", "unsigned int"); function("int", "__builtin_clz", builtinClz, "unsigned int");
function("int", "__builtin_clzl", "unsigned long"); function("int", "__builtin_clzl", builtinClzl, "unsigned long");
function("int", "__builtin_clzll", "unsigned long long"); function("int", "__builtin_clzll", builtinClzll, "unsigned long long");
function("complex double", "__builtin_conj", "complex double"); function("complex double", "__builtin_conj", "complex double");
function("complex float", "__builtin_conjf", "complex float"); function("complex float", "__builtin_conjf", "complex float");
function("complex long double", "__builtin_conjl", "complex long double"); function("complex long double", "__builtin_conjl", "complex long double");
@ -330,7 +336,7 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
function("int", "__builtin_ilogb", "double"); function("int", "__builtin_ilogb", "double");
function("int", "__builtin_ilogbf", "float"); function("int", "__builtin_ilogbf", "float");
function("int", "__builtin_ilogbl", "long double"); function("int", "__builtin_ilogbl", "long double");
function("long long", "__builtin_imaxabs", "long long"); function("long long", "__builtin_imaxabs", builtinLlabs, "long long");
function("double", "__builtin_inf"); function("double", "__builtin_inf");
function("_Decimal32", "__builtin_infd32"); function("_Decimal32", "__builtin_infd32");
function("_Decimal64", "__builtin_infd64"); function("_Decimal64", "__builtin_infd64");

View file

@ -19,6 +19,8 @@ import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue; import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBuiltinParameter; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBuiltinParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
@ -33,7 +35,9 @@ import org.eclipse.core.runtime.CoreException;
public class ExecBuiltin implements ICPPExecution { public class ExecBuiltin implements ICPPExecution {
public final static short BUILTIN_FFS = 0, BUILTIN_FFSL = 1, BUILTIN_FFSLL = 2, BUILTIN_CTZ = 3, BUILTIN_CTZL = 4, 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_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; BUILTIN_PARITYL = 10, BUILTIN_PARITYLL = 11, BUILTIN_ABS = 12, BUILTIN_LABS = 13, BUILTIN_LLABS = 14,
BUILTIN_CLRSB = 15, BUILTIN_CLRSBL = 16, BUILTIN_CLRSBLL = 17, BUILTIN_CLZ = 18, BUILTIN_CLZL = 19,
BUILTIN_CLZLL = 20;
private static IType intType = new CPPBasicType(Kind.eInt, 0); private static IType intType = new CPPBasicType(Kind.eInt, 0);
private static IType longType = new CPPBasicType(Kind.eInt, CPPBasicType.IS_LONG); private static IType longType = new CPPBasicType(Kind.eInt, CPPBasicType.IS_LONG);
@ -84,6 +88,18 @@ public class ExecBuiltin implements ICPPExecution {
return executeBuiltinAbs(record, context, longType); return executeBuiltinAbs(record, context, longType);
case BUILTIN_LLABS: case BUILTIN_LLABS:
return executeBuiltinAbs(record, context, longlongType); return executeBuiltinAbs(record, context, longlongType);
case BUILTIN_CLRSB:
return executeBuiltinClrsb(record, context, intType);
case BUILTIN_CLRSBL:
return executeBuiltinClrsb(record, context, longType);
case BUILTIN_CLRSBLL:
return executeBuiltinClrsb(record, context, longlongType);
case BUILTIN_CLZ:
return executeBuiltinClz(record, context, intType);
case BUILTIN_CLZL:
return executeBuiltinClz(record, context, longType);
case BUILTIN_CLZLL:
return executeBuiltinClz(record, context, longlongType);
} }
return null; return null;
} }
@ -166,6 +182,9 @@ public class ExecBuiltin implements ICPPExecution {
return executeBuiltinPopcountParity(record, context, true, argType); return executeBuiltinPopcountParity(record, context, true, argType);
} }
/*
* Return an execution implementing __builtin_abs
*/
private ICPPExecution executeBuiltinAbs(ActivationRecord record, ConstexprEvaluationContext context, private ICPPExecution executeBuiltinAbs(ActivationRecord record, ConstexprEvaluationContext context,
IType argType) { IType argType) {
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0)); ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
@ -182,6 +201,69 @@ public class ExecBuiltin implements ICPPExecution {
return new ExecReturn(new EvalFixed(argType, ValueCategory.PRVALUE, IntegralValue.create(result))); return new ExecReturn(new EvalFixed(argType, ValueCategory.PRVALUE, IntegralValue.create(result)));
} }
/*
* Return an execution implementing __builtin_clsrb (count leading "redundant" sign bits)
*/
private ICPPExecution executeBuiltinClrsb(ActivationRecord record, ConstexprEvaluationContext context,
IType argType) {
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
SizeAndAlignment sizeToType = SizeofCalculator.getSizeAndAlignment(argType);
if (sizeToType.size > 8)
return null; // can't handle too-large type
IValue argValue = arg0.getValue();
Number argNumber = argValue.numberValue();
if (argNumber == null)
return null;
long argLong = argNumber.longValue();
long signBit = 1L << (sizeToType.size * 8 - 1);
int result = 0;
long valueBit = signBit >>> 1;
if ((argLong & signBit) == 0) {
// if positive, invert all bits so we can unconditionally count 1 bits
argLong = ~argLong;
}
while ((argLong & valueBit) != 0) {
result++;
valueBit >>>= 1;
}
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(result)));
}
private ICPPExecution executeBuiltinClz(ActivationRecord record, ConstexprEvaluationContext context,
IType argType) {
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
SizeAndAlignment sizeToType = SizeofCalculator.getSizeAndAlignment(argType);
if (sizeToType.size > 8)
return null; // can't handle too-large type
IValue argValue = arg0.getValue();
Number argNumber = argValue.numberValue();
if (argNumber == null)
return null;
long argLong = argNumber.longValue();
long valueBit = 1L << (sizeToType.size * 8 - 1);
int result = 0;
// Note that __builtin_clz(0) is supposedly undefined, but GCC (12.1) apparently returns
// the bit size of int, so we'll make sure to do the same.
while ((argLong & valueBit) == 0) {
result++;
valueBit >>>= 1;
if (valueBit == 0)
break;
}
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(result)));
}
@Override @Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
buffer.putShort(ITypeMarshalBuffer.EXEC_BUILTIN); buffer.putShort(ITypeMarshalBuffer.EXEC_BUILTIN);