mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-22 06:02:11 +02:00
Bug 580201 - narrowing for constexpr evaluation of builtins
Implement narrowing of argument value (in constexpr context) for various builtins. Change-Id: I428cc789358638bf3796ea706f459032c8be10a1
This commit is contained in:
parent
b1011b0a82
commit
4a956060cd
5 changed files with 171 additions and 36 deletions
|
@ -113,6 +113,7 @@ public class AST2TestBase extends SemanticTestBase {
|
||||||
map.put("__SIZEOF_SHORT__", "2");
|
map.put("__SIZEOF_SHORT__", "2");
|
||||||
map.put("__SIZEOF_INT__", "4");
|
map.put("__SIZEOF_INT__", "4");
|
||||||
map.put("__SIZEOF_LONG__", "8");
|
map.put("__SIZEOF_LONG__", "8");
|
||||||
|
map.put("__SIZEOF_LONG_LONG__", "8");
|
||||||
map.put("__SIZEOF_DOUBLE__", "8");
|
map.put("__SIZEOF_DOUBLE__", "8");
|
||||||
map.put("__SIZEOF_POINTER__", "8");
|
map.put("__SIZEOF_POINTER__", "8");
|
||||||
return map;
|
return map;
|
||||||
|
@ -123,6 +124,7 @@ public class AST2TestBase extends SemanticTestBase {
|
||||||
map.put("__SIZEOF_SHORT__", "2");
|
map.put("__SIZEOF_SHORT__", "2");
|
||||||
map.put("__SIZEOF_INT__", "4");
|
map.put("__SIZEOF_INT__", "4");
|
||||||
map.put("__SIZEOF_LONG__", "8");
|
map.put("__SIZEOF_LONG__", "8");
|
||||||
|
map.put("__SIZEOF_LONG_LONG__", "8");
|
||||||
map.put("__SIZEOF_DOUBLE__", "8");
|
map.put("__SIZEOF_DOUBLE__", "8");
|
||||||
map.put("__SIZEOF_POINTER__", "8");
|
map.put("__SIZEOF_POINTER__", "8");
|
||||||
return map;
|
return map;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.core.parser.tests.ast2.cxx14.constexpr;
|
package org.eclipse.cdt.core.parser.tests.ast2.cxx14.constexpr;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.testplugin.TestScannerProvider;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
|
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
|
||||||
|
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
@ -36,6 +37,16 @@ public abstract class IntegralValueTests extends TestBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
TestScannerProvider.sDefinedSymbols.put("__SIZEOF_SHORT__", "2");
|
||||||
|
TestScannerProvider.sDefinedSymbols.put("__SIZEOF_INT__", "4");
|
||||||
|
TestScannerProvider.sDefinedSymbols.put("__SIZEOF_LONG__", "8");
|
||||||
|
TestScannerProvider.sDefinedSymbols.put("__SIZEOF_LONG_LONG__", "8");
|
||||||
|
TestScannerProvider.sDefinedSymbols.put("__SIZEOF_POINTER__", "8");
|
||||||
|
super.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
// constexpr auto x = int{} + int();
|
// constexpr auto x = int{} + int();
|
||||||
public void testIntDefaultValue() throws Exception {
|
public void testIntDefaultValue() throws Exception {
|
||||||
assertEvaluationEquals(0);
|
assertEvaluationEquals(0);
|
||||||
|
@ -275,6 +286,16 @@ public abstract class IntegralValueTests extends TestBase {
|
||||||
assertEvaluationEquals(5);
|
assertEvaluationEquals(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// constexpr int x = __builtin_ffs(0x100000000);
|
||||||
|
public void testBuiltinFfsNarrowing() throws Exception {
|
||||||
|
assertEvaluationEquals(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// constexpr int x = __builtin_ffsl(0x100000000);
|
||||||
|
public void testBuiltinFfsl() throws Exception {
|
||||||
|
assertEvaluationEquals(33);
|
||||||
|
}
|
||||||
|
|
||||||
// constexpr int x = __builtin_ctz(16);
|
// constexpr int x = __builtin_ctz(16);
|
||||||
public void testBuiltinCtz() throws Exception {
|
public void testBuiltinCtz() throws Exception {
|
||||||
assertEvaluationEquals(4);
|
assertEvaluationEquals(4);
|
||||||
|
@ -314,4 +335,9 @@ public abstract class IntegralValueTests extends TestBase {
|
||||||
public void testBuiltinAbsNegativeInput() throws Exception {
|
public void testBuiltinAbsNegativeInput() throws Exception {
|
||||||
assertEvaluationEquals(1);
|
assertEvaluationEquals(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// constexpr int x = __builtin_abs(0xFFFFFFFF);
|
||||||
|
public void testBuiltinAbsNarrowing() throws Exception {
|
||||||
|
assertEvaluationEquals(1);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -66,6 +66,7 @@ public abstract class TestBase extends IndexBindingResolutionTestBase {
|
||||||
map.put("__SIZEOF_SHORT__", "2");
|
map.put("__SIZEOF_SHORT__", "2");
|
||||||
map.put("__SIZEOF_INT__", "4");
|
map.put("__SIZEOF_INT__", "4");
|
||||||
map.put("__SIZEOF_LONG__", "8");
|
map.put("__SIZEOF_LONG__", "8");
|
||||||
|
map.put("__SIZEOF_LONG_LONG__", "8");
|
||||||
map.put("__SIZEOF_POINTER__", "8");
|
map.put("__SIZEOF_POINTER__", "8");
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
|
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.isVoidType;
|
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.isVoidType;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
|
@ -60,6 +61,8 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
|
||||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
|
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
||||||
|
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.CPPPointerToMemberType;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
|
||||||
|
@ -1326,4 +1329,99 @@ public class Conversions {
|
||||||
private static boolean isNullPtr(IType t1) {
|
private static boolean isNullPtr(IType t1) {
|
||||||
return t1 instanceof IBasicType && ((IBasicType) t1).getKind() == Kind.eNullPtr;
|
return t1 instanceof IBasicType && ((IBasicType) t1).getKind() == Kind.eNullPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Narrow a numeric value to the range of a specified type.
|
||||||
|
* @param num the value to narrow (may be null)
|
||||||
|
* @param toType the type to narrow to
|
||||||
|
* @return a number representing the narrowed value, or null
|
||||||
|
*/
|
||||||
|
public static Number narrowNumberValue(Number num, IType toType) {
|
||||||
|
if (num == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (toType instanceof IBasicType) {
|
||||||
|
IBasicType basicType = (IBasicType) toType;
|
||||||
|
IBasicType.Kind basicTypeKind = basicType.getKind();
|
||||||
|
switch (basicTypeKind) {
|
||||||
|
case eFloat:
|
||||||
|
if (num instanceof Float)
|
||||||
|
return num;
|
||||||
|
return Float.valueOf(num.floatValue());
|
||||||
|
case eDouble:
|
||||||
|
if (num instanceof Double)
|
||||||
|
return num;
|
||||||
|
return Double.valueOf(num.doubleValue());
|
||||||
|
case eInt:
|
||||||
|
SizeAndAlignment sizeToType = SizeofCalculator.getSizeAndAlignment(toType);
|
||||||
|
if (sizeToType == null)
|
||||||
|
return null;
|
||||||
|
// Note in the following we don't check type.isSigned() since that checks for the
|
||||||
|
// explicit presence of the "signed" modifier. So instead check !type.isUnsigned().
|
||||||
|
if (sizeToType.size <= 8) {
|
||||||
|
// First, mask the value to the correct size
|
||||||
|
// Note that we take the longValue here which may be negative even though the
|
||||||
|
// original value is positive; the masking here should still be correct and we
|
||||||
|
// should ultimately end up with the correct narrowed value, regardless.
|
||||||
|
long longVal = num.longValue();
|
||||||
|
long maskVal = 0xFFFFFFFFFFFFFFFFL;
|
||||||
|
long signBit = 0x8000000000000000L;
|
||||||
|
// Calculate a mask to reduce the size of the value to the target width:
|
||||||
|
maskVal >>>= (8 - sizeToType.size) * 8;
|
||||||
|
signBit >>>= (8 - sizeToType.size) * 8;
|
||||||
|
if (!basicType.isUnsigned() && (longVal & signBit) != 0) {
|
||||||
|
// We need to extend the sign bit.
|
||||||
|
long signBits = ~maskVal;
|
||||||
|
longVal |= signBits;
|
||||||
|
} else {
|
||||||
|
longVal &= maskVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Java type used to store the numerical value is independent of the associated
|
||||||
|
// C type, but we go with a smaller type (Integer) where possible. For 4 bytes
|
||||||
|
// (signed) or less than 4 bytes (signed or not) we can use Integer. For 8 bytes
|
||||||
|
// (signed) or less than 8 bytes (signed or not) we can use Long. Any larger and we
|
||||||
|
// resort to BigInteger.
|
||||||
|
if (longVal >= 0 && longVal <= Integer.MAX_VALUE) {
|
||||||
|
return Integer.valueOf((int) longVal);
|
||||||
|
}
|
||||||
|
if (!basicType.isUnsigned() && longVal >= Integer.MIN_VALUE && longVal <= Integer.MAX_VALUE) {
|
||||||
|
return Integer.valueOf((int) longVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!basicType.isUnsigned() || longVal > 0) {
|
||||||
|
return Long.valueOf(longVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger biVal = BigInteger.valueOf(longVal);
|
||||||
|
// 2**64 = 18446744073709551616
|
||||||
|
biVal = biVal.add(new BigInteger("18446744073709551616")); //$NON-NLS-1$
|
||||||
|
return biVal;
|
||||||
|
}
|
||||||
|
// TODO handle larger int sizes?
|
||||||
|
return null;
|
||||||
|
case eChar:
|
||||||
|
// TODO don't assume signed char
|
||||||
|
if (num instanceof Byte)
|
||||||
|
return num;
|
||||||
|
return Byte.valueOf(num.byteValue());
|
||||||
|
case eChar16:
|
||||||
|
int intVal = num.intValue();
|
||||||
|
int maskedVal = intVal & 0xFFFF;
|
||||||
|
if (maskedVal == intVal && num instanceof Integer)
|
||||||
|
return num;
|
||||||
|
return Integer.valueOf(maskedVal);
|
||||||
|
case eChar32:
|
||||||
|
long longVal = num.longValue();
|
||||||
|
long maskedVal32 = longVal & 0xFFFFFFFFL;
|
||||||
|
if (maskedVal32 == longVal && (num instanceof Integer || num instanceof Long))
|
||||||
|
return num;
|
||||||
|
return Long.valueOf(maskedVal32);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,25 +55,35 @@ public class ExecBuiltin implements ICPPExecution {
|
||||||
|
|
||||||
switch (funcId) {
|
switch (funcId) {
|
||||||
case BUILTIN_FFS:
|
case BUILTIN_FFS:
|
||||||
|
return executeBuiltinFfs(record, context, intType);
|
||||||
case BUILTIN_FFSL:
|
case BUILTIN_FFSL:
|
||||||
|
return executeBuiltinFfs(record, context, longType);
|
||||||
case BUILTIN_FFSLL:
|
case BUILTIN_FFSLL:
|
||||||
return executeBuiltinFfs(record, context);
|
return executeBuiltinFfs(record, context, longlongType);
|
||||||
case BUILTIN_CTZ:
|
case BUILTIN_CTZ:
|
||||||
|
return executeBuiltinCtz(record, context, intType);
|
||||||
case BUILTIN_CTZL:
|
case BUILTIN_CTZL:
|
||||||
|
return executeBuiltinCtz(record, context, longType);
|
||||||
case BUILTIN_CTZLL:
|
case BUILTIN_CTZLL:
|
||||||
return executeBuiltinCtz(record, context);
|
return executeBuiltinCtz(record, context, longlongType);
|
||||||
case BUILTIN_POPCOUNT:
|
case BUILTIN_POPCOUNT:
|
||||||
|
return executeBuiltinPopcount(record, context, intType);
|
||||||
case BUILTIN_POPCOUNTL:
|
case BUILTIN_POPCOUNTL:
|
||||||
|
return executeBuiltinPopcount(record, context, longType);
|
||||||
case BUILTIN_POPCOUNTLL:
|
case BUILTIN_POPCOUNTLL:
|
||||||
return executeBuiltinPopcount(record, context);
|
return executeBuiltinPopcount(record, context, longlongType);
|
||||||
case BUILTIN_PARITY:
|
case BUILTIN_PARITY:
|
||||||
|
return executeBuiltinParity(record, context, intType);
|
||||||
case BUILTIN_PARITYL:
|
case BUILTIN_PARITYL:
|
||||||
|
return executeBuiltinParity(record, context, longType);
|
||||||
case BUILTIN_PARITYLL:
|
case BUILTIN_PARITYLL:
|
||||||
return executeBuiltinParity(record, context);
|
return executeBuiltinParity(record, context, longlongType);
|
||||||
case BUILTIN_ABS:
|
case BUILTIN_ABS:
|
||||||
|
return executeBuiltinAbs(record, context, intType);
|
||||||
case BUILTIN_LABS:
|
case BUILTIN_LABS:
|
||||||
|
return executeBuiltinAbs(record, context, longType);
|
||||||
case BUILTIN_LLABS:
|
case BUILTIN_LLABS:
|
||||||
return executeBuiltinAbs(record, context);
|
return executeBuiltinAbs(record, context, longlongType);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -82,16 +92,18 @@ public class ExecBuiltin implements ICPPExecution {
|
||||||
* Return an execution representing __builtin_ffs or __builtin_ctz
|
* Return an execution representing __builtin_ffs or __builtin_ctz
|
||||||
*/
|
*/
|
||||||
private ICPPExecution executeBuiltinFfsCtz(ActivationRecord record, ConstexprEvaluationContext context,
|
private ICPPExecution executeBuiltinFfsCtz(ActivationRecord record, ConstexprEvaluationContext context,
|
||||||
boolean isCtz) {
|
boolean isCtz, IType argType) {
|
||||||
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
|
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
|
||||||
|
|
||||||
IValue argValue = arg0.getValue();
|
IValue argValue = arg0.getValue();
|
||||||
if (!(argValue instanceof IntegralValue))
|
Number numberVal = argValue.numberValue();
|
||||||
|
numberVal = Conversions.narrowNumberValue(numberVal, argType);
|
||||||
|
if (numberVal == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// __builtin_ffs returns 0 if arg is 0, or 1+count where count is the number of trailing 0 bits
|
// __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
|
// __builtin_ctz is undefined if arg is 0, or returns count
|
||||||
long arg = argValue.numberValue().longValue();
|
long arg = numberVal.longValue();
|
||||||
if (arg == 0) {
|
if (arg == 0) {
|
||||||
if (isCtz) {
|
if (isCtz) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -108,26 +120,30 @@ public class ExecBuiltin implements ICPPExecution {
|
||||||
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(count + increment)));
|
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(count + increment)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICPPExecution executeBuiltinFfs(ActivationRecord record, ConstexprEvaluationContext context) {
|
private ICPPExecution executeBuiltinFfs(ActivationRecord record, ConstexprEvaluationContext context,
|
||||||
return executeBuiltinFfsCtz(record, context, false /* ffs */);
|
IType argType) {
|
||||||
|
return executeBuiltinFfsCtz(record, context, false /* ffs */, argType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICPPExecution executeBuiltinCtz(ActivationRecord record, ConstexprEvaluationContext context) {
|
private ICPPExecution executeBuiltinCtz(ActivationRecord record, ConstexprEvaluationContext context,
|
||||||
return executeBuiltinFfsCtz(record, context, true /* ctz */);
|
IType argType) {
|
||||||
|
return executeBuiltinFfsCtz(record, context, true /* ctz */, argType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return an execution representing __builtin_popcount
|
* Return an execution representing __builtin_popcount
|
||||||
*/
|
*/
|
||||||
private ICPPExecution executeBuiltinPopcountParity(ActivationRecord record, ConstexprEvaluationContext context,
|
private ICPPExecution executeBuiltinPopcountParity(ActivationRecord record, ConstexprEvaluationContext context,
|
||||||
boolean isParity) {
|
boolean isParity, IType argType) {
|
||||||
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
|
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
|
||||||
|
|
||||||
IValue argValue = arg0.getValue();
|
IValue argValue = arg0.getValue();
|
||||||
if (!(argValue instanceof IntegralValue))
|
Number numberVal = argValue.numberValue();
|
||||||
|
numberVal = Conversions.narrowNumberValue(numberVal, argType);
|
||||||
|
if (numberVal == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
long arg = argValue.numberValue().longValue();
|
long arg = numberVal.longValue();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (arg != 0) {
|
while (arg != 0) {
|
||||||
if ((arg & 1) != 0)
|
if ((arg & 1) != 0)
|
||||||
|
@ -140,38 +156,30 @@ public class ExecBuiltin implements ICPPExecution {
|
||||||
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(count)));
|
return new ExecReturn(new EvalFixed(intType, ValueCategory.PRVALUE, IntegralValue.create(count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICPPExecution executeBuiltinPopcount(ActivationRecord record, ConstexprEvaluationContext context) {
|
private ICPPExecution executeBuiltinPopcount(ActivationRecord record, ConstexprEvaluationContext context,
|
||||||
return executeBuiltinPopcountParity(record, context, false);
|
IType argType) {
|
||||||
|
return executeBuiltinPopcountParity(record, context, false, argType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICPPExecution executeBuiltinParity(ActivationRecord record, ConstexprEvaluationContext context) {
|
private ICPPExecution executeBuiltinParity(ActivationRecord record, ConstexprEvaluationContext context,
|
||||||
return executeBuiltinPopcountParity(record, context, true);
|
IType argType) {
|
||||||
|
return executeBuiltinPopcountParity(record, context, true, argType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICPPExecution executeBuiltinAbs(ActivationRecord record, ConstexprEvaluationContext context) {
|
private ICPPExecution executeBuiltinAbs(ActivationRecord record, ConstexprEvaluationContext context,
|
||||||
|
IType argType) {
|
||||||
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
|
ICPPEvaluation arg0 = record.getVariable(new CPPBuiltinParameter(null, 0));
|
||||||
|
|
||||||
IValue argValue = arg0.getValue();
|
IValue argValue = arg0.getValue();
|
||||||
if (!(argValue instanceof IntegralValue))
|
Number argNumber = argValue.numberValue();
|
||||||
|
argNumber = Conversions.narrowNumberValue(argNumber, argType);
|
||||||
|
if (argNumber == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
long arg = argValue.numberValue().longValue();
|
long arg = argNumber.longValue();
|
||||||
long result = Math.abs(arg);
|
long result = Math.abs(arg);
|
||||||
|
|
||||||
IType resultType = null;
|
return new ExecReturn(new EvalFixed(argType, ValueCategory.PRVALUE, IntegralValue.create(result)));
|
||||||
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
|
@Override
|
||||||
|
|
Loading…
Add table
Reference in a new issue