blob: 9e3e455ae9dc376179bec11434fba8203045afec [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//
Zhenyao Moe40d1e92014-07-16 17:40:36 -070034TIntermSymbol *TIntermediate::addSymbol(
35 int id, const TString &name, const TType &type, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036{
Zhenyao Moe40d1e92014-07-16 17:40:36 -070037 TIntermSymbol *node = new TIntermSymbol(id, name, type);
alokp@chromium.org2cf17712010-03-30 20:33:18 +000038 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000039
alokp@chromium.org2cf17712010-03-30 20:33:18 +000040 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000041}
42
43//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000044// Connect two nodes through an index operator, where the left node is the base
45// of an array or struct, and the right node is a direct or indirect offset.
46//
47// Returns the added node.
48// The caller should set the type of the returned node.
49//
Olli Etuaho3272a6d2016-08-29 17:54:50 +030050TIntermTyped *TIntermediate::addIndex(TOperator op,
51 TIntermTyped *base,
52 TIntermTyped *index,
53 const TSourceLoc &line,
54 TDiagnostics *diagnostics)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000055{
Olli Etuaho3272a6d2016-08-29 17:54:50 +030056 TIntermBinary *node = new TIntermBinary(op, base, index);
alokp@chromium.org2cf17712010-03-30 20:33:18 +000057 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000058
Olli Etuaho3272a6d2016-08-29 17:54:50 +030059 TIntermTyped *folded = node->fold(diagnostics);
60 if (folded)
61 {
62 return folded;
63 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000064
alokp@chromium.org2cf17712010-03-30 20:33:18 +000065 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000066}
67
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000068// This is the safe way to change the operator on an aggregate, as it
69// does lots of error checking and fixing. Especially for establishing
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010070// a function call's operation on it's set of parameters.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000071//
72// Returns an aggregate node, which could be the one passed in if
daniel@transgaming.com978702d2012-04-04 15:05:58 +000073// it was already an aggregate but no operator was set.
Zhenyao Moe40d1e92014-07-16 17:40:36 -070074TIntermAggregate *TIntermediate::setAggregateOperator(
75 TIntermNode *node, TOperator op, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000076{
Zhenyao Moe40d1e92014-07-16 17:40:36 -070077 TIntermAggregate *aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000078
alokp@chromium.org2cf17712010-03-30 20:33:18 +000079 //
80 // Make sure we have an aggregate. If not turn it into one.
81 //
Zhenyao Moe40d1e92014-07-16 17:40:36 -070082 if (node)
83 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +000084 aggNode = node->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -070085 if (aggNode == NULL || aggNode->getOp() != EOpNull)
86 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +000087 //
88 // Make an aggregate containing this node.
89 //
90 aggNode = new TIntermAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -070091 aggNode->getSequence()->push_back(node);
alokp@chromium.org2cf17712010-03-30 20:33:18 +000092 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -070093 }
94 else
95 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +000096 aggNode = new TIntermAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -070097 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000098
alokp@chromium.org2cf17712010-03-30 20:33:18 +000099 //
100 // Set the operator.
101 //
alokp@chromium.org58e54292010-08-24 21:40:03 +0000102 aggNode->setOp(op);
Jamie Madill075edd82013-07-08 13:30:19 -0400103 aggNode->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000105 return aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000106}
107
108//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000109// Safe way to combine two nodes into an aggregate. Works with null pointers,
110// a node that's not a aggregate yet, etc.
111//
112// Returns the resulting aggregate, unless 0 was passed in for
113// both existing nodes.
114//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700115TIntermAggregate *TIntermediate::growAggregate(
116 TIntermNode *left, TIntermNode *right, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000117{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700118 if (left == NULL && right == NULL)
119 return NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700121 TIntermAggregate *aggNode = NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000122 if (left)
123 aggNode = left->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700124 if (!aggNode || aggNode->getOp() != EOpNull)
125 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000126 aggNode = new TIntermAggregate;
127 if (left)
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700128 aggNode->getSequence()->push_back(left);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000129 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000131 if (right)
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700132 aggNode->getSequence()->push_back(right);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000133
Jamie Madill075edd82013-07-08 13:30:19 -0400134 aggNode->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000136 return aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137}
138
139//
140// Turn an existing node into an aggregate.
141//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700142// Returns an aggregate, unless NULL was passed in for the existing node.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143//
Olli Etuaho32db19b2016-10-04 14:43:16 +0100144TIntermAggregate *TIntermediate::MakeAggregate(TIntermNode *node, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145{
Olli Etuaho32db19b2016-10-04 14:43:16 +0100146 if (node == nullptr)
147 return nullptr;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700149 TIntermAggregate *aggNode = new TIntermAggregate;
150 aggNode->getSequence()->push_back(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151
Jamie Madill075edd82013-07-08 13:30:19 -0400152 aggNode->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000153
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000154 return aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000155}
156
Olli Etuaho7d7f8c42015-05-19 18:38:49 +0300157// If the input node is nullptr, return nullptr.
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100158// If the input node is a block node, return it.
159// If the input node is not a block node, put it inside a block node and return that.
160TIntermBlock *TIntermediate::EnsureBlock(TIntermNode *node)
Olli Etuaho7d7f8c42015-05-19 18:38:49 +0300161{
162 if (node == nullptr)
163 return nullptr;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100164 TIntermBlock *blockNode = node->getAsBlock();
165 if (blockNode != nullptr)
166 return blockNode;
Olli Etuaho7d7f8c42015-05-19 18:38:49 +0300167
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100168 blockNode = new TIntermBlock();
169 blockNode->setLine(node->getLine());
170 blockNode->getSequence()->push_back(node);
171 return blockNode;
Olli Etuaho7d7f8c42015-05-19 18:38:49 +0300172}
173
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174// For "if" test nodes. There are three children; a condition,
175// a true path, and a false path. The two paths are in the
176// nodePair.
177//
Olli Etuaho57961272016-09-14 13:57:46 +0300178// Returns the node created.
179TIntermNode *TIntermediate::addIfElse(TIntermTyped *cond,
180 TIntermNodePair nodePair,
181 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182{
Olli Etuaho57961272016-09-14 13:57:46 +0300183 // For compile time constant conditions, prune the code now.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200185 if (cond->getAsConstantUnion())
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700186 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +0000187 if (cond->getAsConstantUnion()->getBConst(0) == true)
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700188 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100189 return EnsureBlock(nodePair.node1);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700190 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000191 else
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700192 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100193 return EnsureBlock(nodePair.node2);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700194 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000195 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196
Olli Etuaho57961272016-09-14 13:57:46 +0300197 TIntermIfElse *node =
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100198 new TIntermIfElse(cond, EnsureBlock(nodePair.node1), EnsureBlock(nodePair.node2));
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000199 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000201 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202}
203
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100204TIntermTyped *TIntermediate::AddComma(TIntermTyped *left,
Olli Etuaho15200042015-11-04 16:56:31 +0200205 TIntermTyped *right,
206 const TSourceLoc &line,
207 int shaderVersion)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000208{
Olli Etuaho15200042015-11-04 16:56:31 +0200209 TIntermTyped *commaNode = nullptr;
210 if (!left->hasSideEffects())
211 {
212 commaNode = right;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700213 }
214 else
215 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100216 commaNode = new TIntermBinary(EOpComma, left, right);
217 commaNode->setLine(line);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000218 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100219 TQualifier resultQualifier = TIntermBinary::GetCommaQualifier(shaderVersion, left, right);
Olli Etuaho15200042015-11-04 16:56:31 +0200220 commaNode->getTypePointer()->setQualifier(resultQualifier);
221 return commaNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000222}
223
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000224// For "?:" test nodes. There are three children; a condition,
225// a true path, and a false path. The two paths are specified
226// as separate parameters.
227//
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300228// Returns the ternary node created, or one of trueExpression and falseExpression if the expression
229// could be folded.
230TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond,
231 TIntermTyped *trueExpression,
232 TIntermTyped *falseExpression,
233 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000234{
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200235 // Note that the node resulting from here can be a constant union without being qualified as
236 // constant.
237 if (cond->getAsConstantUnion())
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700238 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300239 TQualifier resultQualifier =
240 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression);
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +0000241 if (cond->getAsConstantUnion()->getBConst(0))
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200242 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300243 trueExpression->getTypePointer()->setQualifier(resultQualifier);
244 return trueExpression;
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200245 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000246 else
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200247 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300248 falseExpression->getTypePointer()->setQualifier(resultQualifier);
249 return falseExpression;
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200250 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000251 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300253 // Make a ternary node.
254 TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000255 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000257 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000258}
259
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100260TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init,
261 TIntermBlock *statementList,
262 const TSourceLoc &line)
Olli Etuahoa3a36662015-02-17 13:46:51 +0200263{
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200264 TIntermSwitch *node = new TIntermSwitch(init, statementList);
265 node->setLine(line);
266
267 return node;
Olli Etuahoa3a36662015-02-17 13:46:51 +0200268}
269
270TIntermCase *TIntermediate::addCase(
271 TIntermTyped *condition, const TSourceLoc &line)
272{
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200273 TIntermCase *node = new TIntermCase(condition);
274 node->setLine(line);
275
276 return node;
Olli Etuahoa3a36662015-02-17 13:46:51 +0200277}
278
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279//
280// Constant terminal nodes. Has a union that contains bool, float or int constants
281//
282// Returns the constant union node created.
283//
284
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200285TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *constantUnion,
286 const TType &type,
287 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288{
Jamie Madillb11e2482015-05-04 14:21:22 -0400289 TIntermConstantUnion *node = new TIntermConstantUnion(constantUnion, type);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000290 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000291
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000292 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293}
294
Olli Etuahob6fa0432016-09-28 16:28:05 +0100295TIntermTyped *TIntermediate::AddSwizzle(TIntermTyped *baseExpression,
296 const TVectorFields &fields,
297 const TSourceLoc &dotLocation)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298{
Olli Etuahob6fa0432016-09-28 16:28:05 +0100299 TVector<int> fieldsVector;
300 for (int i = 0; i < fields.num; ++i)
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700301 {
Olli Etuahob6fa0432016-09-28 16:28:05 +0100302 fieldsVector.push_back(fields.offsets[i]);
303 }
304 TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldsVector);
305 node->setLine(dotLocation);
306
307 TIntermTyped *folded = node->fold();
308 if (folded)
309 {
310 return folded;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000311 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000312
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000313 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000314}
315
316//
317// Create loop nodes.
318//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700319TIntermNode *TIntermediate::addLoop(
320 TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
321 TIntermNode *body, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000322{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100323 TIntermNode *node = new TIntermLoop(type, init, cond, expr, EnsureBlock(body));
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000324 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000326 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000327}
328
329//
330// Add branches.
331//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700332TIntermBranch* TIntermediate::addBranch(
333 TOperator branchOp, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000334{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000335 return addBranch(branchOp, 0, line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336}
337
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700338TIntermBranch* TIntermediate::addBranch(
339 TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000340{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700341 TIntermBranch *node = new TIntermBranch(branchOp, expression);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000342 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000343
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000344 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345}
346
Olli Etuahof119a262016-08-19 15:54:22 +0300347TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
348 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +0530349{
Olli Etuahob43846e2015-06-02 18:18:57 +0300350 switch (aggregate->getOp())
Arun Patole274f0702015-05-05 13:33:30 +0530351 {
Olli Etuaho1d122782015-11-06 15:35:17 +0200352 case EOpAtan:
353 case EOpPow:
354 case EOpMod:
355 case EOpMin:
356 case EOpMax:
357 case EOpClamp:
358 case EOpMix:
359 case EOpStep:
360 case EOpSmoothStep:
361 case EOpMul:
362 case EOpOuterProduct:
363 case EOpLessThan:
364 case EOpLessThanEqual:
365 case EOpGreaterThan:
366 case EOpGreaterThanEqual:
367 case EOpVectorEqual:
368 case EOpVectorNotEqual:
369 case EOpDistance:
370 case EOpDot:
371 case EOpCross:
372 case EOpFaceForward:
373 case EOpReflect:
374 case EOpRefract:
Olli Etuahof119a262016-08-19 15:54:22 +0300375 return aggregate->fold(diagnostics);
Olli Etuaho1d122782015-11-06 15:35:17 +0200376 default:
377 // TODO: Add support for folding array constructors
378 if (aggregate->isConstructor() && !aggregate->isArray())
379 {
Olli Etuahof119a262016-08-19 15:54:22 +0300380 return aggregate->fold(diagnostics);
Olli Etuaho1d122782015-11-06 15:35:17 +0200381 }
382 // Constant folding not supported for the built-in.
383 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +0530384 }
Arun Patole274f0702015-05-05 13:33:30 +0530385}
Jamie Madill45bcc782016-11-07 13:58:48 -0500386
387} // namespace sh