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:
parent
9b05a213eb
commit
1ec4ae52c1
7 changed files with 145 additions and 9 deletions
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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$
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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$
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue