source: icGREP/icgrep-devel/icgrep/pablo/builder.cpp @ 5267

Last change on this file since 5267 was 5267, checked in by nmedfort, 2 years ago

Code clean-up. Removed Pablo Call, SetIthBit? and Prototype.

File size: 19.6 KB
Line 
1#include "builder.hpp"
2#include <pablo/boolean.h>
3#include <pablo/arithmetic.h>
4#include <pablo/branch.h>
5#include <pablo/pe_advance.h>
6#include <pablo/pe_lookahead.h>
7#include <pablo/pe_matchstar.h>
8#include <pablo/pe_scanthru.h>
9#include <pablo/pe_infile.h>
10#include <pablo/pe_count.h>
11#include <pablo/pe_integer.h>
12#include <pablo/pe_string.h>
13#include <pablo/pe_zeroes.h>
14#include <pablo/pe_ones.h>
15#include <pablo/pe_var.h>
16#include <pablo/ps_assign.h>
17
18using namespace llvm;
19
20namespace pablo {
21
22#define MAKE_UNARY(NAME, TYPE, ARGS...) \
23struct __##NAME { \
24    inline PabloAST * operator()(PabloAST * arg) { \
25        return mPb->NAME(arg); \
26    } \
27    inline __##NAME(PabloBlock * pb) : mPb(pb) {} \
28private: \
29    PabloBlock * mPb; \
30}; \
31__##NAME functor(mPb); \
32PabloAST * result = mExprTable.findUnaryOrCall(std::move(functor), TYPE, ARGS)
33
34#define MAKE_NAMED_UNARY(NAME, TYPE, PREFIX, ARGS...) \
35struct __##NAME { \
36    inline PabloAST * operator()(PabloAST * arg) { \
37        return mPb->NAME(arg, mPrefix); \
38    } \
39    inline __##NAME(PabloBlock * pb, const std::string & prefix) : mPb(pb), mPrefix(prefix) {} \
40private: \
41    PabloBlock * mPb; \
42    const std::string & mPrefix; \
43}; \
44__##NAME functor(mPb, prefix); \
45PabloAST * result = mExprTable.findUnaryOrCall(std::move(functor), TYPE, ARGS)
46
47#define MAKE_BINARY(NAME, TYPE, ARGS...) \
48struct __##NAME { \
49    inline PabloAST * operator()(PabloAST * arg1, PabloAST * arg2) { \
50        return mPb->NAME(arg1, arg2); \
51    } \
52    inline __##NAME(PabloBlock * pb) : mPb(pb) {} \
53private: \
54    PabloBlock * mPb; \
55}; \
56__##NAME functor(mPb); \
57PabloAST * result = mExprTable.findBinaryOrCall(std::move(functor), TYPE, ARGS)
58
59#define MAKE_NAMED_BINARY(NAME, TYPE, PREFIX, ARGS...) \
60struct __##NAME { \
61    inline PabloAST * operator()(PabloAST * arg1, PabloAST * arg2) { \
62        return mPb->NAME(arg1, arg2, mPrefix); \
63    } \
64    inline __##NAME(PabloBlock * pb, const std::string & prefix) : mPb(pb), mPrefix(prefix) {} \
65private: \
66    PabloBlock * mPb; \
67    const std::string & mPrefix; \
68}; \
69__##NAME functor(mPb, PREFIX); \
70PabloAST * result = mExprTable.findBinaryOrCall(std::move(functor), TYPE, ARGS)
71
72#define MAKE_TERNARY(NAME, TYPE, ARGS...) \
73struct __##NAME { \
74    inline PabloAST * operator()(PabloAST * arg1, PabloAST * arg2, PabloAST * arg3) { \
75        return mPb->NAME(arg1, arg2, arg3); \
76    } \
77    inline __##NAME(PabloBlock * pb) : mPb(pb) {} \
78private: \
79    PabloBlock * mPb; \
80}; \
81__##NAME functor(mPb); \
82PabloAST * result = mExprTable.findTernaryOrCall(std::move(functor), TYPE, ARGS)
83
84#define MAKE_NAMED_TERNARY(NAME, TYPE, PREFIX, ARGS...) \
85struct __##NAME { \
86    inline PabloAST * operator()(PabloAST * arg1, PabloAST * arg2, PabloAST * arg3) { \
87        return mPb->NAME(arg1, arg2, arg3, mPrefix); \
88    } \
89    inline __##NAME(PabloBlock * pb, const std::string & prefix) : mPb(pb), mPrefix(prefix) {} \
90private: \
91    PabloBlock * mPb; \
92    const std::string & mPrefix; \
93}; \
94__##NAME functor(mPb, PREFIX); \
95PabloAST * result = mExprTable.findTernaryOrCall(std::move(functor), TYPE, ARGS)
96
97#define MAKE_VARIABLE(NAME, TYPE, ARGS...) \
98struct __##NAME { \
99    inline PabloAST * operator()(const std::vector<PabloAST *> & args, PabloAST * prototype) { \
100        return mPb->NAME(prototype, args); \
101    } \
102    inline __##NAME(PabloBlock * pb) : mPb(pb) {} \
103private: \
104    PabloBlock * mPb; \
105}; \
106__##NAME functor(mPb); \
107PabloAST * result = mExprTable.findVariadicOrCall(std::move(functor), TYPE, ARGS)
108
109template<typename Type>
110static inline Type * isBinary(PabloAST * expr) {
111    if (isa<Type>(expr) && cast<Type>(expr)->getNumOperands() == 2) {
112        return cast<Type>(expr);
113    }
114    return nullptr;
115}
116
117using TypeId = PabloAST::ClassTypeId;
118
119PabloAST * PabloBuilder::createAdvance(PabloAST * expr, PabloAST * shiftAmount) {
120    if (isa<Zeroes>(expr) || cast<Integer>(shiftAmount)->value() == 0) {
121        return expr;
122    }
123    MAKE_BINARY(createAdvance, TypeId::Advance, expr, shiftAmount);
124    return result;
125}
126
127PabloAST * PabloBuilder::createAdvance(PabloAST * expr, PabloAST * shiftAmount, const std::string & prefix) {
128    if (isa<Zeroes>(expr) || cast<Integer>(shiftAmount)->value() == 0) {
129        return expr;
130    }
131    MAKE_NAMED_BINARY(createAdvance, TypeId::Advance, prefix, expr, shiftAmount);
132    return result;
133}
134
135Extract * PabloBuilder::createExtract(PabloAST * value, not_null<PabloAST *> index) {
136    MAKE_BINARY(createExtract, TypeId::Extract, value, index);
137    return cast<Extract>(result);
138}
139
140Extract * PabloBuilder::createExtract(PabloAST * value, not_null<PabloAST *> index, const std::string & prefix) {
141    MAKE_NAMED_BINARY(createExtract, TypeId::Extract, prefix, value, index);
142    return cast<Extract>(result);
143}
144
145PabloAST * PabloBuilder::createLookahead(PabloAST * expr, PabloAST * shiftAmount) {
146    if (isa<Zeroes>(expr) || cast<Integer>(shiftAmount)->value() == 0) {
147        return expr;
148    }
149    MAKE_BINARY(createLookahead, TypeId::Lookahead, expr, shiftAmount);
150    return result;
151}
152
153PabloAST * PabloBuilder::createLookahead(PabloAST * expr, PabloAST * shiftAmount, const std::string & prefix) {
154    if (isa<Zeroes>(expr) || cast<Integer>(shiftAmount)->value() == 0) {
155        return expr;
156    }
157    MAKE_NAMED_BINARY(createLookahead, TypeId::Lookahead, prefix, expr, shiftAmount);
158    return result;
159}
160
161PabloAST * PabloBuilder::createNot(PabloAST * expr) {
162    if (isa<Ones>(expr)) {
163        return createZeroes(expr->getType());
164    }
165    else if (isa<Zeroes>(expr)){
166        return createOnes(expr->getType());
167    }
168    else if (Not * not1 = dyn_cast<Not>(expr)) {
169        return not1->getOperand(0);
170    }
171    MAKE_UNARY(createNot, TypeId::Not, expr);
172    return result;
173}
174
175PabloAST * PabloBuilder::createNot(PabloAST * expr, const std::string & prefix) {
176    if (isa<Ones>(expr)) {
177        return createZeroes(expr->getType());
178    }
179    else if (isa<Zeroes>(expr)){
180        return createOnes(expr->getType());
181    }
182    else if (Not * not1 = dyn_cast<Not>(expr)) {
183        return not1->getOperand(0);
184    }
185    MAKE_NAMED_UNARY(createNot, TypeId::Not, prefix, expr);
186    return result;
187}
188
189PabloAST * PabloBuilder::createCount(PabloAST * expr) {
190    MAKE_UNARY(createCount, TypeId::Count, expr);
191    return result;
192}
193
194PabloAST * PabloBuilder::createCount(PabloAST * expr, const std::string & prefix) {
195    MAKE_NAMED_UNARY(createCount, TypeId::Count, prefix, expr);
196    return result;
197}
198
199PabloAST * PabloBuilder::createAssign(PabloAST * const variable, PabloAST * const value) {
200    return mPb->createAssign(variable, value);
201}
202
203PabloAST * PabloBuilder::createAnd(PabloAST * expr1, PabloAST * expr2) {
204    if (isa<Zeroes>(expr2) || isa<Ones>(expr1)) {
205        return expr2;
206    } else if (isa<Zeroes>(expr1) || isa<Ones>(expr2) || equals(expr1, expr2)){
207        return expr1;
208    } else if (Not * not1 = dyn_cast<Not>(expr1)) {
209        if (Not * not2 = dyn_cast<Not>(expr2)) {
210            return createNot(createOr(not1->getOperand(0), not2->getOperand(0)));
211        } else if (equals(not1->getOperand(0), expr2)) {
212            return createZeroes(expr1->getType());
213        }
214    } else if (Not * not2 = dyn_cast<Not>(expr2)) {
215        if (equals(expr1, not2->getOperand(0))) {
216            return createZeroes(expr1->getType());
217        }
218    } else if (Or * or1 = isBinary<Or>(expr1)) {
219        if (equals(or1->getOperand(0), expr2) || equals(or1->getOperand(1), expr2)) {
220            return expr2;
221        }
222    } else if (Or * or2 = isBinary<Or>(expr2)) {
223        if (equals(or2->getOperand(0), expr1) || equals(or2->getOperand(1), expr1)) {
224            return expr1;
225        }
226    }
227    if (expr1 > expr2) {
228        std::swap(expr1, expr2);
229    }
230    MAKE_BINARY(createAnd, TypeId::And, expr1, expr2);
231    return result;
232}
233
234PabloAST * PabloBuilder::createAnd(PabloAST * expr1, PabloAST * expr2, const std::string & prefix) {
235    if (isa<Zeroes>(expr2) || isa<Ones>(expr1)) {
236        return expr2;
237    } else if (isa<Zeroes>(expr1) || isa<Ones>(expr2) || equals(expr1, expr2)){
238        return expr1;
239    } else if (Not * not1 = dyn_cast<Not>(expr1)) {
240        if (Not * not2 = dyn_cast<Not>(expr2)) {
241            return createNot(createOr(not1->getOperand(0), not2->getOperand(0)), prefix);
242        } else if (equals(not1->getOperand(0), expr2)) {
243            return createZeroes(expr1->getType());
244        }
245    } else if (Not * not2 = dyn_cast<Not>(expr2)) {
246        if (equals(expr1, not2->getOperand(0))) {
247            return createZeroes(expr1->getType());
248        }
249    } else if (Or * or1 = isBinary<Or>(expr1)) {
250        if (equals(or1->getOperand(0), expr2) || equals(or1->getOperand(1), expr2)) {
251            return expr2;
252        }
253    } else if (Or * or2 = isBinary<Or>(expr2)) {
254        if (equals(or2->getOperand(0), expr1) || equals(or2->getOperand(1), expr1)) {
255            return expr1;
256        }
257    }
258    if (expr1 > expr2) {
259        std::swap(expr1, expr2);
260    }
261    MAKE_NAMED_BINARY(createAnd, TypeId::And, prefix, expr1, expr2);
262    return result;
263}
264
265PabloAST * PabloBuilder::createOr(PabloAST * expr1, PabloAST * expr2) {
266    if (isa<Zeroes>(expr1) || isa<Ones>(expr2)){
267        return expr2;
268    }
269    if (isa<Zeroes>(expr2) || isa<Ones>(expr1) || equals(expr1, expr2)) {
270        return expr1;
271    } else if (Not * not1 = dyn_cast<Not>(expr1)) {
272        // ¬a√b = ¬¬(¬a √ b) = ¬(a ∧ ¬b)
273        return createNot(createAnd(not1->getOperand(0), createNot(expr2)));
274    } else if (Not * not2 = dyn_cast<Not>(expr2)) {
275        // a√¬b = ¬¬(¬b √ a) = ¬(b ∧ ¬a)
276        return createNot(createAnd(not2->getOperand(0), createNot(expr1)));
277    } else if (equals(expr1, expr2)) {
278        return expr1;
279    } else if (And * and1 = isBinary<And>(expr1)) {
280        PabloAST * const expr1a = and1->getOperand(0);
281        PabloAST * const expr1b = and1->getOperand(1);
282        if (And * and2 = isBinary<And>(expr2)) {
283            PabloAST * const expr2a = and2->getOperand(0);
284            PabloAST * const expr2b = and2->getOperand(1);
285            //These optimizations factor out common components that can occur when sets are formed by union
286            //(e.g., union of [a-z] and [A-Z].
287            if (equals(expr1a, expr2a)) {
288                return createAnd(expr1a, createOr(expr1b, expr2b));
289            } else if (equals(expr1b, expr2b)) {
290                return createAnd(expr1b, createOr(expr1a, expr2a));
291            } else if (equals(expr1a, expr2b)) {
292                return createAnd(expr1a, createOr(expr1b, expr2a));
293            } else if (equals(expr1b, expr2a)) {
294                return createAnd(expr1b, createOr(expr1a, expr2b));
295            }
296        } else if (equals(expr1a, expr2) || equals(expr1b, expr2)) {
297            // (a ∧ b) √ a = a
298            return expr2;
299        }
300    } else if (And * and2 = isBinary<And>(expr2)) {
301        if (equals(and2->getOperand(0), expr1) || equals(and2->getOperand(1), expr1)) {
302            return expr1;
303        }
304    }
305    if (expr1 > expr2) {
306        std::swap(expr1, expr2);
307    }
308    MAKE_BINARY(createOr, TypeId::Or, expr1, expr2);
309    return result;
310}
311
312PabloAST * PabloBuilder::createOr(PabloAST * expr1, PabloAST * expr2, const std::string & prefix) {
313    if (isa<Zeroes>(expr1) || isa<Ones>(expr2)){
314        return expr2;
315    }
316    if (isa<Zeroes>(expr2) || isa<Ones>(expr1) || equals(expr1, expr2)) {
317        return expr1;
318    } else if (Not * not1 = dyn_cast<Not>(expr1)) {
319        // ¬a√b = ¬¬(¬a √ b) = ¬(a ∧ ¬b)
320        return createNot(createAnd(not1->getOperand(0), createNot(expr2)), prefix);
321    } else if (Not * not2 = dyn_cast<Not>(expr2)) {
322        // a√¬b = ¬¬(¬b √ a) = ¬(b ∧ ¬a)
323        return createNot(createAnd(not2->getOperand(0), createNot(expr1)), prefix);
324    } else if (equals(expr1, expr2)) {
325        return expr1;
326    } else if (And * and1 = isBinary<And>(expr1)) {
327        PabloAST * const expr1a = and1->getOperand(0);
328        PabloAST * const expr1b = and1->getOperand(1);
329        if (And * and2 = isBinary<And>(expr2)) {
330            PabloAST * const expr2a = and2->getOperand(0);
331            PabloAST * const expr2b = and2->getOperand(1);
332            //These optimizations factor out common components that can occur when sets are formed by union
333            //(e.g., union of [a-z] and [A-Z].
334            if (equals(expr1a, expr2a)) {
335                return createAnd(expr1a, createOr(expr1b, expr2b), prefix);
336            } else if (equals(expr1b, expr2b)) {
337                return createAnd(expr1b, createOr(expr1a, expr2a), prefix);
338            } else if (equals(expr1a, expr2b)) {
339                return createAnd(expr1a, createOr(expr1b, expr2a), prefix);
340            } else if (equals(expr1b, expr2a)) {
341                return createAnd(expr1b, createOr(expr1a, expr2b), prefix);
342            }
343        } else if (equals(expr1a, expr2) || equals(expr1b, expr2)) {
344            // (a ∧ b) √ a = a
345            return expr2;
346        }
347    } else if (And * and2 = isBinary<And>(expr2)) {
348        if (equals(and2->getOperand(0), expr1) || equals(and2->getOperand(1), expr1)) {
349            return expr1;
350        }
351    }
352    if (expr1 > expr2) {
353        std::swap(expr1, expr2);
354    }
355    MAKE_NAMED_BINARY(createOr, TypeId::Or, prefix, expr1, expr2);
356    return result;
357}
358
359PabloAST * PabloBuilder::createXor(PabloAST * expr1, PabloAST * expr2) {
360    if (expr1 == expr2) {
361        return createZeroes(expr1->getType());
362    } else if (isa<Ones>(expr1)) {
363        return createNot(expr2);
364    } else if (isa<Zeroes>(expr1)){
365        return expr2;
366    } else if (isa<Ones>(expr2)) {
367        return createNot(expr1);
368    } else if (isa<Zeroes>(expr2)){
369        return expr1;
370    } else if (Not * not1 = dyn_cast<Not>(expr1)) {
371        if (Not * not2 = dyn_cast<Not>(expr2)) {
372            return createXor(not1->getOperand(0), not2->getOperand(0));
373        }
374    }
375    if (expr1 > expr2) {
376        std::swap(expr1, expr2);
377    }
378    MAKE_BINARY(createXor, TypeId::Xor, expr1, expr2);
379    return result;
380}
381
382PabloAST * PabloBuilder::createXor(PabloAST * expr1, PabloAST * expr2, const std::string & prefix) {
383    if (expr1 == expr2) {
384        return createZeroes(expr1->getType());
385    } else if (isa<Ones>(expr1)) {
386        return createNot(expr2);
387    } else if (isa<Zeroes>(expr1)){
388        return expr2;
389    } else if (isa<Ones>(expr2)) {
390        return createNot(expr1);
391    } else if (isa<Zeroes>(expr2)){
392        return expr1;
393    } else if (Not * not1 = dyn_cast<Not>(expr1)) {
394        if (Not * not2 = dyn_cast<Not>(expr2)) {
395            return createXor(not1->getOperand(0), not2->getOperand(0), prefix);
396        }
397    }
398    if (expr1 > expr2) {
399        std::swap(expr1, expr2);
400    }
401    MAKE_NAMED_BINARY(createXor, TypeId::Xor, prefix, expr1, expr2);
402    return result;
403}
404
405PabloAST * PabloBuilder::createAdd(PabloAST * expr1, PabloAST * expr2) {
406    if (isa<Integer>(expr1) && isa<Integer>(expr2)) {
407        return getInteger(cast<Integer>(expr1)->value() + cast<Integer>(expr2)->value());
408    } else if (isa<Integer>(expr1)) {
409        if (cast<Integer>(expr1)->value() == 0) {
410            return expr2;
411        }
412    } else if (isa<Integer>(expr2)) {
413        if (cast<Integer>(expr2)->value() == 0) {
414            return expr1;
415        }
416    }
417    MAKE_BINARY(createAdd, TypeId::Add, expr1, expr2);
418    return result;
419}
420
421PabloAST * PabloBuilder::createSubtract(PabloAST * expr1, PabloAST * expr2) {
422    if (isa<Integer>(expr1) && isa<Integer>(expr2)) {
423        return getInteger(cast<Integer>(expr1)->value() - cast<Integer>(expr2)->value());
424    } else if (isa<Integer>(expr1)) {
425        if (cast<Integer>(expr1)->value() == 0) {
426            return expr2;
427        }
428    } else if (isa<Integer>(expr2)) {
429        if (cast<Integer>(expr2)->value() == 0) {
430            return expr1;
431        }
432    }
433    MAKE_BINARY(createSubtract, TypeId::Subtract, expr1, expr2);
434    return result;
435}
436
437PabloAST * PabloBuilder::createLessThan(PabloAST * expr1, PabloAST * expr2) {
438    if (isa<Integer>(expr1) && isa<Integer>(expr2)) {
439        return getInteger(cast<Integer>(expr1)->value() < cast<Integer>(expr2)->value() ? 1 : 0);
440    }
441    MAKE_BINARY(createLessThan, TypeId::LessThan, expr1, expr2);
442    return result;
443}
444
445PabloAST * PabloBuilder::createInFile(PabloAST * expr) {
446    MAKE_UNARY(createInFile, TypeId::InFile, expr);
447    return result;
448}
449
450PabloAST * PabloBuilder::createInFile(PabloAST * expr, const std::string & prefix) {
451    MAKE_NAMED_UNARY(createInFile, TypeId::InFile, prefix, expr);
452    return result;
453}
454
455PabloAST * PabloBuilder::createAtEOF(PabloAST * expr) {
456    MAKE_UNARY(createAtEOF, TypeId::AtEOF, expr);
457    return result;
458}
459
460PabloAST * PabloBuilder::createAtEOF(PabloAST * expr, const std::string & prefix) {
461    MAKE_NAMED_UNARY(createAtEOF, TypeId::AtEOF, prefix, expr);
462    return result;
463}
464
465PabloAST * PabloBuilder::createMatchStar(PabloAST * marker, PabloAST * charclass) {
466    if (isa<Zeroes>(marker) || isa<Zeroes>(charclass)) {
467        return marker;
468    }
469    MAKE_BINARY(createMatchStar, TypeId::MatchStar, marker, charclass);
470    return result;
471}
472
473PabloAST * PabloBuilder::createMatchStar(PabloAST * marker, PabloAST * charclass, const std::string & prefix) {
474    if (isa<Zeroes>(marker) || isa<Zeroes>(charclass)) {
475        return marker;
476    }
477    MAKE_NAMED_BINARY(createMatchStar, TypeId::MatchStar, prefix, marker, charclass);
478    return result;
479}
480
481PabloAST * PabloBuilder::createScanThru(PabloAST * from, PabloAST * thru) {
482    if (isa<Zeroes>(from) || isa<Zeroes>(thru)) {
483        return from;
484    }
485    MAKE_BINARY(createScanThru, TypeId::ScanThru, from, thru);
486    return result;
487}
488
489PabloAST * PabloBuilder::createScanThru(PabloAST * from, PabloAST * thru, const std::string & prefix) {
490    if (isa<Zeroes>(from) || isa<Zeroes>(thru)) {
491        return from;
492    }
493    MAKE_NAMED_BINARY(createScanThru, TypeId::ScanThru, prefix, from, thru);
494    return result;
495}
496
497
498PabloAST * PabloBuilder::createSel(PabloAST * condition, PabloAST * trueExpr, PabloAST * falseExpr) {
499    if (isa<Ones>(condition)) {
500        return trueExpr;
501    } else if (isa<Zeroes>(condition)){
502        return falseExpr;
503    } else if (isa<Ones>(trueExpr)) {
504        return createOr(condition, falseExpr);
505    } else if (isa<Zeroes>(trueExpr)){
506        return createAnd(createNot(condition), falseExpr);
507    } else if (isa<Ones>(falseExpr)) {
508        return createOr(createNot(condition), trueExpr);
509    } else if (isa<Zeroes>(falseExpr)){
510        return createAnd(condition, trueExpr);
511    } else if (equals(trueExpr, falseExpr)) {
512        return trueExpr;
513    } else if (isa<Not>(trueExpr) && equals(cast<Not>(trueExpr)->getOperand(0), falseExpr)) {
514        return createXor(condition, falseExpr);
515    } else if (isa<Not>(falseExpr) && equals(trueExpr, cast<Not>(falseExpr)->getOperand(0))){
516        return createXor(condition, trueExpr);
517    }
518    MAKE_TERNARY(createSel, TypeId::Sel, condition, trueExpr, falseExpr);
519    return result;
520}
521
522PabloAST * PabloBuilder::createSel(PabloAST * condition, PabloAST * trueExpr, PabloAST * falseExpr, const std::string & prefix) {
523    if (isa<Ones>(condition)) {
524        return trueExpr;
525    } else if (isa<Zeroes>(condition)){
526        return falseExpr;
527    } else if (isa<Ones>(trueExpr)) {
528        return createOr(condition, falseExpr);
529    } else if (isa<Zeroes>(trueExpr)){
530        return createAnd(createNot(condition), falseExpr);
531    } else if (isa<Ones>(falseExpr)) {
532        return createOr(createNot(condition), trueExpr);
533    } else if (isa<Zeroes>(falseExpr)){
534        return createAnd(condition, trueExpr);
535    } else if (equals(trueExpr, falseExpr)) {
536        return trueExpr;
537    } else if (isa<Not>(trueExpr) && equals(cast<Not>(trueExpr)->getOperand(0), falseExpr)) {
538        return createXor(condition, falseExpr);
539    } else if (isa<Not>(falseExpr) && equals(trueExpr, cast<Not>(falseExpr)->getOperand(0))){
540        return createXor(condition, trueExpr);
541    }
542    MAKE_NAMED_TERNARY(createSel, TypeId::Sel, prefix, condition, trueExpr, falseExpr);
543    return result;
544}
545
546}
Note: See TracBrowser for help on using the repository browser.