Unverified Commit fa34a9ad by John Kessenich Committed by GitHub

Merge pull request #1385 from KhronosGroup/fix-strtod

PP: Fix strtod problems: add tests, remove 2nd use, replace
parents 8e4b496d 3e8e9f7b
cppPassMacroName.frag
Shader version: 100
0:? Sequence
0:5 Function Definition: main( ( global void)
0:5 Function Parameters:
0:7 Sequence
0:7 Sequence
0:7 move second child to first child ( temp mediump int)
0:7 'f1' ( temp mediump int)
0:7 Constant:
0:7 4 (const int)
0:8 Sequence
0:8 move second child to first child ( temp mediump int)
0:8 'f2' ( temp mediump int)
0:8 'f1' ( temp mediump int)
0:9 Sequence
0:9 move second child to first child ( temp mediump int)
0:9 'f3' ( temp mediump int)
0:9 Constant:
0:9 9 (const int)
0:10 Sequence
0:10 move second child to first child ( temp mediump int)
0:10 'f4' ( temp mediump int)
0:10 Constant:
0:10 1 (const int)
0:9 Function Definition: main( ( global void)
0:9 Function Parameters:
0:11 Sequence
0:11 Sequence
0:11 move second child to first child ( temp mediump int)
0:11 'f5' ( temp mediump int)
0:11 'f1' ( temp mediump int)
0:11 Constant:
0:11 5 (const int)
0:11 4 (const int)
0:12 Sequence
0:12 move second child to first child ( temp mediump int)
0:12 'f2' ( temp mediump int)
0:12 'f1' ( temp mediump int)
0:13 Sequence
0:13 move second child to first child ( temp mediump int)
0:13 'f3' ( temp mediump int)
0:13 Constant:
0:13 9 (const int)
0:14 Sequence
0:14 move second child to first child ( temp mediump int)
0:14 'f4' ( temp mediump int)
0:14 Constant:
0:14 1 (const int)
0:15 Sequence
0:15 move second child to first child ( temp mediump int)
0:15 'f5' ( temp mediump int)
0:15 Constant:
0:15 5 (const int)
0:17 Sequence
0:17 move second child to first child ( temp highp float)
0:17 'fl_f5' ( temp highp float)
0:17 Constant:
0:17 0.460000
0:? Linker Objects
......@@ -36,32 +41,37 @@ Linked fragment stage:
Shader version: 100
0:? Sequence
0:5 Function Definition: main( ( global void)
0:5 Function Parameters:
0:7 Sequence
0:7 Sequence
0:7 move second child to first child ( temp mediump int)
0:7 'f1' ( temp mediump int)
0:7 Constant:
0:7 4 (const int)
0:8 Sequence
0:8 move second child to first child ( temp mediump int)
0:8 'f2' ( temp mediump int)
0:8 'f1' ( temp mediump int)
0:9 Sequence
0:9 move second child to first child ( temp mediump int)
0:9 'f3' ( temp mediump int)
0:9 Constant:
0:9 9 (const int)
0:10 Sequence
0:10 move second child to first child ( temp mediump int)
0:10 'f4' ( temp mediump int)
0:10 Constant:
0:10 1 (const int)
0:9 Function Definition: main( ( global void)
0:9 Function Parameters:
0:11 Sequence
0:11 Sequence
0:11 move second child to first child ( temp mediump int)
0:11 'f5' ( temp mediump int)
0:11 'f1' ( temp mediump int)
0:11 Constant:
0:11 5 (const int)
0:11 4 (const int)
0:12 Sequence
0:12 move second child to first child ( temp mediump int)
0:12 'f2' ( temp mediump int)
0:12 'f1' ( temp mediump int)
0:13 Sequence
0:13 move second child to first child ( temp mediump int)
0:13 'f3' ( temp mediump int)
0:13 Constant:
0:13 9 (const int)
0:14 Sequence
0:14 move second child to first child ( temp mediump int)
0:14 'f4' ( temp mediump int)
0:14 Constant:
0:14 1 (const int)
0:15 Sequence
0:15 move second child to first child ( temp mediump int)
0:15 'f5' ( temp mediump int)
0:15 Constant:
0:15 5 (const int)
0:17 Sequence
0:17 move second child to first child ( temp highp float)
0:17 'fl_f5' ( temp highp float)
0:17 Constant:
0:17 0.460000
0:? Linker Objects
......@@ -66,7 +66,7 @@ ERROR: node is still EOpNull!
0:74 move second child to first child ( temp highp float)
0:74 'funkyf' ( global highp float)
0:75 Constant:
0:75 12300000000000000.000000
0:75 1.2300000000000e+16
0:85 Sequence
0:84 move second child to first child ( temp highp int)
0:84 'funkyh' ( global highp int)
......@@ -200,7 +200,7 @@ ERROR: node is still EOpNull!
0:74 move second child to first child ( temp highp float)
0:74 'funkyf' ( global highp float)
0:75 Constant:
0:75 12300000000000000.000000
0:75 1.2300000000000e+16
0:85 Sequence
0:84 move second child to first child ( temp highp int)
0:84 'funkyh' ( global highp int)
......
......@@ -330,7 +330,7 @@ ERROR: node is still EOpNull!
0:73 move second child to first child ( temp float)
0:73 'g6' ( temp float)
0:73 Constant:
0:73 0.000005
0:73 5.0000000000000e-06
0:74 Sequence
0:74 move second child to first child ( temp float)
0:74 'g7' ( temp float)
......@@ -739,7 +739,7 @@ ERROR: node is still EOpNull!
0:73 move second child to first child ( temp float)
0:73 'g6' ( temp float)
0:73 Constant:
0:73 0.000005
0:73 5.0000000000000e-06
0:74 Sequence
0:74 move second child to first child ( temp float)
0:74 'g7' ( temp float)
......
......@@ -2,6 +2,10 @@
#define I2(f, n) f(n) + f(n+1)
#define I3(f, n) I2(f, n) + f(n+2)
#define FL_f1(i) ((i)*(i))
#define FL_I2(f, n) f(n) + f(n+0.2)
#define FL_I3(f, n) FL_I2(f, n) + f(n+0.5)
void main()
{
int f1 = 4;
......@@ -9,4 +13,18 @@ void main()
int f3 = f1(3);
int f4 = I2(f1, 0);
int f5 = I3(f1, 0);
highp float fl_f5 = FL_I3(FL_f1, 0.1);
}
// f5 = I3(f1, 0)
// = I2(f1, 0) + f1(0 + 2)
// = f1(0) + f1(0+1) + f1(0+2)
// = 0*0 + 1*1 + 2*2
// = 5
// fl_f5 = FL_I3(FL_f1, 0.1)
// = FL_I2(FL_f1, 0.1) + FL_f1(0.1 + 0.5)
// = FL_f1(0.1) + FL_f1(0.1 + 0.2) + FL_f1(0.1 + 0.5)
// = 0.1*0.1 + 0.3*0.3 + 0.6*0.6
// = 0.46
#version 460
//#pragma glslang_binary_double_output
void main()
{
float w1 = 00000.000;
float w2 = 1.0;
float w3 = 007.00;
float w4 = 000130000.0;
float w5 = 123456789.0000;
double w6 = 1234567890123456.0;
double w7 = 12345678901234567.0;
double w8 = 123456789012345678.0;
double w9 = 12345678901234567893.0;
double w10 = 1234567890123456789012345.0;
float e1 = 0e0;
float e2 = 1e0;
float e3 = 0e14;
float e4 = 1e15;
float e5 = 1e16;
float e6 = 0e-14;
float e7 = 1e-15;
float e8 = 1e-16;
double e9 = 1e100;
double e10 = 1e+308;
double e11 = 1e-323;
double e12 = 1e+309;
double e13 = 1e-324;
double e24 = 1e+999;
double e25 = 1e-999;
double f1 = 0.5;
double f2 = 0.125;
double f31 = 0.1;
double f32 = 0.2;
double f33 = 0.3;
double f34 = 0.4;
double f35 = 0.5;
double f36 = 0.6;
double f37 = 0.7;
double f38 = 0.8;
double f39 = 0.9;
double f4 = 0.33333333333333333333333333333333333333333333333333333333333333333333333333333;
double f51 = 0.000000000000000000000000000000000000783475;
double f52 = 0.0000000000000000000000000000000000007834750;
double f53 = .00000000000000000000000000000000000078347500;
double f54 = 0.000000000000000000000000000000000000783475000000;
double f61 = 4.;
double f62 = 40.;
double f63 = 0.;
double f64 = 04.;
double f65 = .0;
double f66 = .004;
double f67 = .400;
double f68 = .04000;
double c1 = .081e-2;
double c2 = .073e2;
double c3 = 34.5e-1;
double c4 = 35.7e-4;
double c5 = 43.9e1;
double c6 = 52.2e4;
double c7 = 000610000e2;
double c8 = 000610000e-6;
double c9 = 000001234567890123450000.0;
double c10 = 000999999999999999999000.0;
double c11 = 0001230000.0045600000;
double c12 = 0001230000.00405600000e-3;
double c13 = 0001230000.004500600000e-4;
double c14 = 00010230000.0045600000e-5;
double c15 = 000120030000.0045600000e4;
double c16 = 0001230000.0045600000e5;
double c17 = 0001230000.0045600000e6;
double c18 = 0001230000.00456007e6;
double b11 = 72057594037927928.0;
double b12 = 72057594037927936.0;
double b13 = 72057594037927932.0;
double b14 = 7205759403792793199999e-5;
double b15 = 7205759403792793200001e-5;
double b21 = 9223372036854774784.0;
double b22 = 9223372036854775808.0;
double b23 = 9223372036854775296.0;
double b24 = 922337203685477529599999e-5;
double b25 = 922337203685477529600001e-5;
double b31 = 10141204801825834086073718800384.0;
double b32 = 10141204801825835211973625643008.0;
double b33 = 10141204801825834649023672221696.0;
double b34 = 1014120480182583464902367222169599999e-5;
double b35 = 1014120480182583464902367222169600001e-5;
double b41 = 5708990770823838890407843763683279797179383808.0;
double b42 = 5708990770823839524233143877797980545530986496.0;
double b43 = 5708990770823839207320493820740630171355185152.0;
double b44 = 5708990770823839207320493820740630171355185151999e-3;
double b45 = 5708990770823839207320493820740630171355185152001e-3;
double pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
}
#version 300 es
//#pragma glslang_binary_double_output
// 1023 characters
in float BCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789;
......
......@@ -269,7 +269,8 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>&
intermediate.setUseStorageBuffer();
} else if (tokens[0].compare("once") == 0) {
warn(loc, "not implemented", "#pragma once", "");
}
} else if (tokens[0].compare("glslang_binary_double_output") == 0)
intermediate.setBinaryDoubleOutput();
}
//
......
......@@ -93,7 +93,13 @@ namespace glslang {
//
class TOutputTraverser : public TIntermTraverser {
public:
TOutputTraverser(TInfoSink& i) : infoSink(i) { }
TOutputTraverser(TInfoSink& i) : infoSink(i), extraOutput(NoExtraOutput) { }
enum EExtraOutput {
NoExtraOutput,
BinaryDoubleOutput
};
void setDoubleOutput(EExtraOutput extra) { extraOutput = extra; }
virtual bool visitBinary(TVisit, TIntermBinary* node);
virtual bool visitUnary(TVisit, TIntermUnary* node);
......@@ -109,6 +115,8 @@ public:
protected:
TOutputTraverser(TOutputTraverser&);
TOutputTraverser& operator=(TOutputTraverser&);
EExtraOutput extraOutput;
};
//
......@@ -1082,7 +1090,61 @@ bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node
return false;
}
static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion, int depth)
// Print infinities and NaNs, and numbers in a portable way.
// Goals:
// - portable (across IEEE 754 platforms)
// - shows all possible IEEE values
// - shows simple numbers in a simple way, e.g., no leading/trailing 0s
// - shows all digits, no premature rounding
static void OutputDouble(TInfoSink& out, double value, TOutputTraverser::EExtraOutput extra)
{
if (IsInfinity(value)) {
if (value < 0)
out.debug << "-1.#INF";
else
out.debug << "+1.#INF";
} else if (IsNan(value))
out.debug << "1.#IND";
else {
const int maxSize = 340;
char buf[maxSize];
const char* format = "%f";
if (fabs(value) > 0.0 && (fabs(value) < 1e-5 || fabs(value) > 1e12))
format = "%-.13e";
snprintf(buf, maxSize, format, value);
// remove a leading zero in the 100s slot in exponent; it is not portable
// pattern: XX...XXXe+0XX or XX...XXXe-0XX
int len = (int)strnlen(buf, maxSize);
if (len > 5) {
if (buf[len-5] == 'e' && (buf[len-4] == '+' || buf[len-4] == '-') && buf[len-3] == '0') {
buf[len-3] = buf[len-2];
buf[len-2] = buf[len-1];
buf[len-1] = '\0';
}
}
out.debug << buf;
switch (extra) {
case TOutputTraverser::BinaryDoubleOutput:
{
out.debug << " : ";
long long b = *reinterpret_cast<long long*>(&value);
for (int i = 0; i < 8 * sizeof(value); ++i, ++b) {
out.debug << ((b & 0x8000000000000000) != 0 ? "1" : "0");
b <<= 1;
}
break;
}
default:
break;
}
}
}
static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion,
TOutputTraverser::EExtraOutput extra, int depth)
{
int size = node->getType().computeNumComponents();
......@@ -1102,24 +1164,8 @@ static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const
case EbtFloat:
case EbtDouble:
case EbtFloat16:
{
const double value = constUnion[i].getDConst();
// Print infinities and NaNs in a portable way.
if (IsInfinity(value)) {
if (value < 0)
out.debug << "-1.#INF\n";
else
out.debug << "+1.#INF\n";
} else if (IsNan(value))
out.debug << "1.#IND\n";
else {
const int maxSize = 300;
char buf[maxSize];
snprintf(buf, maxSize, "%f", value);
out.debug << buf << "\n";
}
}
OutputDouble(out, constUnion[i].getDConst(), extra);
out.debug << "\n";
break;
case EbtInt8:
{
......@@ -1205,7 +1251,7 @@ void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
OutputTreeText(infoSink, node, depth);
infoSink.debug << "Constant:\n";
OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
OutputConstantUnion(infoSink, node, node->getConstArray(), extraOutput, depth + 1);
}
void TOutputTraverser::visitSymbol(TIntermSymbol* node)
......@@ -1215,7 +1261,7 @@ void TOutputTraverser::visitSymbol(TIntermSymbol* node)
infoSink.debug << "'" << node->getName() << "' (" << node->getCompleteString() << ")\n";
if (! node->getConstArray().empty())
OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
OutputConstantUnion(infoSink, node, node->getConstArray(), extraOutput, depth + 1);
else if (node->getConstSubtree()) {
incrementDepth(node);
node->getConstSubtree()->traverse(this);
......@@ -1417,7 +1463,8 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
return;
TOutputTraverser it(infoSink);
if (getBinaryDoubleOutput())
it.setDoubleOutput(TOutputTraverser::BinaryDoubleOutput);
treeRoot->traverse(&it);
}
......
......@@ -233,7 +233,8 @@ public:
useStorageBuffer(false),
hlslIoMapping(false),
textureSamplerTransformMode(EShTexSampTransKeep),
needToLegalize(false)
needToLegalize(false),
binaryDoubleOutput(false)
{
localSize[0] = 1;
localSize[1] = 1;
......@@ -634,6 +635,9 @@ public:
void setNeedsLegalization() { needToLegalize = true; }
bool needsLegalization() const { return needToLegalize; }
void setBinaryDoubleOutput() { binaryDoubleOutput = true; }
bool getBinaryDoubleOutput() { return binaryDoubleOutput; }
const char* const implicitThisName;
const char* const implicitCounterName;
......@@ -742,6 +746,7 @@ protected:
TProcesses processes;
bool needToLegalize;
bool binaryDoubleOutput;
private:
void operator=(TIntermediate&); // prevent assignments
......
......@@ -77,6 +77,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\****************************************************************************/
#include <cstdlib>
#include <locale>
#include "PpContext.h"
......@@ -91,6 +92,8 @@ TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, T
for (elsetracker = 0; elsetracker < maxIfNesting; elsetracker++)
elseSeen[elsetracker] = false;
elsetracker = 0;
strtodStream.imbue(std::locale::classic());
}
TPpContext::~TPpContext()
......
......@@ -80,6 +80,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stack>
#include <unordered_map>
#include <sstream>
#include "../ParseHelper.h"
......@@ -92,13 +93,16 @@ namespace glslang {
class TPpToken {
public:
TPpToken() : space(false), i64val(0)
TPpToken() { clear(); }
void clear()
{
space = false;
i64val = 0;
loc.init();
name[0] = 0;
}
// This is used for comparing macro definitions, so checks what is relevant for that.
// Used for comparing macro definitions, so checks what is relevant for that.
bool operator==(const TPpToken& right)
{
return space == right.space &&
......@@ -108,15 +112,17 @@ public:
bool operator!=(const TPpToken& right) { return ! operator==(right); }
TSourceLoc loc;
bool space; // true if a space (for white space or a removed comment) should also be recognized, in front of the token returned
// True if a space (for white space or a removed comment) should also be
// recognized, in front of the token returned:
bool space;
// Numeric value of the token:
union {
int ival;
double dval;
long long i64val;
};
char name[MaxTokenLength + 1];
// Text string of the token:
char name[MaxTokenLength + 1];
};
class TStringAtomMap {
......@@ -615,6 +621,8 @@ protected:
std::string rootFileName;
std::stack<TShader::Includer::IncludeResult*> includeStack;
std::string currentSourceFile;
std::istringstream strtodStream;
};
} // end namespace glslang
......
......@@ -102,20 +102,36 @@ namespace glslang {
int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
{
bool HasDecimalOrExponent = false;
int isDouble = 0;
const auto saveName = [&](int ch) {
if (len <= MaxTokenLength)
ppToken->name[len++] = static_cast<char>(ch);
};
// Decimal:
// find the range of non-zero digits before the decimal point
int startNonZero = 0;
while (startNonZero < len && ppToken->name[startNonZero] == '0')
++startNonZero;
int endNonZero = len;
while (endNonZero > startNonZero && ppToken->name[endNonZero-1] == '0')
--endNonZero;
int numWholeNumberDigits = endNonZero - startNonZero;
// accumulate the range's value
bool fastPath = numWholeNumberDigits <= 15; // when the number gets too complex, set to false
unsigned long long wholeNumber = 0;
if (fastPath) {
for (int i = startNonZero; i < endNonZero; ++i)
wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
}
int decimalShift = len - endNonZero;
// Decimal point:
bool hasDecimalOrExponent = false;
if (ch == '.') {
HasDecimalOrExponent = true;
hasDecimalOrExponent = true;
saveName(ch);
ch = getChar();
int firstDecimal = len;
// 1.#INF or -1.#INF
if (ch == '#' && (ifdepth > 0 || parseContext.intermediate.getSource() == EShSourceHlsl)) {
......@@ -145,38 +161,97 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
}
}
// Consume leading-zero digits after the decimal point
while (ch == '0') {
saveName(ch);
ch = getChar();
}
int startNonZeroDecimal = len;
int endNonZeroDecimal = len;
// Consume remaining digits, up to the exponent
while (ch >= '0' && ch <= '9') {
saveName(ch);
if (ch != '0')
endNonZeroDecimal = len;
ch = getChar();
}
// Compute accumulation up to the last non-zero digit
if (endNonZeroDecimal > startNonZeroDecimal) {
numWholeNumberDigits += endNonZeroDecimal - endNonZero - 1; // don't include the "."
if (numWholeNumberDigits > 15)
fastPath = false;
if (fastPath) {
for (int i = endNonZero; i < endNonZeroDecimal; ++i) {
if (ppToken->name[i] != '.')
wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
}
}
decimalShift = firstDecimal - endNonZeroDecimal;
}
}
// Exponent:
if (ch == 'e' || ch == 'E') {
HasDecimalOrExponent = true;
saveName(ch);
ch = getChar();
if (ch == '+' || ch == '-') {
bool negativeExponent = false;
double exponentValue = 0.0;
int exponent = 0;
{
if (ch == 'e' || ch == 'E') {
hasDecimalOrExponent = true;
saveName(ch);
ch = getChar();
}
if (ch >= '0' && ch <= '9') {
while (ch >= '0' && ch <= '9') {
if (ch == '+' || ch == '-') {
negativeExponent = ch == '-';
saveName(ch);
ch = getChar();
}
} else {
parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
if (ch >= '0' && ch <= '9') {
while (ch >= '0' && ch <= '9') {
exponent = exponent * 10 + (ch - '0');
saveName(ch);
ch = getChar();
}
} else {
parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
}
}
// Compensate for location of decimal
if (negativeExponent)
exponent -= decimalShift;
else {
exponent += decimalShift;
if (exponent < 0) {
negativeExponent = true;
exponent = -exponent;
}
}
if (exponent > 22)
fastPath = false;
if (fastPath) {
// Compute the floating-point value of the exponent
exponentValue = 1.0;
if (exponent > 0) {
double expFactor = 10;
while (exponent > 0) {
if (exponent & 0x1)
exponentValue *= expFactor;
expFactor *= expFactor;
exponent >>= 1;
}
}
}
}
// Suffix:
bool isDouble = false;
bool isFloat16 = false;
if (ch == 'l' || ch == 'L') {
if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
if (ifdepth == 0 && !HasDecimalOrExponent)
if (ifdepth == 0 && !hasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
if (parseContext.intermediate.getSource() == EShSourceGlsl) {
int ch2 = getChar();
......@@ -186,16 +261,16 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
} else {
saveName(ch);
saveName(ch2);
isDouble = 1;
isDouble = true;
}
} else if (parseContext.intermediate.getSource() == EShSourceHlsl) {
saveName(ch);
isDouble = 1;
isDouble = true;
}
} else if (ch == 'h' || ch == 'H') {
if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
parseContext.float16Check(ppToken->loc, "half floating-point suffix");
if (ifdepth == 0 && !HasDecimalOrExponent)
if (ifdepth == 0 && !hasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
if (parseContext.intermediate.getSource() == EShSourceGlsl) {
int ch2 = getChar();
......@@ -216,13 +291,13 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
if (ifdepth == 0 && !parseContext.relaxedErrors())
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
if (ifdepth == 0 && !HasDecimalOrExponent)
if (ifdepth == 0 && !hasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
saveName(ch);
} else
ungetChar();
// Patch up the name, length, etc.
// Patch up the name and length for overflow
if (len > MaxTokenLength) {
len = MaxTokenLength;
......@@ -230,8 +305,29 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
}
ppToken->name[len] = '\0';
// Get the numerical value
ppToken->dval = strtod(ppToken->name, nullptr);
// Compute the numerical value
if (fastPath) {
// compute the floating-point value of the exponent
if (exponentValue == 0.0)
ppToken->dval = (double)wholeNumber;
else if (negativeExponent)
ppToken->dval = (double)wholeNumber / exponentValue;
else
ppToken->dval = (double)wholeNumber * exponentValue;
} else {
// slow path
strtodStream.clear();
strtodStream.str(ppToken->name);
strtodStream >> ppToken->dval;
// Assume failure combined with a large exponent was overflow, in
// an attempt to set INF. Otherwise, assume underflow, and set 0.0.
if (strtodStream.fail()) {
if (!negativeExponent && exponent + numWholeNumberDigits > 300)
ppToken->i64val = 0x7ff0000000000000; // +Infinity
else
ppToken->dval = 0.0;
}
}
// Return the right token type
if (isDouble)
......
......@@ -97,6 +97,56 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace glslang {
namespace {
// When recording (and playing back) should the backing name string
// be saved (restored)?
bool SaveName(int atom)
{
switch (atom) {
case PpAtomIdentifier:
case PpAtomConstString:
case PpAtomConstInt:
case PpAtomConstUint:
case PpAtomConstInt64:
case PpAtomConstUint64:
#ifdef AMD_EXTENSIONS
case PpAtomConstInt16:
case PpAtomConstUint16:
#endif
case PpAtomConstFloat:
case PpAtomConstDouble:
case PpAtomConstFloat16:
return true;
default:
return false;
}
}
// When recording (and playing back) should the numeric value
// be saved (restored)?
bool SaveValue(int atom)
{
switch (atom) {
case PpAtomConstInt:
case PpAtomConstUint:
case PpAtomConstInt64:
case PpAtomConstUint64:
#ifdef AMD_EXTENSIONS
case PpAtomConstInt16:
case PpAtomConstUint16:
#endif
case PpAtomConstFloat:
case PpAtomConstDouble:
case PpAtomConstFloat16:
return true;
default:
return false;
}
}
}
// push onto back of stream
void TPpContext::TokenStream::putSubtoken(char subtoken)
{
......@@ -121,42 +171,25 @@ void TPpContext::TokenStream::ungetSubtoken()
// Add a complete token (including backing string) to the end of a list
// for later playback.
void TPpContext::TokenStream::putToken(int token, TPpToken* ppToken)
void TPpContext::TokenStream::putToken(int atom, TPpToken* ppToken)
{
const char* s;
char* str = NULL;
// save the atom
assert((atom & ~0xff) == 0);
putSubtoken(static_cast<char>(atom));
assert((token & ~0xff) == 0);
putSubtoken(static_cast<char>(token));
switch (token) {
case PpAtomIdentifier:
case PpAtomConstString:
s = ppToken->name;
// save the backing name string
if (SaveName(atom)) {
const char* s = ppToken->name;
while (*s)
putSubtoken(*s++);
putSubtoken(0);
break;
case PpAtomConstInt:
case PpAtomConstUint:
case PpAtomConstInt64:
case PpAtomConstUint64:
#ifdef AMD_EXTENSIONS
case PpAtomConstInt16:
case PpAtomConstUint16:
#endif
case PpAtomConstFloat:
case PpAtomConstDouble:
case PpAtomConstFloat16:
str = ppToken->name;
while (*str) {
putSubtoken(*str);
str++;
}
putSubtoken(0);
break;
default:
break;
}
// save the numeric value
if (SaveValue(atom)) {
const char* n = reinterpret_cast<const char*>(&ppToken->i64val);
for (int i = 0; i < sizeof(ppToken->i64val); ++i)
putSubtoken(*n++);
}
}
......@@ -164,38 +197,19 @@ void TPpContext::TokenStream::putToken(int token, TPpToken* ppToken)
// (Not the source stream, but a stream used to hold a tokenized macro).
int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken *ppToken)
{
int len;
int ch;
// get the atom
int atom = getSubtoken();
if (atom == EndOfInput)
return atom;
int subtoken = getSubtoken();
// init the token
ppToken->clear();
ppToken->loc = parseContext.getCurrentLoc();
switch (subtoken) {
case '#':
// Check for ##, unless the current # is the last character
if (current < data.size()) {
if (getSubtoken() == '#') {
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
subtoken = PpAtomPaste;
} else
ungetSubtoken();
}
break;
case PpAtomConstString:
case PpAtomIdentifier:
case PpAtomConstFloat:
case PpAtomConstDouble:
case PpAtomConstFloat16:
case PpAtomConstInt:
case PpAtomConstUint:
case PpAtomConstInt64:
case PpAtomConstUint64:
#ifdef AMD_EXTENSIONS
case PpAtomConstInt16:
case PpAtomConstUint16:
#endif
len = 0;
ch = getSubtoken();
// get the backing name string
if (SaveName(atom)) {
int ch = getSubtoken();
int len = 0;
while (ch != 0 && ch != EndOfInput) {
if (len < MaxTokenLength) {
ppToken->name[len] = (char)ch;
......@@ -207,63 +221,28 @@ int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken
}
}
ppToken->name[len] = 0;
}
switch (subtoken) {
case PpAtomIdentifier:
break;
case PpAtomConstString:
break;
case PpAtomConstFloat:
case PpAtomConstDouble:
case PpAtomConstFloat16:
ppToken->dval = atof(ppToken->name);
break;
case PpAtomConstInt:
#ifdef AMD_EXTENSIONS
case PpAtomConstInt16:
#endif
if (len > 0 && ppToken->name[0] == '0') {
if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
ppToken->ival = (int)strtol(ppToken->name, 0, 16);
else
ppToken->ival = (int)strtol(ppToken->name, 0, 8);
} else
ppToken->ival = atoi(ppToken->name);
break;
case PpAtomConstUint:
#ifdef AMD_EXTENSIONS
case PpAtomConstUint16:
#endif
if (len > 0 && ppToken->name[0] == '0') {
if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
ppToken->ival = (int)strtoul(ppToken->name, 0, 16);
else
ppToken->ival = (int)strtoul(ppToken->name, 0, 8);
} else
ppToken->ival = (int)strtoul(ppToken->name, 0, 10);
break;
case PpAtomConstInt64:
if (len > 0 && ppToken->name[0] == '0') {
if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
ppToken->i64val = strtoll(ppToken->name, nullptr, 16);
else
ppToken->i64val = strtoll(ppToken->name, nullptr, 8);
} else
ppToken->i64val = atoll(ppToken->name);
break;
case PpAtomConstUint64:
if (len > 0 && ppToken->name[0] == '0') {
if (len > 1 && (ppToken->name[1] == 'x' || ppToken->name[1] == 'X'))
ppToken->i64val = (long long)strtoull(ppToken->name, nullptr, 16);
else
ppToken->i64val = (long long)strtoull(ppToken->name, nullptr, 8);
// Check for ##, unless the current # is the last character
if (atom == '#') {
if (current < data.size()) {
if (getSubtoken() == '#') {
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
atom = PpAtomPaste;
} else
ppToken->i64val = (long long)strtoull(ppToken->name, 0, 10);
break;
ungetSubtoken();
}
}
return subtoken;
// get the numeric value
if (SaveValue(atom)) {
char* n = reinterpret_cast<char*>(&ppToken->i64val);
for (int i = 0; i < sizeof(ppToken->i64val); ++i)
*n++ = getSubtoken();
}
return atom;
}
// We are pasting if
......
......@@ -208,6 +208,7 @@ INSTANTIATE_TEST_CASE_P(
"prepost.frag",
"runtimeArray.vert",
"simpleFunctionCall.frag",
"stringToDouble.vert",
"structAssignment.frag",
"structDeref.frag",
"structure.frag",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment