<commit_before>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// STP - SFML TMX Parser
// Copyright (c) 2013-2014 Manuel Sabogal
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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 AUTHORS 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 IN THE SOFTWARE.
//
////////////////////////////////////////////////////////////

#include "STP/Core/Layer.hpp"

#include <stdexcept>
#include <string>
#include <vector>

#include "SFML/Graphics/RenderTarget.hpp"

namespace tmx {

Layer::Layer() {}

Layer::Layer(const std::string& name, unsigned int width,
             unsigned int height, float opacity, bool visible, std::string orientation, sf::Vector2i tilesize) :
        MapObject(name, width, height, opacity, visible),
        orientation_(orientation),
        tile_size_(tilesize) {
    // Reserve space for each vector to avoid reallocate
    tiles_.reserve(width * height);
    unsigned char alpha = static_cast<unsigned char>(255 * opacity);
    color_.a = alpha;
}

void Layer::AddTile(unsigned int gid, sf::IntRect& tile_rect, tmx::TileSet* tileset) {
    tiles_.emplace_back(gid, tile_rect, orientation_, tile_size_, tileset);
	tiles_.back().SetColor(color_);
}

unsigned int Layer::GetWidth() const {
    return width_;
}

unsigned int Layer::GetHeight() const {
    return height_;
}

tmx::Layer::Tile& Layer::GetTile(unsigned int x, unsigned int y) {
    if (x >= width_ || y >= height_) {
        char error[100];
        sprintf(error, "Error: tile (%u, %u) out of range.\n", x, y);
        throw std::out_of_range(error);
    }

    unsigned int pos = (y * width_) + x;

    return tiles_[pos];
}

void Layer::SetColor(const sf::Color& color) {
    color_.r = color.r;
    color_.g = color.g;
    color_.b = color.b;
    for (auto& tile : tiles_) {
        tile.SetColor(color_);
    }
}

void Layer::SetOpacity(float opacity) {
    color_.a = static_cast<unsigned char>(255 * opacity);
    for (auto& tile : tiles_) {
        tile.SetColor(color_);
    }
}

void Layer::draw(sf::RenderTarget& target, sf::RenderStates states) const {
    if (visible) {
        for (unsigned int i = 0; i < tiles_.size(); ++i)
            target.draw(tiles_[i]);
    }
}

////////////////////////////////////////////////////////////
// Layer::Tile implementation
////////////////////////////////////////////////////////////

Layer::Tile::Tile() {}

Layer::Tile::Tile(unsigned int gid, sf::IntRect tile_rect, std::string orientation, sf::Vector2i tilesize, tmx::TileSet* tileset) :
        gid_(gid),
        tile_rect_(tile_rect),
        tile_properties_(nullptr),
        texture_(nullptr),
        texture_rect_(),
        visible(true) {
    if (tileset) {
        unsigned int id = gid - tileset->GetFirstGID();  // The local id of the tile in the tileset

        texture_ = tileset->GetTexture();
        texture_rect_ = tileset->GetTextureRect(id);
        tile_properties_ = &tileset->GetTile(id);
    }

    if (orienation != "orthogonal") {
    	float x = tile_rect_.left / tilesize.x;
        float y = tile_rect_.top / tilesize.y;

    	if (orientation == "isometric") {
    		tile_rect_.left = (x-y) * tilesize.x * 0.5;
            tile_rect_.top = (x+y) * tilesize.y * 0.5;
        }

        if (orientation == "staggered") {
        	if ((y % 2) == 0) {
        		tile_rect_.left = x * tilesize.x;
        	}
        	else {
        		tile_rect_.left = x * tilesize.x + tilesize.x /2;
        	}
        	tile_rect_.top = y * tilesize.y / 2;
        }
    }

    UpdatePositions();
    UpdateTexCoords();
}

void Layer::Tile::UpdatePositions() {
    sf::FloatRect bounds = GetGlobalBounds();

    vertices_[0].position = sf::Vector2f(bounds.left, bounds.top);
    vertices_[1].position = sf::Vector2f(bounds.left + bounds.width, bounds.top);
    vertices_[2].position = sf::Vector2f(bounds.left + bounds.width, bounds.top + bounds.height);
    vertices_[3].position = sf::Vector2f(bounds.left, bounds.top + bounds.height);
}

void Layer::Tile::UpdateTexCoords() {
    float left   = static_cast<float>(texture_rect_.left);
    float right  = left + texture_rect_.width;
    float top    = static_cast<float>(texture_rect_.top);
    float bottom = top + texture_rect_.height;

    vertices_[0].texCoords = sf::Vector2f(left, top);
    vertices_[1].texCoords = sf::Vector2f(right, top);
    vertices_[2].texCoords = sf::Vector2f(right, bottom);
    vertices_[3].texCoords = sf::Vector2f(left, bottom);
}

sf::FloatRect Layer::Tile::GetGlobalBounds() const {
    float left = static_cast<float>(tile_rect_.left);
    float top = static_cast<float>(tile_rect_.top);
    float width = static_cast<float>(tile_rect_.width);
    float height = static_cast<float>(tile_rect_.height);

    return sf::FloatRect(left, top, width, height);
}

bool Layer::Tile::empty() const {
    if (gid_ == 0 || !texture_) return true;
    else return false;
}

void Layer::Tile::SetColor(const sf::Color& color) {
    vertices_[0].color = color;
    vertices_[1].color = color;
    vertices_[2].color = color;
    vertices_[3].color = color;
}

void Layer::Tile::AddProperty(const std::string& name, const std::string& value) {
    tile_properties_->AddProperty(name, value);
}

std::string& Layer::Tile::GetPropertyValue(const std::string& name) {
    return tile_properties_->GetPropertyValue(name);
}

void Layer::Tile::draw(sf::RenderTarget& target, sf::RenderStates states) const {
    if (texture_ && visible) {
        states.texture = texture_;
        target.draw(vertices_, 4, sf::Quads, states);
    }
}

}  // namespace tmx
<commit_msg>Fix mistake and remove some tabs<commit_after>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// STP - SFML TMX Parser
// Copyright (c) 2013-2014 Manuel Sabogal
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// 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:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// 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 AUTHORS 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 IN THE SOFTWARE.
//
////////////////////////////////////////////////////////////

#include "STP/Core/Layer.hpp"

#include <stdexcept>
#include <string>
#include <vector>

#include "SFML/Graphics/RenderTarget.hpp"

namespace tmx {

Layer::Layer() {}

Layer::Layer(const std::string& name, unsigned int width,
             unsigned int height, float opacity, bool visible, std::string orientation, sf::Vector2i tilesize) :
        MapObject(name, width, height, opacity, visible),
        orientation_(orientation),
        tile_size_(tilesize) {
    // Reserve space for each vector to avoid reallocate
    tiles_.reserve(width * height);
    unsigned char alpha = static_cast<unsigned char>(255 * opacity);
    color_.a = alpha;
}

void Layer::AddTile(unsigned int gid, sf::IntRect& tile_rect, tmx::TileSet* tileset) {
    tiles_.emplace_back(gid, tile_rect, orientation_, tile_size_, tileset);
	tiles_.back().SetColor(color_);
}

unsigned int Layer::GetWidth() const {
    return width_;
}

unsigned int Layer::GetHeight() const {
    return height_;
}

tmx::Layer::Tile& Layer::GetTile(unsigned int x, unsigned int y) {
    if (x >= width_ || y >= height_) {
        char error[100];
        sprintf(error, "Error: tile (%u, %u) out of range.\n", x, y);
        throw std::out_of_range(error);
    }

    unsigned int pos = (y * width_) + x;

    return tiles_[pos];
}

void Layer::SetColor(const sf::Color& color) {
    color_.r = color.r;
    color_.g = color.g;
    color_.b = color.b;
    for (auto& tile : tiles_) {
        tile.SetColor(color_);
    }
}

void Layer::SetOpacity(float opacity) {
    color_.a = static_cast<unsigned char>(255 * opacity);
    for (auto& tile : tiles_) {
        tile.SetColor(color_);
    }
}

void Layer::draw(sf::RenderTarget& target, sf::RenderStates states) const {
    if (visible) {
        for (unsigned int i = 0; i < tiles_.size(); ++i)
            target.draw(tiles_[i]);
    }
}

////////////////////////////////////////////////////////////
// Layer::Tile implementation
////////////////////////////////////////////////////////////

Layer::Tile::Tile() {}

Layer::Tile::Tile(unsigned int gid, sf::IntRect tile_rect, std::string orientation, sf::Vector2i tilesize, tmx::TileSet* tileset) :
        gid_(gid),
        tile_rect_(tile_rect),
        tile_properties_(nullptr),
        texture_(nullptr),
        texture_rect_(),
        visible(true) {
    if (tileset) {
        unsigned int id = gid - tileset->GetFirstGID();  // The local id of the tile in the tileset

        texture_ = tileset->GetTexture();
        texture_rect_ = tileset->GetTextureRect(id);
        tile_properties_ = &tileset->GetTile(id);
    }

    if (orientation != "orthogonal") {
    	float x = tile_rect_.left / tilesize.x;
        float y = tile_rect_.top / tilesize.y;

    	if (orientation == "isometric") {
    	    tile_rect_.left = (x-y) * tilesize.x * 0.5;
            tile_rect_.top = (x+y) * tilesize.y * 0.5;
        }

        if (orientation == "staggered") {
            if ((y % 2) == 0) {
                tile_rect_.left = x * tilesize.x;
            }
            else {
                tile_rect_.left = x * tilesize.x + tilesize.x /2;
            }
            tile_rect_.top = y * tilesize.y / 2;
        }
    }

    UpdatePositions();
    UpdateTexCoords();
}

void Layer::Tile::UpdatePositions() {
    sf::FloatRect bounds = GetGlobalBounds();

    vertices_[0].position = sf::Vector2f(bounds.left, bounds.top);
    vertices_[1].position = sf::Vector2f(bounds.left + bounds.width, bounds.top);
    vertices_[2].position = sf::Vector2f(bounds.left + bounds.width, bounds.top + bounds.height);
    vertices_[3].position = sf::Vector2f(bounds.left, bounds.top + bounds.height);
}

void Layer::Tile::UpdateTexCoords() {
    float left   = static_cast<float>(texture_rect_.left);
    float right  = left + texture_rect_.width;
    float top    = static_cast<float>(texture_rect_.top);
    float bottom = top + texture_rect_.height;

    vertices_[0].texCoords = sf::Vector2f(left, top);
    vertices_[1].texCoords = sf::Vector2f(right, top);
    vertices_[2].texCoords = sf::Vector2f(right, bottom);
    vertices_[3].texCoords = sf::Vector2f(left, bottom);
}

sf::FloatRect Layer::Tile::GetGlobalBounds() const {
    float left = static_cast<float>(tile_rect_.left);
    float top = static_cast<float>(tile_rect_.top);
    float width = static_cast<float>(tile_rect_.width);
    float height = static_cast<float>(tile_rect_.height);

    return sf::FloatRect(left, top, width, height);
}

bool Layer::Tile::empty() const {
    if (gid_ == 0 || !texture_) return true;
    else return false;
}

void Layer::Tile::SetColor(const sf::Color& color) {
    vertices_[0].color = color;
    vertices_[1].color = color;
    vertices_[2].color = color;
    vertices_[3].color = color;
}

void Layer::Tile::AddProperty(const std::string& name, const std::string& value) {
    tile_properties_->AddProperty(name, value);
}

std::string& Layer::Tile::GetPropertyValue(const std::string& name) {
    return tile_properties_->GetPropertyValue(name);
}

void Layer::Tile::draw(sf::RenderTarget& target, sf::RenderStates states) const {
    if (texture_ && visible) {
        states.texture = texture_;
        target.draw(vertices_, 4, sf::Quads, states);
    }
}

}  // namespace tmx
<|endoftext|>


<commit_before>//===-- TwoAddressInstructionPass.cpp - Two-Address instruction pass ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the TwoAddress instruction pass which is used
// by most register allocators. Two-Address instructions are rewritten
// from:
//
//     A = B op C
//
// to:
//
//     A = B
//     A op= C
//
// Note that if a register allocator chooses to use this pass, that it
// has to be capable of handling the non-SSA nature of these rewritten
// virtual registers.
//
// It is also worth noting that the duplicate operand of the two
// address instruction is removed.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "twoaddrinstr"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
using namespace llvm;

STATISTIC(NumTwoAddressInstrs, "Number of two-address instructions");
STATISTIC(NumCommuted        , "Number of instructions commuted to coalesce");
STATISTIC(NumConvertedTo3Addr, "Number of instructions promoted to 3-address");

namespace {
  struct VISIBILITY_HIDDEN TwoAddressInstructionPass
   : public MachineFunctionPass {
    static char ID; // Pass identification, replacement for typeid
    TwoAddressInstructionPass() : MachineFunctionPass((intptr_t)&ID) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const;

    /// runOnMachineFunction - pass entry point
    bool runOnMachineFunction(MachineFunction&);
  };

  char TwoAddressInstructionPass::ID = 0;
  RegisterPass<TwoAddressInstructionPass>
  X("twoaddressinstruction", "Two-Address instruction pass");
}

const PassInfo *llvm::TwoAddressInstructionPassID = X.getPassInfo();

void TwoAddressInstructionPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<LiveVariables>();
  AU.addPreserved<LiveVariables>();
  AU.addPreservedID(PHIEliminationID);
  MachineFunctionPass::getAnalysisUsage(AU);
}

/// runOnMachineFunction - Reduce two-address instructions to two
/// operands.
///
bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
  DOUT << "Machine Function\n";
  const TargetMachine &TM = MF.getTarget();
  const TargetInstrInfo &TII = *TM.getInstrInfo();
  const MRegisterInfo &MRI = *TM.getRegisterInfo();
  LiveVariables &LV = getAnalysis<LiveVariables>();

  bool MadeChange = false;

  DOUT << "********** REWRITING TWO-ADDR INSTRS **********\n";
  DOUT << "********** Function: " << MF.getFunction()->getName() << '\n';

  for (MachineFunction::iterator mbbi = MF.begin(), mbbe = MF.end();
       mbbi != mbbe; ++mbbi) {
    for (MachineBasicBlock::iterator mi = mbbi->begin(), me = mbbi->end();
         mi != me; ++mi) {
      const TargetInstrDescriptor *TID = mi->getInstrDescriptor();

      bool FirstTied = true;
      for (unsigned si = 1, e = TID->numOperands; si < e; ++si) {
        int ti = TID->getOperandConstraint(si, TOI::TIED_TO);
        if (ti == -1)
          continue;

        if (FirstTied) {
          ++NumTwoAddressInstrs;
          DOUT << '\t'; DEBUG(mi->print(*cerr.stream(), &TM));
        }
        FirstTied = false;

        assert(mi->getOperand(si).isRegister() && mi->getOperand(si).getReg() &&
               mi->getOperand(si).isUse() && "two address instruction invalid");

        // if the two operands are the same we just remove the use
        // and mark the def as def&use, otherwise we have to insert a copy.
        if (mi->getOperand(ti).getReg() != mi->getOperand(si).getReg()) {
          // rewrite:
          //     a = b op c
          // to:
          //     a = b
          //     a = a op c
          unsigned regA = mi->getOperand(ti).getReg();
          unsigned regB = mi->getOperand(si).getReg();

          assert(MRegisterInfo::isVirtualRegister(regA) &&
                 MRegisterInfo::isVirtualRegister(regB) &&
                 "cannot update physical register live information");

#ifndef NDEBUG
          // First, verify that we don't have a use of a in the instruction (a =
          // b + a for example) because our transformation will not work. This
          // should never occur because we are in SSA form.
          for (unsigned i = 0; i != mi->getNumOperands(); ++i)
            assert((int)i == ti ||
                   !mi->getOperand(i).isRegister() ||
                   mi->getOperand(i).getReg() != regA);
#endif

          // If this instruction is not the killing user of B, see if we can
          // rearrange the code to make it so.  Making it the killing user will
          // allow us to coalesce A and B together, eliminating the copy we are
          // about to insert.
          if (!LV.KillsRegister(mi, regB)) {
            // If this instruction is commutative, check to see if C dies.  If
            // so, swap the B and C operands.  This makes the live ranges of A
            // and C joinable.
            // FIXME: This code also works for A := B op C instructions.
            if ((TID->Flags & M_COMMUTABLE) && mi->getNumOperands() == 3) {
              assert(mi->getOperand(3-si).isRegister() &&
                     "Not a proper commutative instruction!");
              unsigned regC = mi->getOperand(3-si).getReg();
              if (LV.KillsRegister(mi, regC)) {
                DOUT << "2addr: COMMUTING  : " << *mi;
                MachineInstr *NewMI = TII.commuteInstruction(mi);
                if (NewMI == 0) {
                  DOUT << "2addr: COMMUTING FAILED!\n";
                } else {
                  DOUT << "2addr: COMMUTED TO: " << *NewMI;
                  // If the instruction changed to commute it, update livevar.
                  if (NewMI != mi) {
                    LV.instructionChanged(mi, NewMI);  // Update live variables
                    mbbi->insert(mi, NewMI);           // Insert the new inst
                    mbbi->erase(mi);                   // Nuke the old inst.
                    mi = NewMI;
                  }

                  ++NumCommuted;
                  regB = regC;
                  goto InstructionRearranged;
                }
              }
            }

            // If this instruction is potentially convertible to a true
            // three-address instruction,
            if (TID->Flags & M_CONVERTIBLE_TO_3_ADDR) {
              // FIXME: This assumes there are no more operands which are tied
              // to another register.
#ifndef NDEBUG
              for (unsigned i = si+1, e = TID->numOperands; i < e; ++i)
                assert(TID->getOperandConstraint(i, TOI::TIED_TO) == -1);
#endif

              if (MachineInstr *New = TII.convertToThreeAddress(mbbi, mi, LV)) {
                DOUT << "2addr: CONVERTING 2-ADDR: " << *mi;
                DOUT << "2addr:         TO 3-ADDR: " << *New;
                mbbi->erase(mi);                 // Nuke the old inst.
                mi = New;
                ++NumConvertedTo3Addr;
                // Done with this instruction.
                break;
              }
            }
          }

        InstructionRearranged:
          const TargetRegisterClass* rc = MF.getSSARegMap()->getRegClass(regA);
          MRI.copyRegToReg(*mbbi, mi, regA, regB, rc, rc);

          MachineBasicBlock::iterator prevMi = prior(mi);
          DOUT << "\t\tprepend:\t"; DEBUG(prevMi->print(*cerr.stream(), &TM));

          // Update live variables for regA
          LiveVariables::VarInfo& varInfo = LV.getVarInfo(regA);
          varInfo.DefInst = prevMi;

          if (LV.removeVirtualRegisterKilled(regB, mbbi, mi))
            LV.addVirtualRegisterKilled(regB, prevMi);

          if (LV.removeVirtualRegisterDead(regB, mbbi, mi))
            LV.addVirtualRegisterDead(regB, prevMi);

          // replace all occurences of regB with regA
          for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) {
            if (mi->getOperand(i).isRegister() &&
                mi->getOperand(i).getReg() == regB)
              mi->getOperand(i).setReg(regA);
          }
        }

        assert(mi->getOperand(ti).isDef() && mi->getOperand(si).isUse());
        mi->getOperand(ti).setReg(mi->getOperand(si).getReg());
        MadeChange = true;

        DOUT << "\t\trewrite to:\t"; DEBUG(mi->print(*cerr.stream(), &TM));
      }
    }
  }

  return MadeChange;
}
<commit_msg>It's possible to commute instrctions with more than 3 operands.<commit_after>//===-- TwoAddressInstructionPass.cpp - Two-Address instruction pass ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the TwoAddress instruction pass which is used
// by most register allocators. Two-Address instructions are rewritten
// from:
//
//     A = B op C
//
// to:
//
//     A = B
//     A op= C
//
// Note that if a register allocator chooses to use this pass, that it
// has to be capable of handling the non-SSA nature of these rewritten
// virtual registers.
//
// It is also worth noting that the duplicate operand of the two
// address instruction is removed.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "twoaddrinstr"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
using namespace llvm;

STATISTIC(NumTwoAddressInstrs, "Number of two-address instructions");
STATISTIC(NumCommuted        , "Number of instructions commuted to coalesce");
STATISTIC(NumConvertedTo3Addr, "Number of instructions promoted to 3-address");

namespace {
  struct VISIBILITY_HIDDEN TwoAddressInstructionPass
   : public MachineFunctionPass {
    static char ID; // Pass identification, replacement for typeid
    TwoAddressInstructionPass() : MachineFunctionPass((intptr_t)&ID) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const;

    /// runOnMachineFunction - pass entry point
    bool runOnMachineFunction(MachineFunction&);
  };

  char TwoAddressInstructionPass::ID = 0;
  RegisterPass<TwoAddressInstructionPass>
  X("twoaddressinstruction", "Two-Address instruction pass");
}

const PassInfo *llvm::TwoAddressInstructionPassID = X.getPassInfo();

void TwoAddressInstructionPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<LiveVariables>();
  AU.addPreserved<LiveVariables>();
  AU.addPreservedID(PHIEliminationID);
  MachineFunctionPass::getAnalysisUsage(AU);
}

/// runOnMachineFunction - Reduce two-address instructions to two
/// operands.
///
bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) {
  DOUT << "Machine Function\n";
  const TargetMachine &TM = MF.getTarget();
  const TargetInstrInfo &TII = *TM.getInstrInfo();
  const MRegisterInfo &MRI = *TM.getRegisterInfo();
  LiveVariables &LV = getAnalysis<LiveVariables>();

  bool MadeChange = false;

  DOUT << "********** REWRITING TWO-ADDR INSTRS **********\n";
  DOUT << "********** Function: " << MF.getFunction()->getName() << '\n';

  for (MachineFunction::iterator mbbi = MF.begin(), mbbe = MF.end();
       mbbi != mbbe; ++mbbi) {
    for (MachineBasicBlock::iterator mi = mbbi->begin(), me = mbbi->end();
         mi != me; ++mi) {
      const TargetInstrDescriptor *TID = mi->getInstrDescriptor();

      bool FirstTied = true;
      for (unsigned si = 1, e = TID->numOperands; si < e; ++si) {
        int ti = TID->getOperandConstraint(si, TOI::TIED_TO);
        if (ti == -1)
          continue;

        if (FirstTied) {
          ++NumTwoAddressInstrs;
          DOUT << '\t'; DEBUG(mi->print(*cerr.stream(), &TM));
        }
        FirstTied = false;

        assert(mi->getOperand(si).isRegister() && mi->getOperand(si).getReg() &&
               mi->getOperand(si).isUse() && "two address instruction invalid");

        // if the two operands are the same we just remove the use
        // and mark the def as def&use, otherwise we have to insert a copy.
        if (mi->getOperand(ti).getReg() != mi->getOperand(si).getReg()) {
          // rewrite:
          //     a = b op c
          // to:
          //     a = b
          //     a = a op c
          unsigned regA = mi->getOperand(ti).getReg();
          unsigned regB = mi->getOperand(si).getReg();

          assert(MRegisterInfo::isVirtualRegister(regA) &&
                 MRegisterInfo::isVirtualRegister(regB) &&
                 "cannot update physical register live information");

#ifndef NDEBUG
          // First, verify that we don't have a use of a in the instruction (a =
          // b + a for example) because our transformation will not work. This
          // should never occur because we are in SSA form.
          for (unsigned i = 0; i != mi->getNumOperands(); ++i)
            assert((int)i == ti ||
                   !mi->getOperand(i).isRegister() ||
                   mi->getOperand(i).getReg() != regA);
#endif

          // If this instruction is not the killing user of B, see if we can
          // rearrange the code to make it so.  Making it the killing user will
          // allow us to coalesce A and B together, eliminating the copy we are
          // about to insert.
          if (!LV.KillsRegister(mi, regB)) {
            // If this instruction is commutative, check to see if C dies.  If
            // so, swap the B and C operands.  This makes the live ranges of A
            // and C joinable.
            // FIXME: This code also works for A := B op C instructions.
            if ((TID->Flags & M_COMMUTABLE) && mi->getNumOperands() >= 3) {
              assert(mi->getOperand(3-si).isRegister() &&
                     "Not a proper commutative instruction!");
              unsigned regC = mi->getOperand(3-si).getReg();
              if (LV.KillsRegister(mi, regC)) {
                DOUT << "2addr: COMMUTING  : " << *mi;
                MachineInstr *NewMI = TII.commuteInstruction(mi);
                if (NewMI == 0) {
                  DOUT << "2addr: COMMUTING FAILED!\n";
                } else {
                  DOUT << "2addr: COMMUTED TO: " << *NewMI;
                  // If the instruction changed to commute it, update livevar.
                  if (NewMI != mi) {
                    LV.instructionChanged(mi, NewMI);  // Update live variables
                    mbbi->insert(mi, NewMI);           // Insert the new inst
                    mbbi->erase(mi);                   // Nuke the old inst.
                    mi = NewMI;
                  }

                  ++NumCommuted;
                  regB = regC;
                  goto InstructionRearranged;
                }
              }
            }

            // If this instruction is potentially convertible to a true
            // three-address instruction,
            if (TID->Flags & M_CONVERTIBLE_TO_3_ADDR) {
              // FIXME: This assumes there are no more operands which are tied
              // to another register.
#ifndef NDEBUG
              for (unsigned i = si+1, e = TID->numOperands; i < e; ++i)
                assert(TID->getOperandConstraint(i, TOI::TIED_TO) == -1);
#endif

              if (MachineInstr *New = TII.convertToThreeAddress(mbbi, mi, LV)) {
                DOUT << "2addr: CONVERTING 2-ADDR: " << *mi;
                DOUT << "2addr:         TO 3-ADDR: " << *New;
                mbbi->erase(mi);                 // Nuke the old inst.
                mi = New;
                ++NumConvertedTo3Addr;
                // Done with this instruction.
                break;
              }
            }
          }

        InstructionRearranged:
          const TargetRegisterClass* rc = MF.getSSARegMap()->getRegClass(regA);
          MRI.copyRegToReg(*mbbi, mi, regA, regB, rc, rc);

          MachineBasicBlock::iterator prevMi = prior(mi);
          DOUT << "\t\tprepend:\t"; DEBUG(prevMi->print(*cerr.stream(), &TM));

          // Update live variables for regA
          LiveVariables::VarInfo& varInfo = LV.getVarInfo(regA);
          varInfo.DefInst = prevMi;

          if (LV.removeVirtualRegisterKilled(regB, mbbi, mi))
            LV.addVirtualRegisterKilled(regB, prevMi);

          if (LV.removeVirtualRegisterDead(regB, mbbi, mi))
            LV.addVirtualRegisterDead(regB, prevMi);

          // replace all occurences of regB with regA
          for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) {
            if (mi->getOperand(i).isRegister() &&
                mi->getOperand(i).getReg() == regB)
              mi->getOperand(i).setReg(regA);
          }
        }

        assert(mi->getOperand(ti).isDef() && mi->getOperand(si).isUse());
        mi->getOperand(ti).setReg(mi->getOperand(si).getReg());
        MadeChange = true;

        DOUT << "\t\trewrite to:\t"; DEBUG(mi->print(*cerr.stream(), &TM));
      }
    }
  }

  return MadeChange;
}
<|endoftext|>


<commit_before>#include "SendingPromise.hpp"

using namespace HomieInternals;

SendingPromise::SendingPromise()
: _node(nullptr)
, _property(nullptr)
, _qos(0)
, _retained(false)
, _overwriteSetter(false)
, _range { .isRange = false, .index = 0 } {
}

SendingPromise& SendingPromise::setQos(uint8_t qos) {
  _qos = qos;
  return *this;
}

SendingPromise& SendingPromise::setRetained(bool retained) {
  _retained = retained;
  return *this;
}

SendingPromise& SendingPromise::overwriteSetter(bool overwrite) {
  _overwriteSetter = overwrite;
  return *this;
}

SendingPromise& SendingPromise::setRange(const HomieRange& range) {
  _range = range;
  return *this;
}

SendingPromise& SendingPromise::setRange(uint16_t rangeIndex) {
  HomieRange range;
  range.isRange = true;
  range.index = rangeIndex;
  _range = range;
  return *this;
}

uint16_t SendingPromise::send(const String& value) {
  if (!Interface::get().ready) {
    Interface::get().getLogger() << F("✖ setNodeProperty(): impossible now") << endl;
    return 0;
  }

  char* topic = new char[strlen(Interface::get().getConfig().get().mqtt.baseTopic) + strlen(Interface::get().getConfig().get().deviceId) + 1 + strlen(_node->getId()) + 1 + strlen(_property->c_str()) + 6 + 4 + 1];  // last + 6 for range _65536, last + 4 for /set
  strcpy(topic, Interface::get().getConfig().get().mqtt.baseTopic);
  strcat(topic, Interface::get().getConfig().get().deviceId);
  strcat_P(topic, PSTR("/"));
  strcat(topic, _node->getId());
  if (_range.isRange) {
    char rangeStr[5 + 1];  // max 65536
    itoa(_range.index, rangeStr, 10);
    strcat_P(topic, PSTR("_"));
    strcat(topic, rangeStr);
    _range.isRange=false;			//FIXME: This is a workaround. Problem is that Range is loaded from the property into SendingPromise, but the SendingPromise is global. (one SendingPromise for the HomieClass instance
    _range.index = 0;
  }

  strcat_P(topic, PSTR("/"));
  strcat(topic, _property->c_str());

  uint16_t packetId = Interface::get().getMqttClient().publish(topic, _qos, _retained, value.c_str());

  if (_overwriteSetter) {
    strcat_P(topic, PSTR("/set"));
    Interface::get().getMqttClient().publish(topic, 1, true, value.c_str());
  }

  delete[] topic;

  return packetId;
}

SendingPromise& SendingPromise::setNode(const HomieNode& node) {
  _node = &node;
  return *this;
}

SendingPromise& SendingPromise::setProperty(const String& property) {
  _property = &property;
  return *this;
}

const HomieNode* SendingPromise::getNode() const {
  return _node;
}

const String* SendingPromise::getProperty() const {
  return _property;
}

uint8_t SendingPromise::getQos() const {
  return _qos;
}

HomieRange SendingPromise::getRange() const {
  return _range;
}

bool SendingPromise::isRetained() const {
  return _retained;
}

bool SendingPromise::doesOverwriteSetter() const {
  return _overwriteSetter;
}
<commit_msg>Fix cpplint warnings<commit_after>#include "SendingPromise.hpp"

using namespace HomieInternals;

SendingPromise::SendingPromise()
: _node(nullptr)
, _property(nullptr)
, _qos(0)
, _retained(false)
, _overwriteSetter(false)
, _range { .isRange = false, .index = 0 } {
}

SendingPromise& SendingPromise::setQos(uint8_t qos) {
  _qos = qos;
  return *this;
}

SendingPromise& SendingPromise::setRetained(bool retained) {
  _retained = retained;
  return *this;
}

SendingPromise& SendingPromise::overwriteSetter(bool overwrite) {
  _overwriteSetter = overwrite;
  return *this;
}

SendingPromise& SendingPromise::setRange(const HomieRange& range) {
  _range = range;
  return *this;
}

SendingPromise& SendingPromise::setRange(uint16_t rangeIndex) {
  HomieRange range;
  range.isRange = true;
  range.index = rangeIndex;
  _range = range;
  return *this;
}

uint16_t SendingPromise::send(const String& value) {
  if (!Interface::get().ready) {
    Interface::get().getLogger() << F("✖ setNodeProperty(): impossible now") << endl;
    return 0;
  }

  char* topic = new char[strlen(Interface::get().getConfig().get().mqtt.baseTopic) + strlen(Interface::get().getConfig().get().deviceId) + 1 + strlen(_node->getId()) + 1 + strlen(_property->c_str()) + 6 + 4 + 1];  // last + 6 for range _65536, last + 4 for /set
  strcpy(topic, Interface::get().getConfig().get().mqtt.baseTopic);
  strcat(topic, Interface::get().getConfig().get().deviceId);
  strcat_P(topic, PSTR("/"));
  strcat(topic, _node->getId());
  if (_range.isRange) {
    char rangeStr[5 + 1];  // max 65536
    itoa(_range.index, rangeStr, 10);
    strcat_P(topic, PSTR("_"));
    strcat(topic, rangeStr);
    _range.isRange = false;                  //FIXME: This is a workaround. Problem is that Range is loaded from the property into SendingPromise, but the SendingPromise is global. (one SendingPromise for the HomieClass instance
    _range.index = 0;
  }

  strcat_P(topic, PSTR("/"));
  strcat(topic, _property->c_str());

  uint16_t packetId = Interface::get().getMqttClient().publish(topic, _qos, _retained, value.c_str());

  if (_overwriteSetter) {
    strcat_P(topic, PSTR("/set"));
    Interface::get().getMqttClient().publish(topic, 1, true, value.c_str());
  }

  delete[] topic;

  return packetId;
}

SendingPromise& SendingPromise::setNode(const HomieNode& node) {
  _node = &node;
  return *this;
}

SendingPromise& SendingPromise::setProperty(const String& property) {
  _property = &property;
  return *this;
}

const HomieNode* SendingPromise::getNode() const {
  return _node;
}

const String* SendingPromise::getProperty() const {
  return _property;
}

uint8_t SendingPromise::getQos() const {
  return _qos;
}

HomieRange SendingPromise::getRange() const {
  return _range;
}

bool SendingPromise::isRetained() const {
  return _retained;
}

bool SendingPromise::doesOverwriteSetter() const {
  return _overwriteSetter;
}
<|endoftext|>


<commit_before>#include "ExpertSystem/CLIPSFunctionBuilder.h"
extern "C" {
#include "clips.h"
}

CLIPSFunctionBuilder::CLIPSFunctionBuilder(std::string nm,
      FunctionNamer& namer) : CLIPSGlobalValueBuilder(nm, "Function",  namer) {
}

void CLIPSFunctionBuilder::build(Function* fn, KnowledgeConstructor* kc) {
   open();
   addFields(fn, kc);
   close();
   std::string str = getCompletedString();
   kc->addToKnowledgeBase((PointerAddress)arg, str);
}

void CLIPSFunctionBuilder::setCallingConvention(CallingConv::ID id) {
   const char* selection;
   switch(id) {
      case CallingConv::C:
         selection = "C";
         break;
      case CallingConv::Fast:
         selection = "Fast";
         break;
      case CallingConv::Cold:
         selection = "Cold";
         break;
      case CallingConv::GHC:
         selection = "GHC";
         break;
      case CallingConv::HiPE:
         selection = "HiPE";
         break;
      case CallingConv::FirstTargetCC:
         selection = "FirstTargetCC";
         break;
      case CallingConv::X86_StdCall:
         selection = "x86-stdcall";
         break;
      case CallingConv::X86_FastCall:
         selection = "x86-fastcall";
         break;
      case CallingConv::ARM_APCS:
         selection = "arm-apcs";
         break;
      case CallingConv::ARM_AAPCS:
         selection = "arm-aapcs";
         break;
      case CallingConv::ARM_AAPCS_VFB:
         selection = "arm-aapcs-vfb";
         break;
      case CallingConv::MSP430_INTR:
         selection = "msp430-intr";
         break;
      case CallingConv::X86_ThisCall:
         selection = "x86-thiscall";
         break;
      case CallingConv::PTX_Kernel:
         selection = "ptx-kernel";
         break;
      case CallingConv::PTX_Device:
         selection = "ptx-device";
         break;
      case CallingConv::MBLAZE_INTR:
         selection = "mblaze-intr";
         break;
      case CallingConv::MBLAZE_SVOL:
         selection = "mblaze-svol";
         break;
      case CallingConv::SPIR_FUNC:
         selection = "spir-func";
         break;
      case CallingConv::SPIR_KERNEL:
         selection = "spir-kernel";
         break;
      case CallingConv::Intel_OCL_BI:
         selection = "intel-ocl-bi";
         break;
      default:
         selection = "Unknown";
         break;
   }
   addField("CallingConvention", selection);
}
void CLIPSFunctionBuilder::setAttributes(const AttributeSet& attr) {

}
void CLIPSFunctionBuilder::addFields(Function* func,
      KnowledgeConstructor* kc) {

   CLIPSGlobalValueBuilder::addFields(func, kc);
   //this part contains the code for building the function itself
   FunctionNamer& namer = getNamer();
   addField("ReturnType", kc->route(func->getReturnType(), namer));
   addField("FunctionType", kc->route(func->getFunctionType(), namer));
   if(func.isVarArg()) {
      addTrueField("IsVarArg");
   }
   addField("IntrinsicID", func->getIntrinsicID());
   if(func.isIntrinsic()) {
      addTrueField("IsIntrinsic");
   }
   setCallingConvention(func->getCallingConv());
   setAttributes(func->getAttributes());
   if(func.hasGC()) {
      addTrueField("HasGC");
      addField("GC", func->getGC());
   }
   if(func.doesNotAccessMemory()) {
      addTrueField("DoesNotAccessMemory");
   }
   if(func.onlyReadsMemory()) {
      addTrueField("OnlyReadsMemory");
   }
   if(func.doesNotReturn()) {
      addTrueField("DoesNotReturn");
   }
   if(func.cannotDuplicate()) {
      addTrueField("CannotDuplicate");
   }
   if(func.hasUWTable()) {
      addTrueField("HasUWTable");
   }
   if(func.needsUnwindTableEntry()) {
      addTrueField("NeedsUnwindTableEntry");
   }
   if(func.hasStructRetAttr()) {
      addTrueField("HasStructRetAttr");
   }
   //TODO: Expose doesNotAlias, doesNotCapture, and getParamAttributes to
   //CLIPS as functions
   char* fnName = (char*)func.getName().data();
   FunctionNamer& namer = getNamer();
   addField("EntryBlock", kc->route(func.getEntryBlock(), fnName, namer));

}
/* Begin C functions for allowing CLIPS to interact with LLVM */
#define msg(x) (char*) x
#define werror msg(werror)
#define name_LLVMFunctionSetGC \
   msg("llvm-function-set-gc")
#define name_LLVMFunctionClearGC \
   msg("llvm-function-clear-gc")
#define name_LLVMFunctionDeleteBody \
   msg("llvm-function-delete-body")
#define name_LLVMFunctionRemoveFromParent \
   msg("llvm-function-remove-from-parent")
#define name_LLVMFunctionEraseFromParent \
   msg("llvm-function-erase-from-parent")
#define name_LLVMFunctionSetDoesNotAccessMemory \
   msg("llvm-function-set-does-not-access-memory")
#define name_LLVMFunctionSetDoesNotAlias \
   msg("llvm-function-set-does-not-alias")
#define name_LLVMFunctionSetDoesNotCapture \
   msg("llvm-function-set-does-not-capture")
#define name_LLVMFunctionSetDoesNotThrow \
   msg("llvm-function-set-does-not-throw")
#define name_LLVMFunctionSetHasUWTable \
   msg("llvm-function-set-has-uw-table")
#define name_LLVMFunctionSetDoesNotReturn \
   msg("llvm-function-set-does-not-return")
#define name_LLVMFunctionSetCannotDuplicate \
   msg("llvm-function-set-cannot-duplicate")
#define name_LLVMFunctionSetOnlyReadsMemory \
   msg("llvm-function-set-only-reads-memory")
/* Getters */
#define name_LLVMFunctionDoesNotAlias \
   msg("llvm-function-does-not-alias")
extern "C" unsigned LLVMFunctionDoesNotAlias(void* theEnv) {
   DATA_OBJECT ptrDO,
               indexDO;
   unsigned index;
   if(EnvArgCountCheck(theEnv, name_LLVMFunctionDoesNotAlias,
            EXACTLY, 2) == -1) {
      return 0;
   }
   if(EnvArgTypeCheck(theEnv, name_LLVMFunctionDoesNotAlias, 1,
            INTEGER, &ptrDO) == FALSE) {
      return 0;
   }
   if(EnvArgTypeCheck(theenv, name_LLVMFunctionDoesNotAlias, 1,
            INTEGER, &indexDO) == FALSE) {
      return 0;
   }
   Function* fn = (Function*)(PointerAddress)DOToLong(ptrDO);
   if(!fn) {
      EnvPrintRouter(theEnv, werror,
            msg("ERROR: The provided function pointer isn't valid"));
      return 0;
   } else {
      index = (unsigned)DOToInteger(indexDO);
      return fn->doesNotAlias(index);
   }
}
#define name_LLVMFunctionDoesNotCapture \
   msg("llvm-function-does-not-capture")
extern "C" unsigned LLVMFunctionDoesNotCapture(void* theEnv) {
   DATA_OBJECT ptrDO,
               indexDO;
   unsigned index;
   if(EnvArgCountCheck(theEnv, name_LLVMFunctionDoesNotCapture,
            EXACTLY, 2) == -1) {
      return 0;
   }
   if(EnvArgTypeCheck(theEnv, name_LLVMFunctionDoesNotCapture, 1,
            INTEGER, &ptrDO) == FALSE) {
      return 0;
   }
   if(EnvArgTypeCheck(theenv, name_LLVMFunctionDoesNotCapture, 1,
            INTEGER, &indexDO) == FALSE) {
      return 0;
   }
   Function* fn = (Function*)(PointerAddress)DOToLong(ptrDO);
   if(!fn) {
      EnvPrintRouter(theEnv, werror,
            msg("ERROR: The provided function pointer isn't valid"));
      return 0;
   } else {
      index = (unsigned)DOToInteger(indexDO);
      return fn->doesNotCapture(index);
   }
}
#define name_LLVMFunctionGetParamAlignment \
   msg("llvm-function-get-param-alignment")
extern "C" unsigned LLVMFunctionGetParamAlignment(void* theEnv) {
   DATA_OBJECT ptrDO,
               indexDO;
   unsigned index;
   if(EnvArgCountCheck(theEnv, name_LLVMFunctionGetParamAlignment,
            EXACTLY, 2) == -1) {
      return 0;
   }
   if(EnvArgTypeCheck(theEnv, name_LLVMFunctionGetParamAlignment, 1,
            INTEGER, &ptrDO) == FALSE) {
      return 0;
   }
   if(EnvArgTypeCheck(theenv, name_LLVMFunctionGetParamAlignment, 1,
            INTEGER, &indexDO) == FALSE) {
      return 0;
   }
   Function* fn = (Function*)(PointerAddress)DOToLong(ptrDO);
   if(!fn) {
      EnvPrintRouter(theEnv, werror,
            msg("ERROR: The provided function pointer isn't valid"));
      return 0;
   } else {
      index = (unsigned)DOToInteger(indexDO);
      return fn->getParamAlignment(index);
   }
}
extern "C" void RegisterLLVMFunctionManipulationFunctions(void *theEnv) {
   EnvDefineFunction(theEnv, name_LLVMFunctionDoesNotCapture, 'i',
         PTIEF LLVMFunctionDoesNotCapture,
         msg("LLVMFunctionDoesNotCapture"));
   EnvDefineFunction(theEnv, name_LLVMFunctionDoesNotAlias, 'i',
         PTIEF LLVMFunctionDoesNotAlias,
         msg("LLVMFunctionDoesNotAlias"));
   EnvDefineFunction(theEnv, name_LLVMFunctionGetParamAlignment, 'i',
         PTIEF LLVMFunctionGetParamAlignment,
         msg("LLVMFunctionGetParamAlignment"));
}
#undef werror
#undef name_LLVMFunctionDoesNotCapture
#undef name_LLVMFunctionDoesNotAlias
#undef name_LLVMFunctionGetParamAlignment
#undef name_LLVMFunctionSetOnlyReadsMemory
#undef name_LLVMFunctionSetGC
#undef name_LLVMFunctionClearGC
#undef name_LLVMFunctionDeleteBody
#undef name_LLVMFunctionRemoveFromParent
#undef name_LLVMFunctionEraseFromParent
#undef name_LLVMFunctionSetDoesNotAccessMemory
#undef name_LLVMFunctionSetDoesNotAlias
#undef name_LLVMFunctionSetDoesNotCapture
#undef name_LLVMFunctionSetDoesNotThrow
#undef name_LLVMFunctionSetHasUWTable
#undef name_LLVMFunctionSetDoesNotReturn
#undef name_LLVMFunctionSetCannotDuplicate
#undef msg
/* End C Interaction Functions */
<commit_msg>Finished implementing addFields in CLIPSFunctionBuilder<commit_after>#include "ExpertSystem/CLIPSFunctionBuilder.h"
extern "C" {
#include "clips.h"
}

CLIPSFunctionBuilder::CLIPSFunctionBuilder(std::string nm,
      FunctionNamer& namer) : CLIPSGlobalValueBuilder(nm, "Function",  namer) {
}

void CLIPSFunctionBuilder::build(Function* fn, KnowledgeConstructor* kc) {
   open();
   addFields(fn, kc);
   close();
   std::string str = getCompletedString();
   kc->addToKnowledgeBase((PointerAddress)arg, str);
}

void CLIPSFunctionBuilder::setCallingConvention(CallingConv::ID id) {
   const char* selection;
   switch(id) {
      case CallingConv::C:
         selection = "C";
         break;
      case CallingConv::Fast:
         selection = "Fast";
         break;
      case CallingConv::Cold:
         selection = "Cold";
         break;
      case CallingConv::GHC:
         selection = "GHC";
         break;
      case CallingConv::HiPE:
         selection = "HiPE";
         break;
      case CallingConv::FirstTargetCC:
         selection = "FirstTargetCC";
         break;
      case CallingConv::X86_StdCall:
         selection = "x86-stdcall";
         break;
      case CallingConv::X86_FastCall:
         selection = "x86-fastcall";
         break;
      case CallingConv::ARM_APCS:
         selection = "arm-apcs";
         break;
      case CallingConv::ARM_AAPCS:
         selection = "arm-aapcs";
         break;
      case CallingConv::ARM_AAPCS_VFB:
         selection = "arm-aapcs-vfb";
         break;
      case CallingConv::MSP430_INTR:
         selection = "msp430-intr";
         break;
      case CallingConv::X86_ThisCall:
         selection = "x86-thiscall";
         break;
      case CallingConv::PTX_Kernel:
         selection = "ptx-kernel";
         break;
      case CallingConv::PTX_Device:
         selection = "ptx-device";
         break;
      case CallingConv::MBLAZE_INTR:
         selection = "mblaze-intr";
         break;
      case CallingConv::MBLAZE_SVOL:
         selection = "mblaze-svol";
         break;
      case CallingConv::SPIR_FUNC:
         selection = "spir-func";
         break;
      case CallingConv::SPIR_KERNEL:
         selection = "spir-kernel";
         break;
      case CallingConv::Intel_OCL_BI:
         selection = "intel-ocl-bi";
         break;
      default:
         selection = "Unknown";
         break;
   }
   addField("CallingConvention", selection);
}
void CLIPSFunctionBuilder::setAttributes(const AttributeSet& attr) {

}
void CLIPSFunctionBuilder::addFields(Function* func,
      KnowledgeConstructor* kc) {

   CLIPSGlobalValueBuilder::addFields(func, kc);
   //this part contains the code for building the function itself
   FunctionNamer& namer = getNamer();
   addField("ReturnType", kc->route(func->getReturnType(), namer));
   addField("FunctionType", kc->route(func->getFunctionType(), namer));
   if(func.isVarArg()) {
      addTrueField("IsVarArg");
   }
   addField("IntrinsicID", func->getIntrinsicID());
   if(func.isIntrinsic()) {
      addTrueField("IsIntrinsic");
   }
   setCallingConvention(func->getCallingConv());
   setAttributes(func->getAttributes());
   if(func.hasGC()) {
      addTrueField("HasGC");
      addField("GC", func->getGC());
   }
   if(func.doesNotAccessMemory()) {
      addTrueField("DoesNotAccessMemory");
   }
   if(func.onlyReadsMemory()) {
      addTrueField("OnlyReadsMemory");
   }
   if(func.doesNotReturn()) {
      addTrueField("DoesNotReturn");
   }
   if(func.cannotDuplicate()) {
      addTrueField("CannotDuplicate");
   }
   if(func.hasUWTable()) {
      addTrueField("HasUWTable");
   }
   if(func.needsUnwindTableEntry()) {
      addTrueField("NeedsUnwindTableEntry");
   }
   if(func.hasStructRetAttr()) {
      addTrueField("HasStructRetAttr");
   }
   if(func.isDefTriviallyDead()) {
      addTrueField("IsDefTriviallyDead");
   }
   if(func.callsFunctionThatReturnsTwice()) {
      addTrueField("CallsFunctionThatReturnsTwice");
   }
   char* fnName = (char*)func.getName().data();
   FunctionNamer& namer = getNamer();
   addField("EntryBlock", kc->route(func.getEntryBlock(), fnName, namer));
   openField("Arguments"); {
      for(Function::arg_iterator s = func.arg_begin(), f = func.arg_end();
            s != f; ++s) {
         Argument* a = s;
         //build it if we need to :)
         appendValue(kc->route(a, namer, fnName));
      }
   } closeField();
   openField("contents"); {
      for(llvm::Function::iterator i = func.begin() , e = func.end();
            i != e; ++i) {
         BasicBlock* bb = i;
         appendValue(kc->route(bb, namer, fnName));
      }
   } closeField();
}
/* Begin C functions for allowing CLIPS to interact with LLVM */
#define msg(x) (char*) x
#define werror msg(werror)
#define name_LLVMFunctionSetGC \
   msg("llvm-function-set-gc")
#define name_LLVMFunctionClearGC \
   msg("llvm-function-clear-gc")
#define name_LLVMFunctionDeleteBody \
   msg("llvm-function-delete-body")
#define name_LLVMFunctionRemoveFromParent \
   msg("llvm-function-remove-from-parent")
#define name_LLVMFunctionEraseFromParent \
   msg("llvm-function-erase-from-parent")
#define name_LLVMFunctionSetDoesNotAccessMemory \
   msg("llvm-function-set-does-not-access-memory")
#define name_LLVMFunctionSetDoesNotAlias \
   msg("llvm-function-set-does-not-alias")
#define name_LLVMFunctionSetDoesNotCapture \
   msg("llvm-function-set-does-not-capture")
#define name_LLVMFunctionSetDoesNotThrow \
   msg("llvm-function-set-does-not-throw")
#define name_LLVMFunctionSetHasUWTable \
   msg("llvm-function-set-has-uw-table")
#define name_LLVMFunctionSetDoesNotReturn \
   msg("llvm-function-set-does-not-return")
#define name_LLVMFunctionSetCannotDuplicate \
   msg("llvm-function-set-cannot-duplicate")
#define name_LLVMFunctionSetOnlyReadsMemory \
   msg("llvm-function-set-only-reads-memory")
#define name_LLVMFunctionDropAllReferences \
   msg("llvm-function-drop-all-references")
#define name_LLVMFunctionHasAddressTaken \
   msg("llvm-function-has-address-taken")
#define name_LLVMFunctionCreate \
   msg("llvm-function-create")
/* Getters */
#define name_LLVMFunctionDoesNotAlias \
   msg("llvm-function-does-not-alias")
extern "C" unsigned LLVMFunctionDoesNotAlias(void* theEnv) {
   DATA_OBJECT ptrDO,
               indexDO;
   unsigned index;
   if(EnvArgCountCheck(theEnv, name_LLVMFunctionDoesNotAlias,
            EXACTLY, 2) == -1) {
      return 0;
   }
   if(EnvArgTypeCheck(theEnv, name_LLVMFunctionDoesNotAlias, 1,
            INTEGER, &ptrDO) == FALSE) {
      return 0;
   }
   if(EnvArgTypeCheck(theenv, name_LLVMFunctionDoesNotAlias, 1,
            INTEGER, &indexDO) == FALSE) {
      return 0;
   }
   Function* fn = (Function*)(PointerAddress)DOToLong(ptrDO);
   if(!fn) {
      EnvPrintRouter(theEnv, werror,
            msg("ERROR: The provided function pointer isn't valid"));
      return 0;
   } else {
      index = (unsigned)DOToInteger(indexDO);
      return fn->doesNotAlias(index);
   }
}
#define name_LLVMFunctionDoesNotCapture \
   msg("llvm-function-does-not-capture")
extern "C" unsigned LLVMFunctionDoesNotCapture(void* theEnv) {
   DATA_OBJECT ptrDO,
               indexDO;
   unsigned index;
   if(EnvArgCountCheck(theEnv, name_LLVMFunctionDoesNotCapture,
            EXACTLY, 2) == -1) {
      return 0;
   }
   if(EnvArgTypeCheck(theEnv, name_LLVMFunctionDoesNotCapture, 1,
            INTEGER, &ptrDO) == FALSE) {
      return 0;
   }
   if(EnvArgTypeCheck(theenv, name_LLVMFunctionDoesNotCapture, 1,
            INTEGER, &indexDO) == FALSE) {
      return 0;
   }
   Function* fn = (Function*)(PointerAddress)DOToLong(ptrDO);
   if(!fn) {
      EnvPrintRouter(theEnv, werror,
            msg("ERROR: The provided function pointer isn't valid"));
      return 0;
   } else {
      index = (unsigned)DOToInteger(indexDO);
      return fn->doesNotCapture(index);
   }
}
#define name_LLVMFunctionGetParamAlignment \
   msg("llvm-function-get-param-alignment")
extern "C" unsigned LLVMFunctionGetParamAlignment(void* theEnv) {
   DATA_OBJECT ptrDO,
               indexDO;
   unsigned index;
   if(EnvArgCountCheck(theEnv, name_LLVMFunctionGetParamAlignment,
            EXACTLY, 2) == -1) {
      return 0;
   }
   if(EnvArgTypeCheck(theEnv, name_LLVMFunctionGetParamAlignment, 1,
            INTEGER, &ptrDO) == FALSE) {
      return 0;
   }
   if(EnvArgTypeCheck(theenv, name_LLVMFunctionGetParamAlignment, 1,
            INTEGER, &indexDO) == FALSE) {
      return 0;
   }
   Function* fn = (Function*)(PointerAddress)DOToLong(ptrDO);
   if(!fn) {
      EnvPrintRouter(theEnv, werror,
            msg("ERROR: The provided function pointer isn't valid"));
      return 0;
   } else {
      index = (unsigned)DOToInteger(indexDO);
      return fn->getParamAlignment(index);
   }
}
extern "C" void RegisterLLVMFunctionManipulationFunctions(void *theEnv) {
   EnvDefineFunction(theEnv, name_LLVMFunctionDoesNotCapture, 'i',
         PTIEF LLVMFunctionDoesNotCapture,
         msg("LLVMFunctionDoesNotCapture"));
   EnvDefineFunction(theEnv, name_LLVMFunctionDoesNotAlias, 'i',
         PTIEF LLVMFunctionDoesNotAlias,
         msg("LLVMFunctionDoesNotAlias"));
   EnvDefineFunction(theEnv, name_LLVMFunctionGetParamAlignment, 'i',
         PTIEF LLVMFunctionGetParamAlignment,
         msg("LLVMFunctionGetParamAlignment"));
}
#undef werror
#undef name_LLVMFunctionDoesNotCapture
#undef name_LLVMFunctionDoesNotAlias
#undef name_LLVMFunctionGetParamAlignment
#undef name_LLVMFunctionSetOnlyReadsMemory
#undef name_LLVMFunctionSetGC
#undef name_LLVMFunctionClearGC
#undef name_LLVMFunctionDeleteBody
#undef name_LLVMFunctionRemoveFromParent
#undef name_LLVMFunctionEraseFromParent
#undef name_LLVMFunctionSetDoesNotAccessMemory
#undef name_LLVMFunctionSetDoesNotAlias
#undef name_LLVMFunctionSetDoesNotCapture
#undef name_LLVMFunctionSetDoesNotThrow
#undef name_LLVMFunctionSetHasUWTable
#undef name_LLVMFunctionSetDoesNotReturn
#undef name_LLVMFunctionSetCannotDuplicate
#undef name_LLVMFunctionDropAllReferences
#undef name_LLVMFunctionHasAddressTaken
#undef name_LLVMFunctionCreate
#undef msg
/* End C Interaction Functions */
<|endoftext|>


<commit_before>// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX - License - Identifier: Apache - 2.0

#include <iostream>
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/CopyObjectRequest.h>
#include <awsdoc/s3/s3_examples.h>
/* ////////////////////////////////////////////////////////////////////////////
 * Purpose:
 *
 * Prerequisites:
 *
 * Inputs:
 * - :
 *
 * Outputs:
 * ///////////////////////////////////////////////////////////////////////// */
/* ////////////////////////////////////////////////////////////////////////////
 * Purpose: Copies an object from one bucket in Amazon S3 to another bucket.
 *
 * Prerequisites: Two buckets. One of the buckets must contain the object to
 * be copied to the other bucket.
 *
 * Inputs:
 * - objectKey: The name of the object to copy.
 * - fromBucket: The name of the bucket to copy the object from.
 * - toBucket: The name of the bucket to copy the object to.
 * - region: The AWS Region to create the bucket in.
 *
 * Outputs: true if the object was copied; otherwise, false.
 * ///////////////////////////////////////////////////////////////////////// */

bool AwsDoc::S3::CopyObject(const Aws::String& objectKey,
    const Aws::String& fromBucket, const Aws::String& toBucket, const Aws::String& region)
{
    Aws::Client::ClientConfiguration config;

    if (!region.empty())
    {
        config.region = region;
    }

    Aws::S3::S3Client s3_client(config);

    Aws::S3::Model::CopyObjectRequest request;

    request.WithCopySource(fromBucket + "/" + objectKey)
        .WithKey(objectKey)
        .WithBucket(toBucket);

    Aws::S3::Model::CopyObjectOutcome outcome = s3_client.CopyObject(request);

    if (!outcome.IsSuccess())
    {
        auto err = outcome.GetError();
        std::cout << "Error: CopyObject: " <<
            err.GetExceptionName() << ": " << err.GetMessage() << std::endl;

        return false;
    }
    else
    {
        return true;
    }
}

int main()
{
    Aws::SDKOptions options;
    Aws::InitAPI(options);
    {
        //TODO: Name of object already in bucket.
        Aws::String object_key = "my-file.txt";
        //TODO: Change from_bucket to the name of your bucket that already contains "my-file.txt".
        //See create_bucket.cpp and put_object.cpp to create a bucket and load an object into that bucket.
        Aws::String from_bucket = "MY-FROM-BUCKET";
        //TODO: Change to the name of another bucket in your account.
        Aws::String to_bucket = "MY-TO-BUCKET";
        //TODO: Set to the AWS Region in which the bucket was created.
        Aws::String region = "us-east-1";

        if (AwsDoc::S3::CopyObject(object_key, from_bucket, to_bucket, region))
        {
            std::cout << "Copied object '" << object_key <<
                "' from '" << from_bucket << "' to '" << to_bucket << "'." <<
                std::endl;
        }
        else
        {
            return 1;
        }
    }
    ShutdownAPI(options);

    return 0;
}<commit_msg>add comments<commit_after>// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX - License - Identifier: Apache - 2.0

#include <iostream>
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/CopyObjectRequest.h>
#include <awsdoc/s3/s3_examples.h>

/* ////////////////////////////////////////////////////////////////////////////
 * Purpose: Copies an object from one bucket in Amazon S3 to another bucket.
 *
 * Prerequisites: Two buckets. One of the buckets must contain the object to
 * be copied to the other bucket.
 *
 * Inputs:
 * - objectKey: The name of the object to copy.
 * - fromBucket: The name of the bucket to copy the object from.
 * - toBucket: The name of the bucket to copy the object to.
 * - region: The AWS Region to create the bucket in.
 *
 * Outputs: true if the object was copied; otherwise, false.
 * ///////////////////////////////////////////////////////////////////////// */

bool AwsDoc::S3::CopyObject(const Aws::String& objectKey,
    const Aws::String& fromBucket, const Aws::String& toBucket, const Aws::String& region)
{
    Aws::Client::ClientConfiguration config;

    if (!region.empty())
    {
        config.region = region;
    }

    Aws::S3::S3Client s3_client(config);

    Aws::S3::Model::CopyObjectRequest request;

    request.WithCopySource(fromBucket + "/" + objectKey)
        .WithKey(objectKey)
        .WithBucket(toBucket);

    Aws::S3::Model::CopyObjectOutcome outcome = s3_client.CopyObject(request);

    if (!outcome.IsSuccess())
    {
        auto err = outcome.GetError();
        std::cout << "Error: CopyObject: " <<
            err.GetExceptionName() << ": " << err.GetMessage() << std::endl;

        return false;
    }
    else
    {
        return true;
    }
}

int main()
{
    Aws::SDKOptions options;
    Aws::InitAPI(options);
    {
        //TODO: Name of object already in bucket.
        Aws::String object_key = "my-file.txt";
        //TODO: Change from_bucket to the name of your bucket that already contains "my-file.txt".
        //See create_bucket.cpp and put_object.cpp to create a bucket and load an object into that bucket.
        Aws::String from_bucket = "MY-FROM-BUCKET";
        //TODO: Change to the name of another bucket in your account.
        Aws::String to_bucket = "MY-TO-BUCKET";
        //TODO: Set to the AWS Region in which the bucket was created.
        Aws::String region = "us-east-1";

        if (AwsDoc::S3::CopyObject(object_key, from_bucket, to_bucket, region))
        {
            std::cout << "Copied object '" << object_key <<
                "' from '" << from_bucket << "' to '" << to_bucket << "'." <<
                std::endl;
        }
        else
        {
            return 1;
        }
    }
    ShutdownAPI(options);

    return 0;
}<|endoftext|>


<commit_before>#include "HalideRuntime.h"
#include "HalideBuffer.h"

// Grab the internal device_interface functions
#define WEAK
#include "device_interface.h"

#include <stdio.h>
#include <stdlib.h>

#include "cleanup_on_error.h"

using namespace Halide::Runtime;

const int size = 64;

int successful_mallocs = 0, failed_mallocs = 0, frees = 0, errors = 0, device_mallocs = 0, device_frees = 0;

void *my_halide_malloc(void *user_context, size_t x) {
    // Only the first malloc succeeds
    if (successful_mallocs) {
        failed_mallocs++;
        return nullptr;
    }
    successful_mallocs++;

    void *orig = malloc(x+40);
    // Round up to next multiple of 32. Should add at least 8 bytes so we can fit the original pointer.
    void *ptr = (void *)((((size_t)orig + 32) >> 5) << 5);
    ((void **)ptr)[-1] = orig;
    return ptr;
}

void my_halide_free(void *user_context, void *ptr) {
    frees++;
    free(((void**)ptr)[-1]);
}

void my_halide_error(void *user_context, const char *msg) {
    errors++;
}

#ifndef _WIN32
// These two can't be overridden on windows, so we'll just check that
// the number of calls to free matches the number of calls to malloc.
extern "C" int halide_device_free(void *user_context, struct buffer_t *buf) {
    device_frees++;
    const halide_device_interface_t *interface = halide_get_device_interface(buf->dev);
    return interface->device_free(user_context, buf);
}

extern "C" int halide_device_malloc(void *user_context, struct buffer_t *buf, const halide_device_interface_t *interface) {
    if (!buf->dev) {
        printf("Custom device malloc!\n");
        device_mallocs++;
    }
    return interface->device_malloc(user_context, buf);
}
#endif

int main(int argc, char **argv) {

    halide_set_custom_malloc(&my_halide_malloc);
    halide_set_custom_free(&my_halide_free);
    halide_set_error_handler(&my_halide_error);

    Buffer<int32_t> output(size);
    int result = cleanup_on_error(output);

    if (result != halide_error_code_out_of_memory) {
        printf("The exit status was %d instead of %d\n", result, halide_error_code_out_of_memory);
        return -1;
    }

    if (failed_mallocs != 1) {
        printf("One of the mallocs was supposed to fail\n");
        return -1;
    }

    if (successful_mallocs != 1) {
        printf("One of the mallocs was supposed to succeed\n");
        return -1;
    }

    if (frees != 1) {
        printf("The successful malloc should have been freed\n");
        return -1;
    }

    if (errors != 1) {
        // There's one error from the malloc failing
        printf("There was supposed to be one error\n");
        return -1;
    }

    if (device_mallocs != device_frees) {
        printf("There were a different number of device mallocs (%d) and frees (%d)\n", device_mallocs, device_frees);
        return -1;
    }

    printf("Success!\n");
    return 0;
}
<commit_msg>Remove debugging printf<commit_after>#include "HalideRuntime.h"
#include "HalideBuffer.h"

// Grab the internal device_interface functions
#define WEAK
#include "device_interface.h"

#include <stdio.h>
#include <stdlib.h>

#include "cleanup_on_error.h"

using namespace Halide::Runtime;

const int size = 64;

int successful_mallocs = 0, failed_mallocs = 0, frees = 0, errors = 0, device_mallocs = 0, device_frees = 0;

void *my_halide_malloc(void *user_context, size_t x) {
    // Only the first malloc succeeds
    if (successful_mallocs) {
        failed_mallocs++;
        return nullptr;
    }
    successful_mallocs++;

    void *orig = malloc(x+40);
    // Round up to next multiple of 32. Should add at least 8 bytes so we can fit the original pointer.
    void *ptr = (void *)((((size_t)orig + 32) >> 5) << 5);
    ((void **)ptr)[-1] = orig;
    return ptr;
}

void my_halide_free(void *user_context, void *ptr) {
    frees++;
    free(((void**)ptr)[-1]);
}

void my_halide_error(void *user_context, const char *msg) {
    errors++;
}

#ifndef _WIN32
// These two can't be overridden on windows, so we'll just check that
// the number of calls to free matches the number of calls to malloc.
extern "C" int halide_device_free(void *user_context, struct buffer_t *buf) {
    device_frees++;
    const halide_device_interface_t *interface = halide_get_device_interface(buf->dev);
    return interface->device_free(user_context, buf);
}

extern "C" int halide_device_malloc(void *user_context, struct buffer_t *buf, const halide_device_interface_t *interface) {
    if (!buf->dev) {
        device_mallocs++;
    }
    return interface->device_malloc(user_context, buf);
}
#endif

int main(int argc, char **argv) {

    halide_set_custom_malloc(&my_halide_malloc);
    halide_set_custom_free(&my_halide_free);
    halide_set_error_handler(&my_halide_error);

    Buffer<int32_t> output(size);
    int result = cleanup_on_error(output);

    if (result != halide_error_code_out_of_memory) {
        printf("The exit status was %d instead of %d\n", result, halide_error_code_out_of_memory);
        return -1;
    }

    if (failed_mallocs != 1) {
        printf("One of the mallocs was supposed to fail\n");
        return -1;
    }

    if (successful_mallocs != 1) {
        printf("One of the mallocs was supposed to succeed\n");
        return -1;
    }

    if (frees != 1) {
        printf("The successful malloc should have been freed\n");
        return -1;
    }

    if (errors != 1) {
        // There's one error from the malloc failing
        printf("There was supposed to be one error\n");
        return -1;
    }

    if (device_mallocs != device_frees) {
        printf("There were a different number of device mallocs (%d) and frees (%d)\n", device_mallocs, device_frees);
        return -1;
    }

    printf("Success!\n");
    return 0;
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "update_statement.hh"
#include "raw/update_statement.hh"
#include "raw/insert_statement.hh"
#include "unimplemented.hh"

#include "cql3/operation_impl.hh"

namespace cql3 {

namespace statements {

update_statement::update_statement(statement_type type, uint32_t bound_terms, schema_ptr s, std::unique_ptr<attributes> attrs, uint64_t* cql_stats_counter_ptr)
    : modification_statement{type, bound_terms, std::move(s), std::move(attrs), cql_stats_counter_ptr}
{ }

bool update_statement::require_full_clustering_key() const {
    return true;
}

bool update_statement::allow_clustering_key_slices() const {
    return false;
}

void update_statement::add_update_for_key(mutation& m, const query::clustering_range& range, const update_parameters& params) {
    auto prefix = range.start() ? std::move(range.start()->value()) : clustering_key_prefix::make_empty();
    if (s->is_dense()) {
        if (prefix.is_empty(*s)) {
            throw exceptions::invalid_request_exception(sprint("Missing PRIMARY KEY part %s", s->clustering_key_columns().begin()->name_as_text()));
        }
        // An empty name for the value is what we use to recognize the case where there is not column
        // outside the PK, see CreateStatement.
        if (s->regular_begin()->name().empty()) {
            // There is no column outside the PK. So no operation could have passed through validation
            assert(_column_operations.empty());
            constants::setter(*s->regular_begin(), make_shared(constants::value(cql3::raw_value::make_value(bytes())))).execute(m, prefix, params);
        } else {
            // dense means we don't have a row marker, so don't accept to set only the PK. See CASSANDRA-5648.
            if (_column_operations.empty()) {
                throw exceptions::invalid_request_exception(sprint("Column %s is mandatory for this COMPACT STORAGE table", s->regular_begin()->name_as_text()));
            }
        }
    } else {
        // If there are static columns, there also must be clustering columns, in which
        // case empty prefix can only refer to the static row.
        bool is_static_prefix = s->has_static_columns() && prefix.is_empty(*s);
        if (type.is_insert() && !is_static_prefix && s->is_cql3_table()) {
            auto& row = m.partition().clustered_row(*s, prefix);
            row.apply(row_marker(params.timestamp(), params.ttl(), params.expiry()));
        }
    }

    for (auto&& update : _column_operations) {
        update->execute(m, prefix, params);
    }

    warn(unimplemented::cause::INDEXES);
#if 0
        SecondaryIndexManager indexManager = Keyspace.open(cfm.ksName).getColumnFamilyStore(cfm.cfId).indexManager;
        if (indexManager.hasIndexes())
        {
            for (Cell cell : cf)
            {
                // Indexed values must be validated by any applicable index. See CASSANDRA-3057/4240/8081 for more details
                if (!indexManager.validate(cell))
                    throw new InvalidRequestException(String.format("Can't index column value of size %d for index %s on %s.%s",
                                                                    cell.value().remaining(),
                                                                    cfm.getColumnDefinition(cell.name()).getIndexName(),
                                                                    cfm.ksName,
                                                                    cfm.cfName));
            }
        }
    }
#endif
}

namespace raw {

insert_statement::insert_statement(            ::shared_ptr<cf_name> name,
                                               ::shared_ptr<attributes::raw> attrs,
                                               std::vector<::shared_ptr<column_identifier::raw>> column_names,
                                               std::vector<::shared_ptr<term::raw>> column_values,
                                               bool if_not_exists)
    : raw::modification_statement{std::move(name), std::move(attrs), conditions_vector{}, if_not_exists, false}
    , _column_names{std::move(column_names)}
    , _column_values{std::move(column_values)}
{ }

::shared_ptr<cql3::statements::modification_statement>
insert_statement::prepare_internal(database& db, schema_ptr schema,
    ::shared_ptr<variable_specifications> bound_names, std::unique_ptr<attributes> attrs, cql_stats& stats)
{
    auto stmt = ::make_shared<cql3::statements::update_statement>(statement_type::INSERT, bound_names->size(), schema, std::move(attrs), &stats.inserts);

    // Created from an INSERT
    if (stmt->is_counter()) {
        throw exceptions::invalid_request_exception("INSERT statement are not allowed on counter tables, use UPDATE instead");
    }

    if (_column_names.size() != _column_values.size()) {
        throw exceptions::invalid_request_exception("Unmatched column names/values");
    }

    if (_column_names.empty()) {
        throw exceptions::invalid_request_exception("No columns provided to INSERT");
    }

    std::vector<::shared_ptr<relation>> relations;
    std::unordered_set<bytes> column_ids;
    for (size_t i = 0; i < _column_names.size(); i++) {
        auto&& col = _column_names[i];
        auto id = col->prepare_column_identifier(schema);
        auto def = get_column_definition(schema, *id);
        if (!def) {
            throw exceptions::invalid_request_exception(sprint("Unknown identifier %s", *id));
        }
        if (column_ids.count(id->name())) {
            throw exceptions::invalid_request_exception(sprint("Multiple definitions found for column %s", *id));
        }
        column_ids.emplace(id->name());

        auto&& value = _column_values[i];

        if (def->is_primary_key()) {
            relations.push_back(::make_shared<single_column_relation>(col, operator_type::EQ, value));
        } else {
            auto operation = operation::set_value(value).prepare(db, keyspace(), *def);
            operation->collect_marker_specification(bound_names);
            stmt->add_operation(std::move(operation));
        };
    }
    stmt->process_where_clause(db, relations, std::move(bound_names));
    return stmt;
}

update_statement::update_statement(            ::shared_ptr<cf_name> name,
                                               ::shared_ptr<attributes::raw> attrs,
                                               std::vector<std::pair<::shared_ptr<column_identifier::raw>, ::shared_ptr<operation::raw_update>>> updates,
                                               std::vector<relation_ptr> where_clause,
                                               conditions_vector conditions)
    : raw::modification_statement(std::move(name), std::move(attrs), std::move(conditions), false, false)
    , _updates(std::move(updates))
    , _where_clause(std::move(where_clause))
{ }

::shared_ptr<cql3::statements::modification_statement>
update_statement::prepare_internal(database& db, schema_ptr schema,
    ::shared_ptr<variable_specifications> bound_names, std::unique_ptr<attributes> attrs, cql_stats& stats)
{
    auto stmt = ::make_shared<cql3::statements::update_statement>(statement_type::UPDATE, bound_names->size(), schema, std::move(attrs), &stats.updates);

    for (auto&& entry : _updates) {
        auto id = entry.first->prepare_column_identifier(schema);
        auto def = get_column_definition(schema, *id);
        if (!def) {
            throw exceptions::invalid_request_exception(sprint("Unknown identifier %s", *entry.first));
        }

        auto operation = entry.second->prepare(db, keyspace(), *def);
        operation->collect_marker_specification(bound_names);

        if (def->is_primary_key()) {
            throw exceptions::invalid_request_exception(sprint("PRIMARY KEY part %s found in SET part", *entry.first));
        }
        stmt->add_operation(std::move(operation));
    }

    stmt->process_where_clause(db, _where_clause, std::move(bound_names));
    return stmt;
}

}

}

}
<commit_msg>update_statement: Reject empty values for dense clustering key<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "update_statement.hh"
#include "raw/update_statement.hh"
#include "raw/insert_statement.hh"
#include "unimplemented.hh"

#include "cql3/operation_impl.hh"

namespace cql3 {

namespace statements {

update_statement::update_statement(statement_type type, uint32_t bound_terms, schema_ptr s, std::unique_ptr<attributes> attrs, uint64_t* cql_stats_counter_ptr)
    : modification_statement{type, bound_terms, std::move(s), std::move(attrs), cql_stats_counter_ptr}
{ }

bool update_statement::require_full_clustering_key() const {
    return true;
}

bool update_statement::allow_clustering_key_slices() const {
    return false;
}

void update_statement::add_update_for_key(mutation& m, const query::clustering_range& range, const update_parameters& params) {
    auto prefix = range.start() ? std::move(range.start()->value()) : clustering_key_prefix::make_empty();
    if (s->is_dense()) {
        if (prefix.is_empty(*s) || prefix.components().front().empty()) {
            throw exceptions::invalid_request_exception(sprint("Missing PRIMARY KEY part %s", s->clustering_key_columns().begin()->name_as_text()));
        }
        // An empty name for the value is what we use to recognize the case where there is not column
        // outside the PK, see CreateStatement.
        if (s->regular_begin()->name().empty()) {
            // There is no column outside the PK. So no operation could have passed through validation
            assert(_column_operations.empty());
            constants::setter(*s->regular_begin(), make_shared(constants::value(cql3::raw_value::make_value(bytes())))).execute(m, prefix, params);
        } else {
            // dense means we don't have a row marker, so don't accept to set only the PK. See CASSANDRA-5648.
            if (_column_operations.empty()) {
                throw exceptions::invalid_request_exception(sprint("Column %s is mandatory for this COMPACT STORAGE table", s->regular_begin()->name_as_text()));
            }
        }
    } else {
        // If there are static columns, there also must be clustering columns, in which
        // case empty prefix can only refer to the static row.
        bool is_static_prefix = s->has_static_columns() && prefix.is_empty(*s);
        if (type.is_insert() && !is_static_prefix && s->is_cql3_table()) {
            auto& row = m.partition().clustered_row(*s, prefix);
            row.apply(row_marker(params.timestamp(), params.ttl(), params.expiry()));
        }
    }

    for (auto&& update : _column_operations) {
        update->execute(m, prefix, params);
    }

    warn(unimplemented::cause::INDEXES);
#if 0
        SecondaryIndexManager indexManager = Keyspace.open(cfm.ksName).getColumnFamilyStore(cfm.cfId).indexManager;
        if (indexManager.hasIndexes())
        {
            for (Cell cell : cf)
            {
                // Indexed values must be validated by any applicable index. See CASSANDRA-3057/4240/8081 for more details
                if (!indexManager.validate(cell))
                    throw new InvalidRequestException(String.format("Can't index column value of size %d for index %s on %s.%s",
                                                                    cell.value().remaining(),
                                                                    cfm.getColumnDefinition(cell.name()).getIndexName(),
                                                                    cfm.ksName,
                                                                    cfm.cfName));
            }
        }
    }
#endif
}

namespace raw {

insert_statement::insert_statement(            ::shared_ptr<cf_name> name,
                                               ::shared_ptr<attributes::raw> attrs,
                                               std::vector<::shared_ptr<column_identifier::raw>> column_names,
                                               std::vector<::shared_ptr<term::raw>> column_values,
                                               bool if_not_exists)
    : raw::modification_statement{std::move(name), std::move(attrs), conditions_vector{}, if_not_exists, false}
    , _column_names{std::move(column_names)}
    , _column_values{std::move(column_values)}
{ }

::shared_ptr<cql3::statements::modification_statement>
insert_statement::prepare_internal(database& db, schema_ptr schema,
    ::shared_ptr<variable_specifications> bound_names, std::unique_ptr<attributes> attrs, cql_stats& stats)
{
    auto stmt = ::make_shared<cql3::statements::update_statement>(statement_type::INSERT, bound_names->size(), schema, std::move(attrs), &stats.inserts);

    // Created from an INSERT
    if (stmt->is_counter()) {
        throw exceptions::invalid_request_exception("INSERT statement are not allowed on counter tables, use UPDATE instead");
    }

    if (_column_names.size() != _column_values.size()) {
        throw exceptions::invalid_request_exception("Unmatched column names/values");
    }

    if (_column_names.empty()) {
        throw exceptions::invalid_request_exception("No columns provided to INSERT");
    }

    std::vector<::shared_ptr<relation>> relations;
    std::unordered_set<bytes> column_ids;
    for (size_t i = 0; i < _column_names.size(); i++) {
        auto&& col = _column_names[i];
        auto id = col->prepare_column_identifier(schema);
        auto def = get_column_definition(schema, *id);
        if (!def) {
            throw exceptions::invalid_request_exception(sprint("Unknown identifier %s", *id));
        }
        if (column_ids.count(id->name())) {
            throw exceptions::invalid_request_exception(sprint("Multiple definitions found for column %s", *id));
        }
        column_ids.emplace(id->name());

        auto&& value = _column_values[i];

        if (def->is_primary_key()) {
            relations.push_back(::make_shared<single_column_relation>(col, operator_type::EQ, value));
        } else {
            auto operation = operation::set_value(value).prepare(db, keyspace(), *def);
            operation->collect_marker_specification(bound_names);
            stmt->add_operation(std::move(operation));
        };
    }
    stmt->process_where_clause(db, relations, std::move(bound_names));
    return stmt;
}

update_statement::update_statement(            ::shared_ptr<cf_name> name,
                                               ::shared_ptr<attributes::raw> attrs,
                                               std::vector<std::pair<::shared_ptr<column_identifier::raw>, ::shared_ptr<operation::raw_update>>> updates,
                                               std::vector<relation_ptr> where_clause,
                                               conditions_vector conditions)
    : raw::modification_statement(std::move(name), std::move(attrs), std::move(conditions), false, false)
    , _updates(std::move(updates))
    , _where_clause(std::move(where_clause))
{ }

::shared_ptr<cql3::statements::modification_statement>
update_statement::prepare_internal(database& db, schema_ptr schema,
    ::shared_ptr<variable_specifications> bound_names, std::unique_ptr<attributes> attrs, cql_stats& stats)
{
    auto stmt = ::make_shared<cql3::statements::update_statement>(statement_type::UPDATE, bound_names->size(), schema, std::move(attrs), &stats.updates);

    for (auto&& entry : _updates) {
        auto id = entry.first->prepare_column_identifier(schema);
        auto def = get_column_definition(schema, *id);
        if (!def) {
            throw exceptions::invalid_request_exception(sprint("Unknown identifier %s", *entry.first));
        }

        auto operation = entry.second->prepare(db, keyspace(), *def);
        operation->collect_marker_specification(bound_names);

        if (def->is_primary_key()) {
            throw exceptions::invalid_request_exception(sprint("PRIMARY KEY part %s found in SET part", *entry.first));
        }
        stmt->add_operation(std::move(operation));
    }

    stmt->process_where_clause(db, _where_clause, std::move(bound_names));
    return stmt;
}

}

}

}
<|endoftext|>


<commit_before>//===- LowerAllocations.cpp - Reduce malloc & free insts to calls ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The LowerAllocations transformation is a target-dependent tranformation
// because it depends on the size of data types and alignment constraints.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/iMemory.h"
#include "llvm/iOther.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/Target/TargetData.h"
#include "Support/Statistic.h"
using namespace llvm;

namespace {
  Statistic<> NumLowered("lowerallocs", "Number of allocations lowered");

  /// LowerAllocations - Turn malloc and free instructions into %malloc and
  /// %free calls.
  ///
  class LowerAllocations : public BasicBlockPass {
    Function *MallocFunc;   // Functions in the module we are processing
    Function *FreeFunc;     // Initialized by doInitialization
  public:
    LowerAllocations() : MallocFunc(0), FreeFunc(0) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<TargetData>();
    }

    /// doPassInitialization - For the lower allocations pass, this ensures that
    /// a module contains a declaration for a malloc and a free function.
    ///
    bool doInitialization(Module &M);

    /// runOnBasicBlock - This method does the actual work of converting
    /// instructions over, assuming that the pass has already been initialized.
    ///
    bool runOnBasicBlock(BasicBlock &BB);
  };

  RegisterOpt<LowerAllocations>
  X("lowerallocs", "Lower allocations from instructions to calls");
}

// createLowerAllocationsPass - Interface to this file...
FunctionPass *llvm::createLowerAllocationsPass() {
  return new LowerAllocations();
}

// doInitialization - For the lower allocations pass, this ensures that a
// module contains a declaration for a malloc and a free function.
//
// This function is always successful.
//
bool LowerAllocations::doInitialization(Module &M) {
  const Type *SBPTy = PointerType::get(Type::SByteTy);
  MallocFunc = M.getNamedFunction("malloc");
  FreeFunc   = M.getNamedFunction("free");

  if (MallocFunc == 0)
    MallocFunc = M.getOrInsertFunction("malloc", SBPTy, Type::UIntTy, 0);
  if (FreeFunc == 0)
    FreeFunc   = M.getOrInsertFunction("free"  , Type::VoidTy, SBPTy, 0);

  return true;
}

// runOnBasicBlock - This method does the actual work of converting
// instructions over, assuming that the pass has already been initialized.
//
bool LowerAllocations::runOnBasicBlock(BasicBlock &BB) {
  bool Changed = false;
  assert(MallocFunc && FreeFunc && "Pass not initialized!");

  BasicBlock::InstListType &BBIL = BB.getInstList();
  TargetData &DataLayout = getAnalysis<TargetData>();

  // Loop over all of the instructions, looking for malloc or free instructions
  for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) {
    if (MallocInst *MI = dyn_cast<MallocInst>(I)) {
      const Type *AllocTy = MI->getType()->getElementType();

      // Get the number of bytes to be allocated for one element of the
      // requested type...
      unsigned Size = DataLayout.getTypeSize(AllocTy);

      // malloc(type) becomes sbyte *malloc(constint)
      Value *MallocArg = ConstantUInt::get(Type::UIntTy, Size);
      if (MI->getNumOperands() && Size == 1) {
        MallocArg = MI->getOperand(0);         // Operand * 1 = Operand
      } else if (MI->getNumOperands()) {
        // Multiply it by the array size if necessary...
        MallocArg = BinaryOperator::create(Instruction::Mul, MI->getOperand(0),
                                           MallocArg, "", I);
      }

      const FunctionType *MallocFTy = MallocFunc->getFunctionType();
      std::vector<Value*> MallocArgs;

      if (MallocFTy->getNumParams() > 0 || MallocFTy->isVarArg()) {
        if (MallocFTy->getNumParams() > 0 &&
            MallocFTy->getParamType(0) != Type::UIntTy)
          MallocArg = new CastInst(MallocArg, MallocFTy->getParamType(0), "",I);
        MallocArgs.push_back(MallocArg);
      }

      // If malloc is prototyped to take extra arguments, pass nulls.
      for (unsigned i = 1; i < MallocFTy->getNumParams(); ++i)
       MallocArgs.push_back(Constant::getNullValue(MallocFTy->getParamType(i)));

      // Create the call to Malloc...
      CallInst *MCall = new CallInst(MallocFunc, MallocArgs, "", I);

      // Create a cast instruction to convert to the right type...
      Value *MCast;
      if (MCall->getType() != Type::VoidTy)
        MCast = new CastInst(MCall, MI->getType(), "", I);
      else
        MCast = Constant::getNullValue(MI->getType());

      // Replace all uses of the old malloc inst with the cast inst
      MI->replaceAllUsesWith(MCast);
      I = --BBIL.erase(I);         // remove and delete the malloc instr...
      Changed = true;
      ++NumLowered;
    } else if (FreeInst *FI = dyn_cast<FreeInst>(I)) {
      const FunctionType *FreeFTy = FreeFunc->getFunctionType();
      std::vector<Value*> FreeArgs;

      if (FreeFTy->getNumParams() > 0 || FreeFTy->isVarArg()) {
        Value *MCast = FI->getOperand(0);
        if (FreeFTy->getNumParams() > 0 &&
            FreeFTy->getParamType(0) != MCast->getType())
          MCast = new CastInst(MCast, FreeFTy->getParamType(0), "", I);
        FreeArgs.push_back(MCast);
      }

      // If malloc is prototyped to take extra arguments, pass nulls.
      for (unsigned i = 1; i < FreeFTy->getNumParams(); ++i)
       FreeArgs.push_back(Constant::getNullValue(FreeFTy->getParamType(i)));

      // Insert a call to the free function...
      new CallInst(FreeFunc, FreeArgs, "", I);

      // Delete the old free instruction
      I = --BBIL.erase(I);
      Changed = true;
      ++NumLowered;
    }
  }

  return Changed;
}

<commit_msg>Don't emit things like malloc(16*1).  Allocation instructions are fixed arity now.<commit_after>//===- LowerAllocations.cpp - Reduce malloc & free insts to calls ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The LowerAllocations transformation is a target-dependent tranformation
// because it depends on the size of data types and alignment constraints.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/iMemory.h"
#include "llvm/iOther.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
#include "llvm/Target/TargetData.h"
#include "Support/Statistic.h"
using namespace llvm;

namespace {
  Statistic<> NumLowered("lowerallocs", "Number of allocations lowered");

  /// LowerAllocations - Turn malloc and free instructions into %malloc and
  /// %free calls.
  ///
  class LowerAllocations : public BasicBlockPass {
    Function *MallocFunc;   // Functions in the module we are processing
    Function *FreeFunc;     // Initialized by doInitialization
  public:
    LowerAllocations() : MallocFunc(0), FreeFunc(0) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<TargetData>();
    }

    /// doPassInitialization - For the lower allocations pass, this ensures that
    /// a module contains a declaration for a malloc and a free function.
    ///
    bool doInitialization(Module &M);

    /// runOnBasicBlock - This method does the actual work of converting
    /// instructions over, assuming that the pass has already been initialized.
    ///
    bool runOnBasicBlock(BasicBlock &BB);
  };

  RegisterOpt<LowerAllocations>
  X("lowerallocs", "Lower allocations from instructions to calls");
}

// createLowerAllocationsPass - Interface to this file...
FunctionPass *llvm::createLowerAllocationsPass() {
  return new LowerAllocations();
}

// doInitialization - For the lower allocations pass, this ensures that a
// module contains a declaration for a malloc and a free function.
//
// This function is always successful.
//
bool LowerAllocations::doInitialization(Module &M) {
  const Type *SBPTy = PointerType::get(Type::SByteTy);
  MallocFunc = M.getNamedFunction("malloc");
  FreeFunc   = M.getNamedFunction("free");

  if (MallocFunc == 0)
    MallocFunc = M.getOrInsertFunction("malloc", SBPTy, Type::UIntTy, 0);
  if (FreeFunc == 0)
    FreeFunc   = M.getOrInsertFunction("free"  , Type::VoidTy, SBPTy, 0);

  return true;
}

// runOnBasicBlock - This method does the actual work of converting
// instructions over, assuming that the pass has already been initialized.
//
bool LowerAllocations::runOnBasicBlock(BasicBlock &BB) {
  bool Changed = false;
  assert(MallocFunc && FreeFunc && "Pass not initialized!");

  BasicBlock::InstListType &BBIL = BB.getInstList();
  TargetData &DataLayout = getAnalysis<TargetData>();

  // Loop over all of the instructions, looking for malloc or free instructions
  for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) {
    if (MallocInst *MI = dyn_cast<MallocInst>(I)) {
      const Type *AllocTy = MI->getType()->getElementType();

      // Get the number of bytes to be allocated for one element of the
      // requested type...
      unsigned Size = DataLayout.getTypeSize(AllocTy);

      // malloc(type) becomes sbyte *malloc(constint)
      Value *MallocArg = ConstantUInt::get(Type::UIntTy, Size);
      if (MI->getNumOperands() && Size == 1) {
        MallocArg = MI->getOperand(0);         // Operand * 1 = Operand
      } else if (MI->isArrayAllocation()) {
        // Multiply it by the array size if necessary...
        MallocArg = BinaryOperator::create(Instruction::Mul, MI->getOperand(0),
                                           MallocArg, "", I);
      }

      const FunctionType *MallocFTy = MallocFunc->getFunctionType();
      std::vector<Value*> MallocArgs;

      if (MallocFTy->getNumParams() > 0 || MallocFTy->isVarArg()) {
        if (MallocFTy->getNumParams() > 0 &&
            MallocFTy->getParamType(0) != Type::UIntTy)
          MallocArg = new CastInst(MallocArg, MallocFTy->getParamType(0), "",I);
        MallocArgs.push_back(MallocArg);
      }

      // If malloc is prototyped to take extra arguments, pass nulls.
      for (unsigned i = 1; i < MallocFTy->getNumParams(); ++i)
       MallocArgs.push_back(Constant::getNullValue(MallocFTy->getParamType(i)));

      // Create the call to Malloc...
      CallInst *MCall = new CallInst(MallocFunc, MallocArgs, "", I);

      // Create a cast instruction to convert to the right type...
      Value *MCast;
      if (MCall->getType() != Type::VoidTy)
        MCast = new CastInst(MCall, MI->getType(), "", I);
      else
        MCast = Constant::getNullValue(MI->getType());

      // Replace all uses of the old malloc inst with the cast inst
      MI->replaceAllUsesWith(MCast);
      I = --BBIL.erase(I);         // remove and delete the malloc instr...
      Changed = true;
      ++NumLowered;
    } else if (FreeInst *FI = dyn_cast<FreeInst>(I)) {
      const FunctionType *FreeFTy = FreeFunc->getFunctionType();
      std::vector<Value*> FreeArgs;

      if (FreeFTy->getNumParams() > 0 || FreeFTy->isVarArg()) {
        Value *MCast = FI->getOperand(0);
        if (FreeFTy->getNumParams() > 0 &&
            FreeFTy->getParamType(0) != MCast->getType())
          MCast = new CastInst(MCast, FreeFTy->getParamType(0), "", I);
        FreeArgs.push_back(MCast);
      }

      // If malloc is prototyped to take extra arguments, pass nulls.
      for (unsigned i = 1; i < FreeFTy->getNumParams(); ++i)
       FreeArgs.push_back(Constant::getNullValue(FreeFTy->getParamType(i)));

      // Insert a call to the free function...
      new CallInst(FreeFunc, FreeArgs, "", I);

      // Delete the old free instruction
      I = --BBIL.erase(I);
      Changed = true;
      ++NumLowered;
    }
  }

  return Changed;
}

<|endoftext|>