1 /* 2 * Copyright (C) 2012 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "third_party/compiler/ArrayBoundsClamper.h" 27 28 // The built-in 'clamp' instruction only accepts floats and returns a float. I 29 // iterated a few times with our driver team who examined the output from our 30 // compiler - they said the multiple casts generates more code than a single 31 // function call. An inline ternary operator might have been better, but since 32 // the index value might be an expression itself, we'd have to make temporary 33 // variables to avoid evaluating the expression multiple times. And making 34 // temporary variables was difficult because ANGLE would then need to make more 35 // brutal changes to the expression tree. 36 37 const char* kIntClampBegin = "// BEGIN: Generated code for array bounds clamping\n\n"; 38 const char* kIntClampEnd = "// END: Generated code for array bounds clamping\n\n"; 39 const char* kIntClampDefinition = "int webgl_int_clamp(int value, int minValue, int maxValue) { return ((value < minValue) ? minValue : ((value > maxValue) ? maxValue : value)); }\n\n"; 40 41 namespace { 42 43 class ArrayBoundsClamperMarker : public TIntermTraverser { 44 public: 45 ArrayBoundsClamperMarker() 46 : mNeedsClamp(false) 47 { 48 } 49 50 virtual bool visitBinary(Visit visit, TIntermBinary* node) 51 { 52 if (node->getOp() == EOpIndexIndirect) 53 { 54 TIntermTyped* left = node->getLeft(); 55 if (left->isArray() || left->isVector() || left->isMatrix()) 56 { 57 node->setAddIndexClamp(); 58 mNeedsClamp = true; 59 } 60 } 61 return true; 62 } 63 64 bool GetNeedsClamp() { return mNeedsClamp; } 65 66 private: 67 bool mNeedsClamp; 68 }; 69 70 } // anonymous namespace 71 72 ArrayBoundsClamper::ArrayBoundsClamper() 73 : mClampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC) 74 , mArrayBoundsClampDefinitionNeeded(false) 75 { 76 } 77 78 void ArrayBoundsClamper::SetClampingStrategy(ShArrayIndexClampingStrategy clampingStrategy) 79 { 80 mClampingStrategy = clampingStrategy; 81 } 82 83 void ArrayBoundsClamper::MarkIndirectArrayBoundsForClamping(TIntermNode* root) 84 { 85 ASSERT(root); 86 87 ArrayBoundsClamperMarker clamper; 88 root->traverse(&clamper); 89 if (clamper.GetNeedsClamp()) 90 { 91 SetArrayBoundsClampDefinitionNeeded(); 92 } 93 } 94 95 void ArrayBoundsClamper::OutputClampingFunctionDefinition(TInfoSinkBase& out) const 96 { 97 if (!mArrayBoundsClampDefinitionNeeded) 98 { 99 return; 100 } 101 if (mClampingStrategy != SH_CLAMP_WITH_USER_DEFINED_INT_CLAMP_FUNCTION) 102 { 103 return; 104 } 105 out << kIntClampBegin << kIntClampDefinition << kIntClampEnd; 106 } 107