Home | History | Annotate | Download | only in compiler
      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