/*
 * Copyright © 2012 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 */

// Imported from pNaCl project
// Copyright (c) 2003-2014 University of Illinois at Urbana-Champaign.
// All rights reserved.
//
// Developed by:
//
//    LLVM Team
//
//    University of Illinois at Urbana-Champaign
//
//    http://llvm.org
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal with
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimers.
//
//   * Redistributions in binary form must reproduce the above copyright notice,
//      this list of conditions and the following disclaimers in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the names of the LLVM Team, University of Illinois at
//      Urbana-Champaign, nor the names of its contributors may be used to
//      endorse or promote products derived from this Software without specific
//      prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
// SOFTWARE.

//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass strips out attributes that are not supported by Beignet.
// Currently, this strips out:
//
//  * Calling conventions from functions and function calls.
//

#include "llvm_includes.hpp"

#include "llvm_gen_backend.hpp"

using namespace llvm;

namespace {
  class StripAttributes : public FunctionPass {
  public:
    static char ID; // Pass identification, replacement for typeid
    StripAttributes(bool lastTime) : FunctionPass(ID),
                                     lastTime(lastTime) {
    }

    virtual bool runOnFunction(Function &Func);
  private:
    bool lastTime; //last time all StripAttributes
  };
}

char StripAttributes::ID = 0;

bool StripAttributes::runOnFunction(Function &Func) {
  Func.setCallingConv(CallingConv::C);
  Func.setLinkage(GlobalValue::ExternalLinkage);
  if (!gbe::isKernelFunction(Func)) {
    Func.addFnAttr(Attribute::AlwaysInline);
    if (lastTime ||
        (Func.getName().find("__gen_mem") == std::string::npos))
      // Memcpy and memset functions could be deleted at last inline.
      // Delete memcpy and memset functions for output llvm ir friendly.
      Func.setLinkage(GlobalValue::LinkOnceAnyLinkage);
  }

  for (Function::iterator BB = Func.begin(), E = Func.end();
       BB != E; ++BB) {
    for (BasicBlock::iterator Inst = BB->begin(), E = BB->end();
         Inst != E; ++Inst) {
      CallSite Call(&*Inst);
      if (Call)
        Call.setCallingConv(CallingConv::C);
    }
  }

  return true;
}

FunctionPass *llvm::createStripAttributesPass(bool lastTime) {
  return new StripAttributes(lastTime);
}
