1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-21 21:52:10 +02:00

Bug 579934 support constexpr evaluation of __builtin_ffs[l,ll]

Change-Id: I103a4d0a7958d6172eb2b05379c8eec40369526c
This commit is contained in:
Davin McCall 2022-05-16 23:35:29 +10:00 committed by Jonah Graham
parent 9b05a213eb
commit 1ec4ae52c1
7 changed files with 145 additions and 9 deletions

View file

@ -269,4 +269,9 @@ public abstract class IntegralValueTests extends TestBase {
public void testHexLiteral() throws Exception {
assertEvaluationEquals(42);
}
// constexpr int x = __builtin_ffs(0) + __builtin_ffs(16);
public void testBuiltinFfs() throws Exception {
assertEvaluationEquals(5);
}
}

View file

@ -21,7 +21,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration;
import org.eclipse.cdt.core.dom.parser.cpp.ANSICPPParserExtensionConfiguration;
import org.eclipse.cdt.core.dom.parser.cpp.GPPParserExtensionConfiguration;
import org.eclipse.cdt.core.dom.parser.cpp.GPPScannerExtensionConfiguration;
import org.eclipse.cdt.core.dom.parser.cpp.ICPPParserExtensionConfiguration;
import org.eclipse.cdt.core.index.IIndex;
@ -194,7 +194,7 @@ public abstract class TestBase extends IndexBindingResolutionTestBase {
IScanner scanner = createScanner(FileContent.create(TEST_CODE, code.toCharArray()), ParserLanguage.CPP,
ParserMode.COMPLETE_PARSE, SCANNER_INFO);
AbstractGNUSourceCodeParser parser = null;
ICPPParserExtensionConfiguration config = new ANSICPPParserExtensionConfiguration();
ICPPParserExtensionConfiguration config = new GPPParserExtensionConfiguration();
parser = new GNUCPPSourceParser(scanner, ParserMode.COMPLETE_PARSE, NULL_LOG, config, null);
parser.setMaximumTrivialExpressionsInAggregateInitializers(Integer.MAX_VALUE);

View file

@ -53,6 +53,8 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitTypedef;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecBuiltin;
/**
* This is the IBuiltinBindingsProvider used to implement the "Other" built-in GCC symbols defined:
@ -188,6 +190,8 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
function("bool", "__atomic_always_lock_free", "size_t", "void*");
function("bool", "__atomic_is_lock_free", "size_t", "void*");
ICPPExecution builtinFfs = new ExecBuiltin(ExecBuiltin.BUILTIN_FFS);
// Other Builtins (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) [incomplete]
function("void", "__builtin_abort");
function("int", "__builtin_abs", "int");
@ -277,9 +281,9 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
function("double", "__builtin_fdim", "double", "double");
function("float", "__builtin_fdimf", "float", "float");
function("long double", "__builtin_fdiml", "long double", "long double");
function("int", "__builtin_ffs", "unsigned int");
function("int", "__builtin_ffsl", "unsigned long");
function("int", "__builtin_ffsll", "unsigned long long");
function("int", "__builtin_ffs", builtinFfs, "unsigned int");
function("int", "__builtin_ffsl", builtinFfs, "unsigned long");
function("int", "__builtin_ffsll", builtinFfs, "unsigned long long");
function("double", "__builtin_floor", "double");
function("float", "__builtin_floorf", "float");
function("long double", "__builtin_floorl", "long double");
@ -501,6 +505,13 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
}
private void function(String returnType, String name, String... parameterTypes) {
function(returnType, name, null, parameterTypes);
}
/*
* Create a function which can possibly be constexpr-evaluated
*/
private void function(String returnType, String name, ICPPExecution exec, String... parameterTypes) {
int len = parameterTypes.length;
boolean varargs = len > 0 && parameterTypes[len - 1].equals("...");
if (varargs)
@ -511,14 +522,14 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
for (int i = 0; i < len; i++) {
IType pType = toType(parameterTypes[i]);
pTypes[i] = pType;
theParms[i] = fCpp ? new CPPBuiltinParameter(pType) : new CBuiltinParameter(pType);
theParms[i] = fCpp ? new CPPBuiltinParameter(pType, i) : new CBuiltinParameter(pType);
}
IType rt = toType(returnType);
IFunctionType ft = fCpp ? new CPPFunctionType(rt, pTypes, null) : new CFunctionType(rt, pTypes);
IBinding b = fCpp
? new CPPImplicitFunction(toCharArray(name), fScope, (ICPPFunctionType) ft, (ICPPParameter[]) theParms,
false, varargs)
? new CPPBuiltinImplicitFunction(toCharArray(name), fScope, (ICPPFunctionType) ft,
(ICPPParameter[]) theParms, varargs, exec)
: new CImplicitFunction(toCharArray(name), fScope, ft, theParms, varargs);
fBindingList.add(b);
}
@ -661,4 +672,22 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
public boolean isKnownBuiltin(char[] builtinName) {
return fKnownBuiltins.containsKey(builtinName);
}
/*
* A builtin function which can be evaluated in a constexpr context
*/
private static class CPPBuiltinImplicitFunction extends CPPImplicitFunction {
private ICPPExecution execution;
public CPPBuiltinImplicitFunction(char[] name, IScope scope, ICPPFunctionType type, ICPPParameter[] params,
boolean takesVarArgs, ICPPExecution execution) {
super(name, scope, type, params, true, takesVarArgs);
this.execution = execution;
}
@Override
public ICPPExecution getFunctionBodyExecution() {
return execution;
}
}
}

View file

@ -52,7 +52,7 @@ public interface ITypeMarshalBuffer {
EXEC_DECLARATION_STATEMENT = 0x05, EXEC_DECLARATOR = 0x06, EXEC_DEFAULT = 0x07,
EXEC_SIMPLE_DECLARATION = 0x08, EXEC_RETURN = 0x09, EXEC_EXPRESSION_STATEMENT = 0x0A, EXEC_IF = 0x0B,
EXEC_WHILE = 0x0C, EXEC_DO = 0x0D, EXEC_FOR = 0x0E, EXEC_RANGE_BASED_FOR = 0x0F, EXEC_SWITCH = 0x10,
EXEC_CONSTRUCTOR_CHAIN = 0x11, EXEC_INCOMPLETE = 0x12;
EXEC_CONSTRUCTOR_CHAIN = 0x11, EXEC_INCOMPLETE = 0x12, EXEC_BUILTIN = 0x13;
// Can add more executions up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE.
static final short KIND_MASK = 0x001F;

View file

@ -38,9 +38,16 @@ public class CPPBuiltinParameter extends PlatformObject implements ICPPParameter
}
private IType type;
private int position;
public CPPBuiltinParameter(IType type) {
this.type = type;
this.position = -1;
}
public CPPBuiltinParameter(IType type, int position) {
this.type = type;
this.position = position;
}
@Override
@ -75,6 +82,9 @@ public class CPPBuiltinParameter extends PlatformObject implements ICPPParameter
@Override
public String getName() {
if (position != -1) {
return "arg" + position; //$NON-NLS-1$
}
return ""; //$NON-NLS-1$
}

View file

@ -0,0 +1,89 @@
/*******************************************************************************
* Copyright (c) 2022 Davin McCall and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Davin McCall - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.IType;
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.IntegralValue;
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.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation.ConstexprEvaluationContext;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
import org.eclipse.core.runtime.CoreException;
/**
* Constexpr-evaluation for compiler builtin functions.
*/
public class ExecBuiltin implements ICPPExecution {
public final static short BUILTIN_FFS = 0;
private static IType intType = new CPPBasicType(Kind.eInt, 0);
private short funcId;
public ExecBuiltin(short funcId) {
this.funcId = funcId;
}
@Override
public ICPPExecution instantiate(InstantiationContext context, int maxDepth) {
return this;
}
@Override
public ICPPExecution executeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) {
switch (funcId) {
case BUILTIN_FFS:
return executeBuiltinFfs(record, context);
}
return null;
}
private ICPPExecution executeBuiltinFfs(ActivationRecord record, ConstexprEvaluationContext context) {
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
IValue argValue = arg0.getValue();
if (!(argValue instanceof IntegralValue))
return null;
// __builtin_ffs returns 0 if arg is 0, or 1+count where count is the number of trailing 0 bits
long arg = argValue.numberValue().longValue();
if (arg == 0) {
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)));
}
@Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
buffer.putShort(ITypeMarshalBuffer.EXEC_BUILTIN);
buffer.putShort(funcId);
}
public static ICPPExecution unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException {
short funcId = buffer.getShort();
return new ExecBuiltin(funcId);
}
}

View file

@ -143,6 +143,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalTypeId;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalUnary;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalUnaryTypeID;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecBreak;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecBuiltin;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecCase;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecCompoundStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecConstructorChain;
@ -1771,6 +1772,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
return ExecConstructorChain.unmarshal(firstBytes, buffer);
case ITypeMarshalBuffer.EXEC_INCOMPLETE:
return ExecIncomplete.unmarshal(firstBytes, buffer);
case ITypeMarshalBuffer.EXEC_BUILTIN:
return ExecBuiltin.unmarshal(firstBytes, buffer);
}
throw new CoreException(CCorePlugin.createStatus("Cannot unmarshal an execution, first bytes=" + firstBytes)); //$NON-NLS-1$
}