blob: c607ecb67e3def9f4f368b154445355b20c3bca7 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011#include <float.h>
alokp@chromium.org1bcc3fd2010-05-19 17:08:44 +000012#include <limits.h>
alokp@chromium.org32cfaf42010-08-23 21:01:13 +000013#include <algorithm>
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000014
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include "compiler/translator/Intermediate.h"
Geoff Lang17732822013-08-29 13:46:49 -040016#include "compiler/translator/SymbolTable.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000017
Jamie Madill45bcc782016-11-07 13:58:48 -050018namespace sh
19{
20
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021////////////////////////////////////////////////////////////////////////////
22//
23// First set of functions are to help build the intermediate representation.
24// These functions are not member functions of the nodes.
25// They are called from parser productions.
26//
27/////////////////////////////////////////////////////////////////////////////
28
29//
30// Add a terminal node for an identifier in an expression.
31//
32// Returns the added node.
33//
Jamie Madilld7b1ab52016-12-12 14:42:19 -050034TIntermSymbol *TIntermediate::addSymbol(int id,
35 const TString &name,
36 const TType &type,
37 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038{
Zhenyao Moe40d1e92014-07-16 17:40:36 -070039 TIntermSymbol *node = new TIntermSymbol(id, name, type);
alokp@chromium.org2cf17712010-03-30 20:33:18 +000040 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000041
alokp@chromium.org2cf17712010-03-30 20:33:18 +000042 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000043}
44
45//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000046// Connect two nodes through an index operator, where the left node is the base
47// of an array or struct, and the right node is a direct or indirect offset.
48//
49// Returns the added node.
50// The caller should set the type of the returned node.
51//
Olli Etuaho3272a6d2016-08-29 17:54:50 +030052TIntermTyped *TIntermediate::addIndex(TOperator op,
53 TIntermTyped *base,
54 TIntermTyped *index,
55 const TSourceLoc &line,
56 TDiagnostics *diagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000057{
Olli Etuaho3272a6d2016-08-29 17:54:50 +030058 TIntermBinary *node = new TIntermBinary(op, base, index);
alokp@chromium.org2cf17712010-03-30 20:33:18 +000059 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000060
Olli Etuaho3272a6d2016-08-29 17:54:50 +030061 TIntermTyped *folded = node->fold(diagnostics);
62 if (folded)
63 {
64 return folded;
65 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000066
alokp@chromium.org2cf17712010-03-30 20:33:18 +000067 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000068}
69
Olli Etuaho7d7f8c42015-05-19 18:38:49 +030070// If the input node is nullptr, return nullptr.
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010071// If the input node is a block node, return it.
72// If the input node is not a block node, put it inside a block node and return that.
73TIntermBlock *TIntermediate::EnsureBlock(TIntermNode *node)
Olli Etuaho7d7f8c42015-05-19 18:38:49 +030074{
75 if (node == nullptr)
76 return nullptr;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010077 TIntermBlock *blockNode = node->getAsBlock();
78 if (blockNode != nullptr)
79 return blockNode;
Olli Etuaho7d7f8c42015-05-19 18:38:49 +030080
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010081 blockNode = new TIntermBlock();
82 blockNode->setLine(node->getLine());
Olli Etuaho81629262017-04-19 11:56:01 +030083 blockNode->appendStatement(node);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010084 return blockNode;
Olli Etuaho7d7f8c42015-05-19 18:38:49 +030085}
86
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000087// For "if" test nodes. There are three children; a condition,
88// a true path, and a false path. The two paths are in the
89// nodePair.
90//
Olli Etuaho57961272016-09-14 13:57:46 +030091// Returns the node created.
92TIntermNode *TIntermediate::addIfElse(TIntermTyped *cond,
93 TIntermNodePair nodePair,
94 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000095{
Olli Etuaho57961272016-09-14 13:57:46 +030096 // For compile time constant conditions, prune the code now.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000097
Olli Etuaho7c3848e2015-11-04 13:19:17 +020098 if (cond->getAsConstantUnion())
Zhenyao Moe40d1e92014-07-16 17:40:36 -070099 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +0000100 if (cond->getAsConstantUnion()->getBConst(0) == true)
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700101 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100102 return EnsureBlock(nodePair.node1);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700103 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000104 else
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700105 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100106 return EnsureBlock(nodePair.node2);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700107 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000108 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000109
Olli Etuaho57961272016-09-14 13:57:46 +0300110 TIntermIfElse *node =
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100111 new TIntermIfElse(cond, EnsureBlock(nodePair.node1), EnsureBlock(nodePair.node2));
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000112 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000113
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000114 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000115}
116
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100117TIntermTyped *TIntermediate::AddComma(TIntermTyped *left,
Olli Etuaho15200042015-11-04 16:56:31 +0200118 TIntermTyped *right,
119 const TSourceLoc &line,
120 int shaderVersion)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000121{
Olli Etuaho15200042015-11-04 16:56:31 +0200122 TIntermTyped *commaNode = nullptr;
123 if (!left->hasSideEffects())
124 {
125 commaNode = right;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700126 }
127 else
128 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100129 commaNode = new TIntermBinary(EOpComma, left, right);
130 commaNode->setLine(line);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000131 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100132 TQualifier resultQualifier = TIntermBinary::GetCommaQualifier(shaderVersion, left, right);
Olli Etuaho15200042015-11-04 16:56:31 +0200133 commaNode->getTypePointer()->setQualifier(resultQualifier);
134 return commaNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135}
136
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137// For "?:" test nodes. There are three children; a condition,
138// a true path, and a false path. The two paths are specified
139// as separate parameters.
140//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300141// Returns the ternary node created, or one of trueExpression and falseExpression if the expression
142// could be folded.
143TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond,
144 TIntermTyped *trueExpression,
145 TIntermTyped *falseExpression,
146 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000147{
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200148 // Note that the node resulting from here can be a constant union without being qualified as
149 // constant.
150 if (cond->getAsConstantUnion())
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700151 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300152 TQualifier resultQualifier =
153 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression);
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +0000154 if (cond->getAsConstantUnion()->getBConst(0))
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200155 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300156 trueExpression->getTypePointer()->setQualifier(resultQualifier);
157 return trueExpression;
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200158 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000159 else
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200160 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300161 falseExpression->getTypePointer()->setQualifier(resultQualifier);
162 return falseExpression;
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200163 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000164 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000165
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300166 // Make a ternary node.
167 TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000168 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000169
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000170 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171}
172
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100173TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init,
174 TIntermBlock *statementList,
175 const TSourceLoc &line)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200176{
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200177 TIntermSwitch *node = new TIntermSwitch(init, statementList);
178 node->setLine(line);
179
180 return node;
Olli Etuahoa3a36662015-02-17 13:46:51 +0200181}
182
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500183TIntermCase *TIntermediate::addCase(TIntermTyped *condition, const TSourceLoc &line)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200184{
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200185 TIntermCase *node = new TIntermCase(condition);
186 node->setLine(line);
187
188 return node;
Olli Etuahoa3a36662015-02-17 13:46:51 +0200189}
190
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000191//
192// Constant terminal nodes. Has a union that contains bool, float or int constants
193//
194// Returns the constant union node created.
195//
196
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200197TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *constantUnion,
198 const TType &type,
199 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200{
Jamie Madillb11e2482015-05-04 14:21:22 -0400201 TIntermConstantUnion *node = new TIntermConstantUnion(constantUnion, type);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000202 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000204 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205}
206
Olli Etuahob6fa0432016-09-28 16:28:05 +0100207TIntermTyped *TIntermediate::AddSwizzle(TIntermTyped *baseExpression,
208 const TVectorFields &fields,
209 const TSourceLoc &dotLocation)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210{
Olli Etuahob6fa0432016-09-28 16:28:05 +0100211 TVector<int> fieldsVector;
212 for (int i = 0; i < fields.num; ++i)
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700213 {
Olli Etuahob6fa0432016-09-28 16:28:05 +0100214 fieldsVector.push_back(fields.offsets[i]);
215 }
216 TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldsVector);
217 node->setLine(dotLocation);
218
219 TIntermTyped *folded = node->fold();
220 if (folded)
221 {
222 return folded;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000223 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000224
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000225 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226}
227
228//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229// Add branches.
230//
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500231TIntermBranch *TIntermediate::addBranch(TOperator branchOp, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000232{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000233 return addBranch(branchOp, 0, line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000234}
235
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500236TIntermBranch *TIntermediate::addBranch(TOperator branchOp,
237 TIntermTyped *expression,
238 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700240 TIntermBranch *node = new TIntermBranch(branchOp, expression);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000241 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000242
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000243 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000244}
245
Olli Etuahof119a262016-08-19 15:54:22 +0300246TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
247 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +0530248{
Olli Etuahob43846e2015-06-02 18:18:57 +0300249 switch (aggregate->getOp())
Arun Patole274f0702015-05-05 13:33:30 +0530250 {
Olli Etuaho1d122782015-11-06 15:35:17 +0200251 case EOpAtan:
252 case EOpPow:
253 case EOpMod:
254 case EOpMin:
255 case EOpMax:
256 case EOpClamp:
257 case EOpMix:
258 case EOpStep:
259 case EOpSmoothStep:
Olli Etuaho74da73f2017-02-01 15:37:48 +0000260 case EOpLdexp:
Olli Etuahoe1805592017-01-02 16:41:20 +0000261 case EOpMulMatrixComponentWise:
Olli Etuaho1d122782015-11-06 15:35:17 +0200262 case EOpOuterProduct:
Olli Etuahoe1805592017-01-02 16:41:20 +0000263 case EOpEqualComponentWise:
264 case EOpNotEqualComponentWise:
265 case EOpLessThanComponentWise:
266 case EOpLessThanEqualComponentWise:
267 case EOpGreaterThanComponentWise:
268 case EOpGreaterThanEqualComponentWise:
Olli Etuaho1d122782015-11-06 15:35:17 +0200269 case EOpDistance:
270 case EOpDot:
271 case EOpCross:
Jamie Madille72595b2017-06-06 15:12:26 -0400272 case EOpFaceforward:
Olli Etuaho1d122782015-11-06 15:35:17 +0200273 case EOpReflect:
274 case EOpRefract:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000275 case EOpBitfieldExtract:
276 case EOpBitfieldInsert:
Olli Etuahof119a262016-08-19 15:54:22 +0300277 return aggregate->fold(diagnostics);
Olli Etuaho1d122782015-11-06 15:35:17 +0200278 default:
279 // TODO: Add support for folding array constructors
280 if (aggregate->isConstructor() && !aggregate->isArray())
281 {
Olli Etuahof119a262016-08-19 15:54:22 +0300282 return aggregate->fold(diagnostics);
Olli Etuaho1d122782015-11-06 15:35:17 +0200283 }
284 // Constant folding not supported for the built-in.
285 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +0530286 }
Arun Patole274f0702015-05-05 13:33:30 +0530287}
Jamie Madill45bcc782016-11-07 13:58:48 -0500288
289} // namespace sh