mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-22 06:02:11 +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 {
|
public void testHexLiteral() throws Exception {
|
||||||
assertEvaluationEquals(42);
|
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.IValue;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
|
||||||
import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration;
|
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.GPPScannerExtensionConfiguration;
|
||||||
import org.eclipse.cdt.core.dom.parser.cpp.ICPPParserExtensionConfiguration;
|
import org.eclipse.cdt.core.dom.parser.cpp.ICPPParserExtensionConfiguration;
|
||||||
import org.eclipse.cdt.core.index.IIndex;
|
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,
|
IScanner scanner = createScanner(FileContent.create(TEST_CODE, code.toCharArray()), ParserLanguage.CPP,
|
||||||
ParserMode.COMPLETE_PARSE, SCANNER_INFO);
|
ParserMode.COMPLETE_PARSE, SCANNER_INFO);
|
||||||
AbstractGNUSourceCodeParser parser = null;
|
AbstractGNUSourceCodeParser parser = null;
|
||||||
ICPPParserExtensionConfiguration config = new ANSICPPParserExtensionConfiguration();
|
ICPPParserExtensionConfiguration config = new GPPParserExtensionConfiguration();
|
||||||
parser = new GNUCPPSourceParser(scanner, ParserMode.COMPLETE_PARSE, NULL_LOG, config, null);
|
parser = new GNUCPPSourceParser(scanner, ParserMode.COMPLETE_PARSE, NULL_LOG, config, null);
|
||||||
parser.setMaximumTrivialExpressionsInAggregateInitializers(Integer.MAX_VALUE);
|
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.CPPPointerType;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType;
|
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.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:
|
* 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_always_lock_free", "size_t", "void*");
|
||||||
function("bool", "__atomic_is_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]
|
// Other Builtins (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html) [incomplete]
|
||||||
function("void", "__builtin_abort");
|
function("void", "__builtin_abort");
|
||||||
function("int", "__builtin_abs", "int");
|
function("int", "__builtin_abs", "int");
|
||||||
|
@ -277,9 +281,9 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
|
||||||
function("double", "__builtin_fdim", "double", "double");
|
function("double", "__builtin_fdim", "double", "double");
|
||||||
function("float", "__builtin_fdimf", "float", "float");
|
function("float", "__builtin_fdimf", "float", "float");
|
||||||
function("long double", "__builtin_fdiml", "long double", "long double");
|
function("long double", "__builtin_fdiml", "long double", "long double");
|
||||||
function("int", "__builtin_ffs", "unsigned int");
|
function("int", "__builtin_ffs", builtinFfs, "unsigned int");
|
||||||
function("int", "__builtin_ffsl", "unsigned long");
|
function("int", "__builtin_ffsl", builtinFfs, "unsigned long");
|
||||||
function("int", "__builtin_ffsll", "unsigned long long");
|
function("int", "__builtin_ffsll", builtinFfs, "unsigned long long");
|
||||||
function("double", "__builtin_floor", "double");
|
function("double", "__builtin_floor", "double");
|
||||||
function("float", "__builtin_floorf", "float");
|
function("float", "__builtin_floorf", "float");
|
||||||
function("long double", "__builtin_floorl", "long double");
|
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) {
|
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;
|
int len = parameterTypes.length;
|
||||||
boolean varargs = len > 0 && parameterTypes[len - 1].equals("...");
|
boolean varargs = len > 0 && parameterTypes[len - 1].equals("...");
|
||||||
if (varargs)
|
if (varargs)
|
||||||
|
@ -511,14 +522,14 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
IType pType = toType(parameterTypes[i]);
|
IType pType = toType(parameterTypes[i]);
|
||||||
pTypes[i] = pType;
|
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);
|
IType rt = toType(returnType);
|
||||||
IFunctionType ft = fCpp ? new CPPFunctionType(rt, pTypes, null) : new CFunctionType(rt, pTypes);
|
IFunctionType ft = fCpp ? new CPPFunctionType(rt, pTypes, null) : new CFunctionType(rt, pTypes);
|
||||||
|
|
||||||
IBinding b = fCpp
|
IBinding b = fCpp
|
||||||
? new CPPImplicitFunction(toCharArray(name), fScope, (ICPPFunctionType) ft, (ICPPParameter[]) theParms,
|
? new CPPBuiltinImplicitFunction(toCharArray(name), fScope, (ICPPFunctionType) ft,
|
||||||
false, varargs)
|
(ICPPParameter[]) theParms, varargs, exec)
|
||||||
: new CImplicitFunction(toCharArray(name), fScope, ft, theParms, varargs);
|
: new CImplicitFunction(toCharArray(name), fScope, ft, theParms, varargs);
|
||||||
fBindingList.add(b);
|
fBindingList.add(b);
|
||||||
}
|
}
|
||||||
|
@ -661,4 +672,22 @@ public class GCCBuiltinSymbolProvider implements IBuiltinBindingsProvider {
|
||||||
public boolean isKnownBuiltin(char[] builtinName) {
|
public boolean isKnownBuiltin(char[] builtinName) {
|
||||||
return fKnownBuiltins.containsKey(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_DECLARATION_STATEMENT = 0x05, EXEC_DECLARATOR = 0x06, EXEC_DEFAULT = 0x07,
|
||||||
EXEC_SIMPLE_DECLARATION = 0x08, EXEC_RETURN = 0x09, EXEC_EXPRESSION_STATEMENT = 0x0A, EXEC_IF = 0x0B,
|
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_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.
|
// Can add more executions up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE.
|
||||||
|
|
||||||
static final short KIND_MASK = 0x001F;
|
static final short KIND_MASK = 0x001F;
|
||||||
|
|
|
@ -38,9 +38,16 @@ public class CPPBuiltinParameter extends PlatformObject implements ICPPParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
private IType type;
|
private IType type;
|
||||||
|
private int position;
|
||||||
|
|
||||||
public CPPBuiltinParameter(IType type) {
|
public CPPBuiltinParameter(IType type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.position = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPPBuiltinParameter(IType type, int position) {
|
||||||
|
this.type = type;
|
||||||
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -75,6 +82,9 @@ public class CPPBuiltinParameter extends PlatformObject implements ICPPParameter
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
if (position != -1) {
|
||||||
|
return "arg" + position; //$NON-NLS-1$
|
||||||
|
}
|
||||||
return ""; //$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.EvalUnary;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalUnaryTypeID;
|
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.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.ExecCase;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecCompoundStatement;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecCompoundStatement;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecConstructorChain;
|
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);
|
return ExecConstructorChain.unmarshal(firstBytes, buffer);
|
||||||
case ITypeMarshalBuffer.EXEC_INCOMPLETE:
|
case ITypeMarshalBuffer.EXEC_INCOMPLETE:
|
||||||
return ExecIncomplete.unmarshal(firstBytes, buffer);
|
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$
|
throw new CoreException(CCorePlugin.createStatus("Cannot unmarshal an execution, first bytes=" + firstBytes)); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue