<commit_before>/****************************************************************************
 *
 *   Copyright (C) 2012 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file mixer.cpp
 *
 * Programmable multi-channel mixer library.
 */

#include <nuttx/config.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <ctype.h>
#include <systemlib/err.h>

#include "mixer.h"

Mixer::Mixer(ControlCallback control_cb, uintptr_t cb_handle) :
	_next(nullptr),
	_control_cb(control_cb),
	_cb_handle(cb_handle)
{
}

float
Mixer::get_control(uint8_t group, uint8_t index)
{
	float	value;

	_control_cb(_cb_handle, group, index, value);

	return value;
}

float
Mixer::scale(const mixer_scaler_s &scaler, float input)
{
	float output;

	if (input < 0.0f) {
		output = (input * scaler.negative_scale) + scaler.offset;

	} else {
		output = (input * scaler.positive_scale) + scaler.offset;
	}

	if (output > scaler.max_output) {
		output = scaler.max_output;

	} else if (output < scaler.min_output) {
		output = scaler.min_output;
	}

	return output;
}

int
Mixer::scale_check(struct mixer_scaler_s &scaler)
{
	if (scaler.offset > 1.001f)
		return 1;

	if (scaler.offset < -1.001f)
		return 2;

	if (scaler.min_output > scaler.max_output)
		return 3;

	if (scaler.min_output < -1.001f)
		return 4;

	if (scaler.max_output > 1.001f)
		return 5;

	return 0;
}

const char *
Mixer::findtag(const char *buf, unsigned &buflen, char tag)
{
	while (buflen >= 2) {
		if ((buf[0] == tag) && (buf[1] == ':'))
			return buf;
		buf++;
		buflen--;
	}
	return nullptr;
}

const char *
Mixer::skipline(const char *buf, unsigned &buflen)
{
	const char *p;

	/* if we can find a CR or NL in the buffer, skip up to it */
	if ((p = (const char *)memchr(buf, '\r', buflen)) || (p = (const char *)memchr(buf, '\n', buflen))) {
		/* skip up to it AND one beyond - could be on the NUL symbol now */
		buflen -= (p - buf) + 1;
		return p + 1;
	}

	return nullptr;
}

/****************************************************************************/

NullMixer::NullMixer() :
	Mixer(nullptr, 0)
{
}

unsigned
NullMixer::mix(float *outputs, unsigned space)
{
	if (space > 0) {
		*outputs = 0.0f;
		return 1;
	}

	return 0;
}

void
NullMixer::groups_required(uint32_t &groups)
{

}

NullMixer *
NullMixer::from_text(const char *buf, unsigned &buflen)
{
	NullMixer *nm = nullptr;
	const char *end = buf + buflen;

	/* enforce that the mixer ends with space or a new line */
	for (int i = buflen - 1; i >= 0; i--) {
		if (buf[i] == '\0')
			continue;

		/* require a space or newline at the end of the buffer, fail on printable chars */
		if (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\r') {
			/* found a line ending or space, so no split symbols / numbers. good. */
			break;
		} else {
			return nm;
		}

	}

	if ((buflen >= 2) && (buf[0] == 'Z') && (buf[1] == ':')) {
		nm = new NullMixer;
		buflen -= 2;
	}

	return nm;
}
<commit_msg>Remove unused variable<commit_after>/****************************************************************************
 *
 *   Copyright (C) 2012 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file mixer.cpp
 *
 * Programmable multi-channel mixer library.
 */

#include <nuttx/config.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <ctype.h>
#include <systemlib/err.h>

#include "mixer.h"

Mixer::Mixer(ControlCallback control_cb, uintptr_t cb_handle) :
	_next(nullptr),
	_control_cb(control_cb),
	_cb_handle(cb_handle)
{
}

float
Mixer::get_control(uint8_t group, uint8_t index)
{
	float	value;

	_control_cb(_cb_handle, group, index, value);

	return value;
}

float
Mixer::scale(const mixer_scaler_s &scaler, float input)
{
	float output;

	if (input < 0.0f) {
		output = (input * scaler.negative_scale) + scaler.offset;

	} else {
		output = (input * scaler.positive_scale) + scaler.offset;
	}

	if (output > scaler.max_output) {
		output = scaler.max_output;

	} else if (output < scaler.min_output) {
		output = scaler.min_output;
	}

	return output;
}

int
Mixer::scale_check(struct mixer_scaler_s &scaler)
{
	if (scaler.offset > 1.001f)
		return 1;

	if (scaler.offset < -1.001f)
		return 2;

	if (scaler.min_output > scaler.max_output)
		return 3;

	if (scaler.min_output < -1.001f)
		return 4;

	if (scaler.max_output > 1.001f)
		return 5;

	return 0;
}

const char *
Mixer::findtag(const char *buf, unsigned &buflen, char tag)
{
	while (buflen >= 2) {
		if ((buf[0] == tag) && (buf[1] == ':'))
			return buf;
		buf++;
		buflen--;
	}
	return nullptr;
}

const char *
Mixer::skipline(const char *buf, unsigned &buflen)
{
	const char *p;

	/* if we can find a CR or NL in the buffer, skip up to it */
	if ((p = (const char *)memchr(buf, '\r', buflen)) || (p = (const char *)memchr(buf, '\n', buflen))) {
		/* skip up to it AND one beyond - could be on the NUL symbol now */
		buflen -= (p - buf) + 1;
		return p + 1;
	}

	return nullptr;
}

/****************************************************************************/

NullMixer::NullMixer() :
	Mixer(nullptr, 0)
{
}

unsigned
NullMixer::mix(float *outputs, unsigned space)
{
	if (space > 0) {
		*outputs = 0.0f;
		return 1;
	}

	return 0;
}

void
NullMixer::groups_required(uint32_t &groups)
{

}

NullMixer *
NullMixer::from_text(const char *buf, unsigned &buflen)
{
	NullMixer *nm = nullptr;

	/* enforce that the mixer ends with space or a new line */
	for (int i = buflen - 1; i >= 0; i--) {
		if (buf[i] == '\0')
			continue;

		/* require a space or newline at the end of the buffer, fail on printable chars */
		if (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\r') {
			/* found a line ending or space, so no split symbols / numbers. good. */
			break;
		} else {
			return nm;
		}

	}

	if ((buflen >= 2) && (buf[0] == 'Z') && (buf[1] == ':')) {
		nm = new NullMixer;
		buflen -= 2;
	}

	return nm;
}
<|endoftext|>


<commit_before>//===-- SpillPlacement.cpp - Optimal Spill Code Placement -----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the spill code placement analysis.
//
// Each edge bundle corresponds to a node in a Hopfield network. Constraints on
// basic blocks are weighted by the block frequency and added to become the node
// bias.
//
// Transparent basic blocks have the variable live through, but don't care if it
// is spilled or in a register. These blocks become connections in the Hopfield
// network, again weighted by block frequency.
//
// The Hopfield network minimizes (possibly locally) its energy function:
//
//   E = -sum_n V_n * ( B_n + sum_{n, m linked by b} V_m * F_b )
//
// The energy function represents the expected spill code execution frequency,
// or the cost of spilling. This is a Lyapunov function which never increases
// when a node is updated. It is guaranteed to converge to a local minimum.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "spillplacement"
#include "SpillPlacement.h"
#include "llvm/CodeGen/EdgeBundles.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"

using namespace llvm;

char SpillPlacement::ID = 0;
INITIALIZE_PASS_BEGIN(SpillPlacement, "spill-code-placement",
                      "Spill Code Placement Analysis", true, true)
INITIALIZE_PASS_DEPENDENCY(EdgeBundles)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_END(SpillPlacement, "spill-code-placement",
                    "Spill Code Placement Analysis", true, true)

char &llvm::SpillPlacementID = SpillPlacement::ID;

void SpillPlacement::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesAll();
  AU.addRequiredTransitive<EdgeBundles>();
  AU.addRequiredTransitive<MachineLoopInfo>();
  MachineFunctionPass::getAnalysisUsage(AU);
}

/// Node - Each edge bundle corresponds to a Hopfield node.
///
/// The node contains precomputed frequency data that only depends on the CFG,
/// but Bias and Links are computed each time placeSpills is called.
///
/// The node Value is positive when the variable should be in a register. The
/// value can change when linked nodes change, but convergence is very fast
/// because all weights are positive.
///
struct SpillPlacement::Node {
  /// Frequency - Total block frequency feeding into[0] or out of[1] the bundle.
  /// Ideally, these two numbers should be identical, but inaccuracies in the
  /// block frequency estimates means that we need to normalize ingoing and
  /// outgoing frequencies separately so they are commensurate.
  float Frequency[2];

  /// Bias - Normalized contributions from non-transparent blocks.
  /// A bundle connected to a MustSpill block has a huge negative bias,
  /// otherwise it is a number in the range [-2;2].
  float Bias;

  /// Value - Output value of this node computed from the Bias and links.
  /// This is always in the range [-1;1]. A positive number means the variable
  /// should go in a register through this bundle.
  float Value;

  typedef SmallVector<std::pair<float, unsigned>, 4> LinkVector;

  /// Links - (Weight, BundleNo) for all transparent blocks connecting to other
  /// bundles. The weights are all positive and add up to at most 2, weights
  /// from ingoing and outgoing nodes separately add up to a most 1. The weight
  /// sum can be less than 2 when the variable is not live into / out of some
  /// connected basic blocks.
  LinkVector Links;

  /// preferReg - Return true when this node prefers to be in a register.
  bool preferReg() const {
    // Undecided nodes (Value==0) go on the stack.
    return Value > 0;
  }

  /// mustSpill - Return True if this node is so biased that it must spill.
  bool mustSpill() const {
    // Actually, we must spill if Bias < sum(weights).
    // It may be worth it to compute the weight sum here?
    return Bias < -2.0f;
  }

  /// Node - Create a blank Node.
  Node() {
    Frequency[0] = Frequency[1] = 0;
  }

  /// clear - Reset per-query data, but preserve frequencies that only depend on
  // the CFG.
  void clear() {
    Bias = Value = 0;
    Links.clear();
  }

  /// addLink - Add a link to bundle b with weight w.
  /// out=0 for an ingoing link, and 1 for an outgoing link.
  void addLink(unsigned b, float w, bool out) {
    // Normalize w relative to all connected blocks from that direction.
    w /= Frequency[out];

    // There can be multiple links to the same bundle, add them up.
    for (LinkVector::iterator I = Links.begin(), E = Links.end(); I != E; ++I)
      if (I->second == b) {
        I->first += w;
        return;
      }
    // This must be the first link to b.
    Links.push_back(std::make_pair(w, b));
  }

  /// addBias - Bias this node from an ingoing[0] or outgoing[1] link.
  /// Return the change to the total number of positive biases.
  int addBias(float w, bool out) {
    // Normalize w relative to all connected blocks from that direction.
    w /= Frequency[out];
    int Before = Bias > 0;
    Bias += w;
    int After = Bias > 0;
    return After - Before;
  }

  /// update - Recompute Value from Bias and Links. Return true when node
  /// preference changes.
  bool update(const Node nodes[]) {
    // Compute the weighted sum of inputs.
    float Sum = Bias;
    for (LinkVector::iterator I = Links.begin(), E = Links.end(); I != E; ++I)
      Sum += I->first * nodes[I->second].Value;

    // The weighted sum is going to be in the range [-2;2]. Ideally, we should
    // simply set Value = sign(Sum), but we will add a dead zone around 0 for
    // two reasons:
    //  1. It avoids arbitrary bias when all links are 0 as is possible during
    //     initial iterations.
    //  2. It helps tame rounding errors when the links nominally sum to 0.
    const float Thres = 1e-4f;
    bool Before = preferReg();
    if (Sum < -Thres)
      Value = -1;
    else if (Sum > Thres)
      Value = 1;
    else
      Value = 0;
    return Before != preferReg();
  }
};

bool SpillPlacement::runOnMachineFunction(MachineFunction &mf) {
  MF = &mf;
  bundles = &getAnalysis<EdgeBundles>();
  loops = &getAnalysis<MachineLoopInfo>();

  assert(!nodes && "Leaking node array");
  nodes = new Node[bundles->getNumBundles()];

  // Compute total ingoing and outgoing block frequencies for all bundles.
  BlockFrequency.resize(mf.getNumBlockIDs());
  for (MachineFunction::iterator I = mf.begin(), E = mf.end(); I != E; ++I) {
    float Freq = LiveIntervals::getSpillWeight(true, false,
                                               loops->getLoopDepth(I));
    unsigned Num = I->getNumber();
    BlockFrequency[Num] = Freq;
    nodes[bundles->getBundle(Num, 1)].Frequency[0] += Freq;
    nodes[bundles->getBundle(Num, 0)].Frequency[1] += Freq;
  }

  // We never change the function.
  return false;
}

void SpillPlacement::releaseMemory() {
  delete[] nodes;
  nodes = 0;
}

/// activate - mark node n as active if it wasn't already.
void SpillPlacement::activate(unsigned n) {
  if (ActiveNodes->test(n))
    return;
  ActiveNodes->set(n);
  nodes[n].clear();
}

/// addConstraints - Compute node biases and weights from a set of constraints.
/// Set a bit in NodeMask for each active node.
void SpillPlacement::addConstraints(ArrayRef<BlockConstraint> LiveBlocks) {
  for (ArrayRef<BlockConstraint>::iterator I = LiveBlocks.begin(),
       E = LiveBlocks.end(); I != E; ++I) {
    float Freq = getBlockFrequency(I->Number);
    const float Bias[] = {
      0,           // DontCare,
      1,           // PrefReg,
      -1,          // PrefSpill
      -HUGE_VALF   // MustSpill
    };

    // Live-in to block?
    if (I->Entry != DontCare) {
      unsigned ib = bundles->getBundle(I->Number, 0);
      activate(ib);
      PositiveNodes += nodes[ib].addBias(Freq * Bias[I->Entry], 1);
    }

    // Live-out from block?
    if (I->Exit != DontCare) {
      unsigned ob = bundles->getBundle(I->Number, 1);
      activate(ob);
      PositiveNodes += nodes[ob].addBias(Freq * Bias[I->Exit], 0);
    }
  }
}

void SpillPlacement::addLinks(ArrayRef<unsigned> Links) {
  for (ArrayRef<unsigned>::iterator I = Links.begin(), E = Links.end(); I != E;
       ++I) {
    unsigned Number = *I;
    unsigned ib = bundles->getBundle(Number, 0);
    unsigned ob = bundles->getBundle(Number, 1);

    // Ignore self-loops.
    if (ib == ob)
      continue;
    activate(ib);
    activate(ob);
    float Freq = getBlockFrequency(Number);
    nodes[ib].addLink(ob, Freq, 1);
    nodes[ob].addLink(ib, Freq, 0);
  }
}

/// iterate - Repeatedly update the Hopfield nodes until stability or the
/// maximum number of iterations is reached.
/// @param Linked - Numbers of linked nodes that need updating.
void SpillPlacement::iterate(const SmallVectorImpl<unsigned> &Linked) {
  if (Linked.empty())
    return;

  // Run up to 10 iterations. The edge bundle numbering is closely related to
  // basic block numbering, so there is a strong tendency towards chains of
  // linked nodes with sequential numbers. By scanning the linked nodes
  // backwards and forwards, we make it very likely that a single node can
  // affect the entire network in a single iteration. That means very fast
  // convergence, usually in a single iteration.
  for (unsigned iteration = 0; iteration != 10; ++iteration) {
    // Scan backwards, skipping the last node which was just updated.
    bool Changed = false;
    for (SmallVectorImpl<unsigned>::const_reverse_iterator I =
           llvm::next(Linked.rbegin()), E = Linked.rend(); I != E; ++I) {
      unsigned n = *I;
      bool C = nodes[n].update(nodes);
      Changed |= C;
    }
    if (!Changed)
      return;

    // Scan forwards, skipping the first node which was just updated.
    Changed = false;
    for (SmallVectorImpl<unsigned>::const_iterator I =
           llvm::next(Linked.begin()), E = Linked.end(); I != E; ++I) {
      unsigned n = *I;
      bool C = nodes[n].update(nodes);
      Changed |= C;
    }
    if (!Changed)
      return;
  }
}

void SpillPlacement::prepare(BitVector &RegBundles) {
  // Reuse RegBundles as our ActiveNodes vector.
  ActiveNodes = &RegBundles;
  ActiveNodes->clear();
  ActiveNodes->resize(bundles->getNumBundles());
  PositiveNodes = 0;
}

bool
SpillPlacement::finish() {
  assert(ActiveNodes && "Call prepare() first");
  // Update all active nodes, and find the ones that are actually linked to
  // something so their value may change when iterating.
  SmallVector<unsigned, 8> Linked;
  for (int n = ActiveNodes->find_first(); n>=0; n = ActiveNodes->find_next(n)) {
    nodes[n].update(nodes);
    // A node that must spill, or a node without any links is not going to
    // change its value ever again, so exclude it from iterations.
    if (!nodes[n].Links.empty() && !nodes[n].mustSpill())
      Linked.push_back(n);
  }

  // Iterate the network to convergence.
  iterate(Linked);

  // Write preferences back to ActiveNodes.
  bool Perfect = true;
  for (int n = ActiveNodes->find_first(); n>=0; n = ActiveNodes->find_next(n))
    if (!nodes[n].preferReg()) {
      ActiveNodes->reset(n);
      Perfect = false;
    }
  ActiveNodes = 0;
  return Perfect;
}
<commit_msg>Prefer multiplications to divisions.<commit_after>//===-- SpillPlacement.cpp - Optimal Spill Code Placement -----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the spill code placement analysis.
//
// Each edge bundle corresponds to a node in a Hopfield network. Constraints on
// basic blocks are weighted by the block frequency and added to become the node
// bias.
//
// Transparent basic blocks have the variable live through, but don't care if it
// is spilled or in a register. These blocks become connections in the Hopfield
// network, again weighted by block frequency.
//
// The Hopfield network minimizes (possibly locally) its energy function:
//
//   E = -sum_n V_n * ( B_n + sum_{n, m linked by b} V_m * F_b )
//
// The energy function represents the expected spill code execution frequency,
// or the cost of spilling. This is a Lyapunov function which never increases
// when a node is updated. It is guaranteed to converge to a local minimum.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "spillplacement"
#include "SpillPlacement.h"
#include "llvm/CodeGen/EdgeBundles.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"

using namespace llvm;

char SpillPlacement::ID = 0;
INITIALIZE_PASS_BEGIN(SpillPlacement, "spill-code-placement",
                      "Spill Code Placement Analysis", true, true)
INITIALIZE_PASS_DEPENDENCY(EdgeBundles)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_END(SpillPlacement, "spill-code-placement",
                    "Spill Code Placement Analysis", true, true)

char &llvm::SpillPlacementID = SpillPlacement::ID;

void SpillPlacement::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.setPreservesAll();
  AU.addRequiredTransitive<EdgeBundles>();
  AU.addRequiredTransitive<MachineLoopInfo>();
  MachineFunctionPass::getAnalysisUsage(AU);
}

/// Node - Each edge bundle corresponds to a Hopfield node.
///
/// The node contains precomputed frequency data that only depends on the CFG,
/// but Bias and Links are computed each time placeSpills is called.
///
/// The node Value is positive when the variable should be in a register. The
/// value can change when linked nodes change, but convergence is very fast
/// because all weights are positive.
///
struct SpillPlacement::Node {
  /// Scale - Inverse block frequency feeding into[0] or out of[1] the bundle.
  /// Ideally, these two numbers should be identical, but inaccuracies in the
  /// block frequency estimates means that we need to normalize ingoing and
  /// outgoing frequencies separately so they are commensurate.
  float Scale[2];

  /// Bias - Normalized contributions from non-transparent blocks.
  /// A bundle connected to a MustSpill block has a huge negative bias,
  /// otherwise it is a number in the range [-2;2].
  float Bias;

  /// Value - Output value of this node computed from the Bias and links.
  /// This is always in the range [-1;1]. A positive number means the variable
  /// should go in a register through this bundle.
  float Value;

  typedef SmallVector<std::pair<float, unsigned>, 4> LinkVector;

  /// Links - (Weight, BundleNo) for all transparent blocks connecting to other
  /// bundles. The weights are all positive and add up to at most 2, weights
  /// from ingoing and outgoing nodes separately add up to a most 1. The weight
  /// sum can be less than 2 when the variable is not live into / out of some
  /// connected basic blocks.
  LinkVector Links;

  /// preferReg - Return true when this node prefers to be in a register.
  bool preferReg() const {
    // Undecided nodes (Value==0) go on the stack.
    return Value > 0;
  }

  /// mustSpill - Return True if this node is so biased that it must spill.
  bool mustSpill() const {
    // Actually, we must spill if Bias < sum(weights).
    // It may be worth it to compute the weight sum here?
    return Bias < -2.0f;
  }

  /// Node - Create a blank Node.
  Node() {
    Scale[0] = Scale[1] = 0;
  }

  /// clear - Reset per-query data, but preserve frequencies that only depend on
  // the CFG.
  void clear() {
    Bias = Value = 0;
    Links.clear();
  }

  /// addLink - Add a link to bundle b with weight w.
  /// out=0 for an ingoing link, and 1 for an outgoing link.
  void addLink(unsigned b, float w, bool out) {
    // Normalize w relative to all connected blocks from that direction.
    w *= Scale[out];

    // There can be multiple links to the same bundle, add them up.
    for (LinkVector::iterator I = Links.begin(), E = Links.end(); I != E; ++I)
      if (I->second == b) {
        I->first += w;
        return;
      }
    // This must be the first link to b.
    Links.push_back(std::make_pair(w, b));
  }

  /// addBias - Bias this node from an ingoing[0] or outgoing[1] link.
  /// Return the change to the total number of positive biases.
  int addBias(float w, bool out) {
    // Normalize w relative to all connected blocks from that direction.
    w *= Scale[out];
    int Before = Bias > 0;
    Bias += w;
    int After = Bias > 0;
    return After - Before;
  }

  /// update - Recompute Value from Bias and Links. Return true when node
  /// preference changes.
  bool update(const Node nodes[]) {
    // Compute the weighted sum of inputs.
    float Sum = Bias;
    for (LinkVector::iterator I = Links.begin(), E = Links.end(); I != E; ++I)
      Sum += I->first * nodes[I->second].Value;

    // The weighted sum is going to be in the range [-2;2]. Ideally, we should
    // simply set Value = sign(Sum), but we will add a dead zone around 0 for
    // two reasons:
    //  1. It avoids arbitrary bias when all links are 0 as is possible during
    //     initial iterations.
    //  2. It helps tame rounding errors when the links nominally sum to 0.
    const float Thres = 1e-4f;
    bool Before = preferReg();
    if (Sum < -Thres)
      Value = -1;
    else if (Sum > Thres)
      Value = 1;
    else
      Value = 0;
    return Before != preferReg();
  }
};

bool SpillPlacement::runOnMachineFunction(MachineFunction &mf) {
  MF = &mf;
  bundles = &getAnalysis<EdgeBundles>();
  loops = &getAnalysis<MachineLoopInfo>();

  assert(!nodes && "Leaking node array");
  nodes = new Node[bundles->getNumBundles()];

  // Compute total ingoing and outgoing block frequencies for all bundles.
  BlockFrequency.resize(mf.getNumBlockIDs());
  for (MachineFunction::iterator I = mf.begin(), E = mf.end(); I != E; ++I) {
    float Freq = LiveIntervals::getSpillWeight(true, false,
                                               loops->getLoopDepth(I));
    unsigned Num = I->getNumber();
    BlockFrequency[Num] = Freq;
    nodes[bundles->getBundle(Num, 1)].Scale[0] += Freq;
    nodes[bundles->getBundle(Num, 0)].Scale[1] += Freq;
  }

  // Scales are reciprocal frequencies.
  for (unsigned i = 0, e = bundles->getNumBundles(); i != e; ++i)
    for (unsigned d = 0; d != 2; ++d)
      if (nodes[i].Scale[d] > 0)
        nodes[i].Scale[d] = 1 / nodes[i].Scale[d];

  // We never change the function.
  return false;
}

void SpillPlacement::releaseMemory() {
  delete[] nodes;
  nodes = 0;
}

/// activate - mark node n as active if it wasn't already.
void SpillPlacement::activate(unsigned n) {
  if (ActiveNodes->test(n))
    return;
  ActiveNodes->set(n);
  nodes[n].clear();
}

/// addConstraints - Compute node biases and weights from a set of constraints.
/// Set a bit in NodeMask for each active node.
void SpillPlacement::addConstraints(ArrayRef<BlockConstraint> LiveBlocks) {
  for (ArrayRef<BlockConstraint>::iterator I = LiveBlocks.begin(),
       E = LiveBlocks.end(); I != E; ++I) {
    float Freq = getBlockFrequency(I->Number);
    const float Bias[] = {
      0,           // DontCare,
      1,           // PrefReg,
      -1,          // PrefSpill
      -HUGE_VALF   // MustSpill
    };

    // Live-in to block?
    if (I->Entry != DontCare) {
      unsigned ib = bundles->getBundle(I->Number, 0);
      activate(ib);
      PositiveNodes += nodes[ib].addBias(Freq * Bias[I->Entry], 1);
    }

    // Live-out from block?
    if (I->Exit != DontCare) {
      unsigned ob = bundles->getBundle(I->Number, 1);
      activate(ob);
      PositiveNodes += nodes[ob].addBias(Freq * Bias[I->Exit], 0);
    }
  }
}

void SpillPlacement::addLinks(ArrayRef<unsigned> Links) {
  for (ArrayRef<unsigned>::iterator I = Links.begin(), E = Links.end(); I != E;
       ++I) {
    unsigned Number = *I;
    unsigned ib = bundles->getBundle(Number, 0);
    unsigned ob = bundles->getBundle(Number, 1);

    // Ignore self-loops.
    if (ib == ob)
      continue;
    activate(ib);
    activate(ob);
    float Freq = getBlockFrequency(Number);
    nodes[ib].addLink(ob, Freq, 1);
    nodes[ob].addLink(ib, Freq, 0);
  }
}

/// iterate - Repeatedly update the Hopfield nodes until stability or the
/// maximum number of iterations is reached.
/// @param Linked - Numbers of linked nodes that need updating.
void SpillPlacement::iterate(const SmallVectorImpl<unsigned> &Linked) {
  if (Linked.empty())
    return;

  // Run up to 10 iterations. The edge bundle numbering is closely related to
  // basic block numbering, so there is a strong tendency towards chains of
  // linked nodes with sequential numbers. By scanning the linked nodes
  // backwards and forwards, we make it very likely that a single node can
  // affect the entire network in a single iteration. That means very fast
  // convergence, usually in a single iteration.
  for (unsigned iteration = 0; iteration != 10; ++iteration) {
    // Scan backwards, skipping the last node which was just updated.
    bool Changed = false;
    for (SmallVectorImpl<unsigned>::const_reverse_iterator I =
           llvm::next(Linked.rbegin()), E = Linked.rend(); I != E; ++I) {
      unsigned n = *I;
      bool C = nodes[n].update(nodes);
      Changed |= C;
    }
    if (!Changed)
      return;

    // Scan forwards, skipping the first node which was just updated.
    Changed = false;
    for (SmallVectorImpl<unsigned>::const_iterator I =
           llvm::next(Linked.begin()), E = Linked.end(); I != E; ++I) {
      unsigned n = *I;
      bool C = nodes[n].update(nodes);
      Changed |= C;
    }
    if (!Changed)
      return;
  }
}

void SpillPlacement::prepare(BitVector &RegBundles) {
  // Reuse RegBundles as our ActiveNodes vector.
  ActiveNodes = &RegBundles;
  ActiveNodes->clear();
  ActiveNodes->resize(bundles->getNumBundles());
  PositiveNodes = 0;
}

bool
SpillPlacement::finish() {
  assert(ActiveNodes && "Call prepare() first");
  // Update all active nodes, and find the ones that are actually linked to
  // something so their value may change when iterating.
  SmallVector<unsigned, 8> Linked;
  for (int n = ActiveNodes->find_first(); n>=0; n = ActiveNodes->find_next(n)) {
    nodes[n].update(nodes);
    // A node that must spill, or a node without any links is not going to
    // change its value ever again, so exclude it from iterations.
    if (!nodes[n].Links.empty() && !nodes[n].mustSpill())
      Linked.push_back(n);
  }

  // Iterate the network to convergence.
  iterate(Linked);

  // Write preferences back to ActiveNodes.
  bool Perfect = true;
  for (int n = ActiveNodes->find_first(); n>=0; n = ActiveNodes->find_next(n))
    if (!nodes[n].preferReg()) {
      ActiveNodes->reset(n);
      Perfect = false;
    }
  ActiveNodes = 0;
  return Perfect;
}
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "HomogenizationConstraint.h"

#include "Function.h"

registerMooseObject("TensorMechanicsApp", HomogenizationConstraint);

InputParameters
HomogenizationConstraint::validParams()
{
  InputParameters params = ElementUserObject::validParams();
  params.addRequiredParam<MultiMooseEnum>(
      "constraint_types",
      Homogenization::constraintType,
      "Type of each constraint: strain, stress, or none. The types are specified in the "
      "column-major order, and there must be 9 entries in total.");
  params.addRequiredParam<std::vector<FunctionName>>(
      "targets", "Functions giving the targets to hit for constraint types that are not none.");
  params.addParam<bool>("large_kinematics", false, "Using large displacements?");
  params.addParam<std::string>("base_name", "Material property base name");
  return params;
}

HomogenizationConstraint::HomogenizationConstraint(const InputParameters & parameters)
  : ElementUserObject(parameters),
    _large_kinematics(getParam<bool>("large_kinematics")),
    _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
    _F(getMaterialPropertyByName<RankTwoTensor>(_base_name + "deformation_gradient")),
    _pk1_stress(getMaterialPropertyByName<RankTwoTensor>(_base_name + "pk1_stress")),
    _pk1_jacobian(getMaterialPropertyByName<RankFourTensor>(_base_name + "pk1_jacobian"))
{
  // Constraint types
  auto types = getParam<MultiMooseEnum>("constraint_types");
  if (types.size() != Moose::dim * Moose::dim)
    mooseError("Number of constraint types must equal dim * dim. ", types.size(), " are provided.");

  // Targets to hit
  const std::vector<FunctionName> & fnames = getParam<std::vector<FunctionName>>("targets");

  // Prepare the constraint map
  unsigned int fcount = 0;
  for (const auto j : make_range(Moose::dim))
    for (const auto i : make_range(Moose::dim))
    {
      const auto idx = i + Moose::dim * j;
      const auto ctype = static_cast<Homogenization::ConstraintType>(types.get(idx));
      if (ctype != Homogenization::ConstraintType::None)
      {
        const Function * const f = &getFunctionByName(fnames[fcount++]);
        _cmap[{i, j}] = {ctype, f};
      }
    }
}

void
HomogenizationConstraint::initialize()
{
  _residual.zero();
  _jacobian.zero();
}

void
HomogenizationConstraint::execute()
{
  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
  {
    Real dV = _JxW[_qp] * _coord[_qp];
    _residual += computeResidual() * dV;
    _jacobian += computeJacobian() * dV;
  }
}

void
HomogenizationConstraint::threadJoin(const UserObject & y)
{
  const HomogenizationConstraint & other = static_cast<const HomogenizationConstraint &>(y);
  _residual += other._residual;
  _jacobian += other._jacobian;
}

void
HomogenizationConstraint::finalize()
{
  std::vector<Real> residual(&_residual(0, 0), &_residual(0, 0) + RankTwoTensor::N2);
  std::vector<Real> jacobian(&_jacobian(0, 0, 0, 0), &_jacobian(0, 0, 0, 0) + RankFourTensor::N4);

  gatherSum(residual);
  gatherSum(jacobian);

  std::copy(residual.begin(), residual.end(), &_residual(0, 0));
  std::copy(jacobian.begin(), jacobian.end(), &_jacobian(0, 0, 0, 0));
}

RankTwoTensor
HomogenizationConstraint::computeResidual()
{
  RankTwoTensor res;

  for (auto && [indices, constraint] : _cmap)
  {
    auto && [i, j] = indices;
    auto && [ctype, ctarget] = constraint;

    if (_large_kinematics)
    {
      if (ctype == Homogenization::ConstraintType::Stress)
        res(i, j) = _pk1_stress[_qp](i, j) - ctarget->value(_t, _q_point[_qp]);
      else if (ctype == Homogenization::ConstraintType::Strain)
        res(i, j) = _F[_qp](i, j) - (Real(i == j) + ctarget->value(_t, _q_point[_qp]));
      else
        mooseError("Unknown constraint type in the integral!");
    }
    else
    {
      if (ctype == Homogenization::ConstraintType::Stress)
        res(i, j) = _pk1_stress[_qp](i, j) - ctarget->value(_t, _q_point[_qp]);
      else if (ctype == Homogenization::ConstraintType::Strain)
        res(i, j) = 0.5 * (_F[_qp](i, j) + _F[_qp](j, i)) -
                    (Real(i == j) + ctarget->value(_t, _q_point[_qp]));
      else
        mooseError("Unknown constraint type in the integral!");
    }
  }

  return res;
}

RankFourTensor
HomogenizationConstraint::computeJacobian()
{
  RankFourTensor res;

  for (auto && [indices1, constraint1] : _cmap)
  {
    auto && [i, j] = indices1;
    auto && [ctype, ctarget] = constraint1;
    for (auto && indices2 : _cmap)
    {
      auto && [a, b] = indices2.first;
      if (ctype == Homogenization::ConstraintType::Stress)
        res(i, j, a, b) = _pk1_jacobian[_qp](i, j, a, b);
      else if (ctype == Homogenization::ConstraintType::Strain)
      {
        if (_large_kinematics)
          res(i, j, a, b) = Real(i == a && j == b);
        else
          res(i, j, a, b) = 0.5 * Real(i == a && j == b) + 0.5 * Real(i == b && j == a);
      }
      else
        mooseError("Unknown constraint type in Jacobian calculator!");
    }
  }

  return res;
}
<commit_msg>fix min gcc unused var error<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "HomogenizationConstraint.h"

#include "Function.h"

registerMooseObject("TensorMechanicsApp", HomogenizationConstraint);

InputParameters
HomogenizationConstraint::validParams()
{
  InputParameters params = ElementUserObject::validParams();
  params.addRequiredParam<MultiMooseEnum>(
      "constraint_types",
      Homogenization::constraintType,
      "Type of each constraint: strain, stress, or none. The types are specified in the "
      "column-major order, and there must be 9 entries in total.");
  params.addRequiredParam<std::vector<FunctionName>>(
      "targets", "Functions giving the targets to hit for constraint types that are not none.");
  params.addParam<bool>("large_kinematics", false, "Using large displacements?");
  params.addParam<std::string>("base_name", "Material property base name");
  return params;
}

HomogenizationConstraint::HomogenizationConstraint(const InputParameters & parameters)
  : ElementUserObject(parameters),
    _large_kinematics(getParam<bool>("large_kinematics")),
    _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
    _F(getMaterialPropertyByName<RankTwoTensor>(_base_name + "deformation_gradient")),
    _pk1_stress(getMaterialPropertyByName<RankTwoTensor>(_base_name + "pk1_stress")),
    _pk1_jacobian(getMaterialPropertyByName<RankFourTensor>(_base_name + "pk1_jacobian"))
{
  // Constraint types
  auto types = getParam<MultiMooseEnum>("constraint_types");
  if (types.size() != Moose::dim * Moose::dim)
    mooseError("Number of constraint types must equal dim * dim. ", types.size(), " are provided.");

  // Targets to hit
  const std::vector<FunctionName> & fnames = getParam<std::vector<FunctionName>>("targets");

  // Prepare the constraint map
  unsigned int fcount = 0;
  for (const auto j : make_range(Moose::dim))
    for (const auto i : make_range(Moose::dim))
    {
      const auto idx = i + Moose::dim * j;
      const auto ctype = static_cast<Homogenization::ConstraintType>(types.get(idx));
      if (ctype != Homogenization::ConstraintType::None)
      {
        const Function * const f = &getFunctionByName(fnames[fcount++]);
        _cmap[{i, j}] = {ctype, f};
      }
    }
}

void
HomogenizationConstraint::initialize()
{
  _residual.zero();
  _jacobian.zero();
}

void
HomogenizationConstraint::execute()
{
  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
  {
    Real dV = _JxW[_qp] * _coord[_qp];
    _residual += computeResidual() * dV;
    _jacobian += computeJacobian() * dV;
  }
}

void
HomogenizationConstraint::threadJoin(const UserObject & y)
{
  const HomogenizationConstraint & other = static_cast<const HomogenizationConstraint &>(y);
  _residual += other._residual;
  _jacobian += other._jacobian;
}

void
HomogenizationConstraint::finalize()
{
  std::vector<Real> residual(&_residual(0, 0), &_residual(0, 0) + RankTwoTensor::N2);
  std::vector<Real> jacobian(&_jacobian(0, 0, 0, 0), &_jacobian(0, 0, 0, 0) + RankFourTensor::N4);

  gatherSum(residual);
  gatherSum(jacobian);

  std::copy(residual.begin(), residual.end(), &_residual(0, 0));
  std::copy(jacobian.begin(), jacobian.end(), &_jacobian(0, 0, 0, 0));
}

RankTwoTensor
HomogenizationConstraint::computeResidual()
{
  RankTwoTensor res;

  for (auto && [indices, constraint] : _cmap)
  {
    auto && [i, j] = indices;
    auto && [ctype, ctarget] = constraint;

    if (_large_kinematics)
    {
      if (ctype == Homogenization::ConstraintType::Stress)
        res(i, j) = _pk1_stress[_qp](i, j) - ctarget->value(_t, _q_point[_qp]);
      else if (ctype == Homogenization::ConstraintType::Strain)
        res(i, j) = _F[_qp](i, j) - (Real(i == j) + ctarget->value(_t, _q_point[_qp]));
      else
        mooseError("Unknown constraint type in the integral!");
    }
    else
    {
      if (ctype == Homogenization::ConstraintType::Stress)
        res(i, j) = _pk1_stress[_qp](i, j) - ctarget->value(_t, _q_point[_qp]);
      else if (ctype == Homogenization::ConstraintType::Strain)
        res(i, j) = 0.5 * (_F[_qp](i, j) + _F[_qp](j, i)) -
                    (Real(i == j) + ctarget->value(_t, _q_point[_qp]));
      else
        mooseError("Unknown constraint type in the integral!");
    }
  }

  return res;
}

RankFourTensor
HomogenizationConstraint::computeJacobian()
{
  RankFourTensor res;

  for (auto && [indices1, constraint1] : _cmap)
  {
    auto && [i, j] = indices1;
    auto && ctype = constraint1.first;
    for (auto && indices2 : _cmap)
    {
      auto && [a, b] = indices2.first;
      if (ctype == Homogenization::ConstraintType::Stress)
        res(i, j, a, b) = _pk1_jacobian[_qp](i, j, a, b);
      else if (ctype == Homogenization::ConstraintType::Strain)
      {
        if (_large_kinematics)
          res(i, j, a, b) = Real(i == a && j == b);
        else
          res(i, j, a, b) = 0.5 * Real(i == a && j == b) + 0.5 * Real(i == b && j == a);
      }
      else
        mooseError("Unknown constraint type in Jacobian calculator!");
    }
  }

  return res;
}
<|endoftext|>


<commit_before>/*  This file is part of the KDE project.

Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "videorenderer_vmr9.h"

#ifndef QT_NO_PHONON_VIDEO

#include <QtGui/QWidget>
#include <QtGui/QPainter>
#include <QtCore/QTimerEvent>

#ifndef Q_OS_WINCE
#include <d3d9.h>
#include <vmr9.h>
#else
#include <uuids.h>
#endif

QT_BEGIN_NAMESPACE

namespace Phonon
{
    namespace DS9
    {
        VideoRendererVMR9::~VideoRendererVMR9()
        {
        }

        bool VideoRendererVMR9::isNative() const
        {
            return true;
        }

#ifdef Q_OS_WINCE
        VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target)
        {
            m_target->setAttribute(Qt::WA_PaintOnScreen, true);
            m_filter = Filter(CLSID_VideoRenderer, IID_IBaseFilter);
        }

        QSize VideoRendererVMR9::videoSize() const
        {
            LONG w = 0,
                h = 0;
            ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
            if (basic) {
                basic->GetVideoSize( &w, &h);
            }
            return QSize(w, h);
        }

        void VideoRendererVMR9::repaintCurrentFrame(QWidget * /*target*/, const QRect & /*rect*/)
        {
            //nothing to do here: the renderer paints everything
        }

        void VideoRendererVMR9::notifyResize(const QRect &rect, Phonon::VideoWidget::AspectRatio aspectRatio,
            Phonon::VideoWidget::ScaleMode scaleMode)
        {
            ComPointer<IVideoWindow> video(m_filter, IID_IVideoWindow);

            OAHWND owner;
            HRESULT hr = video->get_Owner(&owner);
            if (FAILED(hr)) {
                return;
            }

            const OAHWND newOwner = reinterpret_cast<OAHWND>(m_target->winId());
            if (owner != newOwner) {
                video->put_Owner(newOwner);
                video->put_MessageDrain(newOwner);
                video->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
            }

            //make sure the widget takes the whole size of the parent
            video->SetWindowPosition(0, 0, rect.width(), rect.height());

            const QSize vsize = videoSize();
            internalNotifyResize(rect.size(), vsize, aspectRatio, scaleMode);

            ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
            if (basic) {
                basic->SetDestinationPosition(m_dstX, m_dstY, m_dstWidth, m_dstHeight);
            }
        }

        void VideoRendererVMR9::applyMixerSettings(qreal /*brightness*/, qreal /*contrast*/, qreal /*m_hue*/, qreal /*saturation*/)
        {
            //this can't be supported for WinCE
        }

        void VideoRendererVMR9::setActive(bool b)
        {
            if (b) {
            } else {
                ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
                if (basic) {
                    basic->SetDestinationPosition(0, 0, 0, 0);
                }
            }
        }

        QImage VideoRendererVMR9::snapshot() const
        {
            ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
            if (basic) {
                LONG bufferSize = 0;
                //1st we get the buffer size
                basic->GetCurrentImage(&bufferSize, 0);

                QByteArray buffer;
                buffer.resize(bufferSize);
                HRESULT hr = basic->GetCurrentImage(&bufferSize, reinterpret_cast<long*>(buffer.data()));

                if (SUCCEEDED(hr)) {

                    const BITMAPINFOHEADER  *bmi = reinterpret_cast<const BITMAPINFOHEADER*>(buffer.constData());

                    const int w = bmi->biWidth,
                        h = bmi->biHeight;

                    // Create image and copy data into image.
                    QImage ret(w, h, QImage::Format_RGB32);

                    if (!ret.isNull()) {
                        const char *data = buffer.constData() + bmi->biSize;
                        const int bytes_per_line = w * sizeof(QRgb);
                        for (int y = h - 1; y >= 0; --y) {
                            qMemCopy(ret.scanLine(y), //destination
                                data,     //source
                                bytes_per_line);
                            data += bytes_per_line;
                        }
                    }
                    return ret;
                }
            }
            return QImage();
        }

#else
        VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target)
        {
            m_target->setAttribute(Qt::WA_PaintOnScreen, true);
            m_filter = Filter(CLSID_VideoMixingRenderer9, IID_IBaseFilter);
            if (!m_filter) {
                qWarning("the video widget could not be initialized correctly");
                return;
            }

            ComPointer<IVMRFilterConfig9> config(m_filter, IID_IVMRFilterConfig9);
            Q_ASSERT(config);
            HRESULT hr = config->SetRenderingMode(VMR9Mode_Windowless);
            Q_ASSERT(SUCCEEDED(hr));
            hr = config->SetNumberOfStreams(1); //for now we limit it to 1 input stream
            Q_ASSERT(SUCCEEDED(hr));
            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
            windowlessControl->SetVideoClippingWindow(reinterpret_cast<HWND>(target->winId()));
        }

        QImage VideoRendererVMR9::snapshot() const
        {
            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
            if (windowlessControl) {
                BYTE *buffer = 0;
                HRESULT hr = windowlessControl->GetCurrentImage(&buffer);
                if (SUCCEEDED(hr)) {

                    const BITMAPINFOHEADER  *bmi = reinterpret_cast<BITMAPINFOHEADER*>(buffer);

                    const int w = bmi->biWidth,
                        h = bmi->biHeight;

                    // Create image and copy data into image.
                    QImage ret(w, h, QImage::Format_RGB32);

                    if (!ret.isNull()) {
                        uchar *data = buffer + bmi->biSize;
                        const int bytes_per_line = w * sizeof(QRgb);
                        for (int y = h - 1; y >= 0; --y) {
                            qMemCopy(ret.scanLine(y), //destination
                                data,     //source
                                bytes_per_line);
                            data += bytes_per_line;
                        }
                    }
                    ::CoTaskMemFree(buffer);
                    return ret;
                }
            }
            return QImage();
        }

        QSize VideoRendererVMR9::videoSize() const
        {
            LONG w = 0,
                h = 0;
            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
            if (windowlessControl) {
                windowlessControl->GetNativeVideoSize( &w, &h, 0, 0);
            }
            return QSize(w, h);
        }

        void VideoRendererVMR9::repaintCurrentFrame(QWidget *target, const QRect &)
        {
            HDC hDC = target->getDC();
            // repaint the video
            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);

            HRESULT hr = windowlessControl ? windowlessControl->RepaintVideo(target->winId(), hDC) : E_POINTER;
            if (FAILED(hr) || m_dstY > 0 || m_dstX > 0 || true) {
                const QColor c = target->palette().color(target->backgroundRole());
                COLORREF color = RGB(c.red(), c.green(), c.blue());
                HPEN hPen = ::CreatePen(PS_SOLID, 1, color);
                HBRUSH hBrush = ::CreateSolidBrush(color);
                ::SelectObject(hDC, hPen);
                ::SelectObject(hDC, hBrush);
                // repaint the video
                if (FAILED(hr)) {
                    //black background : we use the Win32 API to avoid the ghost effect of the backing store
                    ::Rectangle(hDC, 0, 0, target->width(), target->height());
                } else {
                    if (m_dstY > 0) {
                        ::Rectangle(hDC, 0, 0, target->width(), m_dstY); //top
                        ::Rectangle(hDC, 0, target->height() - m_dstY, target->width(), target->height()); //bottom
                    }
                    if (m_dstX > 0) {
                        ::Rectangle(hDC, 0, m_dstY, m_dstX, m_dstHeight + m_dstY); //left
                        ::Rectangle(hDC, m_dstWidth + m_dstX, m_dstY, target->width(), m_dstHeight + m_dstY); //right
                    }
                }
                ::DeleteObject(hPen);
                ::DeleteObject(hBrush);
            }
            target->releaseDC(hDC);

        }

        void VideoRendererVMR9::notifyResize(const QRect &rect, Phonon::VideoWidget::AspectRatio aspectRatio,
            Phonon::VideoWidget::ScaleMode scaleMode)
        {
            const QSize vsize = videoSize();
            internalNotifyResize(rect.size(), vsize, aspectRatio, scaleMode);

            RECT dstRectWin = { m_dstX, m_dstY, m_dstWidth + m_dstX, m_dstHeight + m_dstY};
            RECT srcRectWin = { 0, 0, vsize.width(), vsize.height()};

            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
            if (windowlessControl) {
                windowlessControl->SetVideoPosition(&srcRectWin, &dstRectWin);
            }
        }

        void VideoRendererVMR9::setActive(bool b)
        {
            if (b) {
            } else {
                RECT dummyRect = { 0, 0, 0, 0};
                ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
                windowlessControl->SetVideoPosition(&dummyRect, &dummyRect);
            }
        }

        void VideoRendererVMR9::applyMixerSettings(qreal brightness, qreal contrast, qreal hue, qreal saturation)
        {
            InputPin sink = BackendNode::pins(m_filter, PINDIR_INPUT).first();
            OutputPin source;
            if (FAILED(sink->ConnectedTo(source.pparam()))) {
                return; //it must be connected to work
            }

            //get the mixer (used for brightness/contrast/saturation/hue)
            ComPointer<IVMRMixerControl9> mixer(m_filter, IID_IVMRMixerControl9);
            Q_ASSERT(mixer);

            VMR9ProcAmpControl ctrl;
            ctrl.dwSize = sizeof(ctrl);
            ctrl.dwFlags = ProcAmpControl9_Contrast | ProcAmpControl9_Brightness | ProcAmpControl9_Saturation | ProcAmpControl9_Hue;
            VMR9ProcAmpControlRange range;
            range.dwSize = sizeof(range);

            range.dwProperty = ProcAmpControl9_Contrast;
            HRESULT hr = mixer->GetProcAmpControlRange(0, &range);
            if (FAILED(hr)) {
                return;
            }
            ctrl.Contrast = ((contrast < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(contrast) + range.DefaultValue;

            //brightness
            range.dwProperty = ProcAmpControl9_Brightness;
            hr = mixer->GetProcAmpControlRange(0, &range);
            if (FAILED(hr)) {
                return;
            }
            ctrl.Brightness = ((brightness < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(brightness) + range.DefaultValue;

            //saturation
            range.dwProperty = ProcAmpControl9_Saturation;
            hr = mixer->GetProcAmpControlRange(0, &range);
            if (FAILED(hr)) {
                return;
            }
            ctrl.Saturation = ((saturation < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(saturation) + range.DefaultValue;

            //hue
            range.dwProperty = ProcAmpControl9_Hue;
            hr = mixer->GetProcAmpControlRange(0, &range);
            if (FAILED(hr)) {
                return;
            }
            ctrl.Hue = ((hue < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(hue) + range.DefaultValue;

            //finally set the settings
            mixer->SetProcAmpControl(0, &ctrl);
        }
#endif
    }
}

QT_END_NAMESPACE

#endif //QT_NO_PHONON_VIDEO
<commit_msg>make the video widget compatible with Qt 4.5 new paint engine<commit_after>/*  This file is part of the KDE project.

Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "videorenderer_vmr9.h"

#ifndef QT_NO_PHONON_VIDEO

#include <QtGui/QWidget>
#include <QtGui/QPainter>
#include <QtCore/QTimerEvent>

#ifndef Q_OS_WINCE
#include <d3d9.h>
#include <vmr9.h>
#else
#include <uuids.h>
#endif

QT_BEGIN_NAMESPACE

namespace Phonon
{
    namespace DS9
    {
        VideoRendererVMR9::~VideoRendererVMR9()
        {
        }

        bool VideoRendererVMR9::isNative() const
        {
            return true;
        }

#ifdef Q_OS_WINCE
        VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target)
        {
            m_target->setAttribute(Qt::WA_PaintOnScreen, true);
            m_filter = Filter(CLSID_VideoRenderer, IID_IBaseFilter);
        }

        QSize VideoRendererVMR9::videoSize() const
        {
            LONG w = 0,
                h = 0;
            ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
            if (basic) {
                basic->GetVideoSize( &w, &h);
            }
            return QSize(w, h);
        }

        void VideoRendererVMR9::repaintCurrentFrame(QWidget * /*target*/, const QRect & /*rect*/)
        {
            //nothing to do here: the renderer paints everything
        }

        void VideoRendererVMR9::notifyResize(const QRect &rect, Phonon::VideoWidget::AspectRatio aspectRatio,
            Phonon::VideoWidget::ScaleMode scaleMode)
        {
            ComPointer<IVideoWindow> video(m_filter, IID_IVideoWindow);

            OAHWND owner;
            HRESULT hr = video->get_Owner(&owner);
            if (FAILED(hr)) {
                return;
            }

            const OAHWND newOwner = reinterpret_cast<OAHWND>(m_target->winId());
            if (owner != newOwner) {
                video->put_Owner(newOwner);
                video->put_MessageDrain(newOwner);
                video->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
            }

            //make sure the widget takes the whole size of the parent
            video->SetWindowPosition(0, 0, rect.width(), rect.height());

            const QSize vsize = videoSize();
            internalNotifyResize(rect.size(), vsize, aspectRatio, scaleMode);

            ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
            if (basic) {
                basic->SetDestinationPosition(m_dstX, m_dstY, m_dstWidth, m_dstHeight);
            }
        }

        void VideoRendererVMR9::applyMixerSettings(qreal /*brightness*/, qreal /*contrast*/, qreal /*m_hue*/, qreal /*saturation*/)
        {
            //this can't be supported for WinCE
        }

        void VideoRendererVMR9::setActive(bool b)
        {
            if (b) {
            } else {
                ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
                if (basic) {
                    basic->SetDestinationPosition(0, 0, 0, 0);
                }
            }
        }

        QImage VideoRendererVMR9::snapshot() const
        {
            ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
            if (basic) {
                LONG bufferSize = 0;
                //1st we get the buffer size
                basic->GetCurrentImage(&bufferSize, 0);

                QByteArray buffer;
                buffer.resize(bufferSize);
                HRESULT hr = basic->GetCurrentImage(&bufferSize, reinterpret_cast<long*>(buffer.data()));

                if (SUCCEEDED(hr)) {

                    const BITMAPINFOHEADER  *bmi = reinterpret_cast<const BITMAPINFOHEADER*>(buffer.constData());

                    const int w = bmi->biWidth,
                        h = bmi->biHeight;

                    // Create image and copy data into image.
                    QImage ret(w, h, QImage::Format_RGB32);

                    if (!ret.isNull()) {
                        const char *data = buffer.constData() + bmi->biSize;
                        const int bytes_per_line = w * sizeof(QRgb);
                        for (int y = h - 1; y >= 0; --y) {
                            qMemCopy(ret.scanLine(y), //destination
                                data,     //source
                                bytes_per_line);
                            data += bytes_per_line;
                        }
                    }
                    return ret;
                }
            }
            return QImage();
        }

#else
        VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target)
        {
            m_target->setAttribute(Qt::WA_PaintOnScreen, true);
            m_filter = Filter(CLSID_VideoMixingRenderer9, IID_IBaseFilter);
            if (!m_filter) {
                qWarning("the video widget could not be initialized correctly");
                return;
            }

            ComPointer<IVMRFilterConfig9> config(m_filter, IID_IVMRFilterConfig9);
            Q_ASSERT(config);
            HRESULT hr = config->SetRenderingMode(VMR9Mode_Windowless);
            Q_ASSERT(SUCCEEDED(hr));
            hr = config->SetNumberOfStreams(1); //for now we limit it to 1 input stream
            Q_ASSERT(SUCCEEDED(hr));
            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
            windowlessControl->SetVideoClippingWindow(reinterpret_cast<HWND>(target->winId()));
        }

        QImage VideoRendererVMR9::snapshot() const
        {
            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
            if (windowlessControl) {
                BYTE *buffer = 0;
                HRESULT hr = windowlessControl->GetCurrentImage(&buffer);
                if (SUCCEEDED(hr)) {

                    const BITMAPINFOHEADER  *bmi = reinterpret_cast<BITMAPINFOHEADER*>(buffer);

                    const int w = bmi->biWidth,
                        h = bmi->biHeight;

                    // Create image and copy data into image.
                    QImage ret(w, h, QImage::Format_RGB32);

                    if (!ret.isNull()) {
                        uchar *data = buffer + bmi->biSize;
                        const int bytes_per_line = w * sizeof(QRgb);
                        for (int y = h - 1; y >= 0; --y) {
                            qMemCopy(ret.scanLine(y), //destination
                                data,     //source
                                bytes_per_line);
                            data += bytes_per_line;
                        }
                    }
                    ::CoTaskMemFree(buffer);
                    return ret;
                }
            }
            return QImage();
        }

        QSize VideoRendererVMR9::videoSize() const
        {
            LONG w = 0,
                h = 0;
            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
            if (windowlessControl) {
                windowlessControl->GetNativeVideoSize( &w, &h, 0, 0);
            }
            return QSize(w, h);
        }

        void VideoRendererVMR9::repaintCurrentFrame(QWidget *target, const QRect &)
        {
            HDC hDC = target->getDC();
            // repaint the video
            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);

            HRESULT hr = windowlessControl ? windowlessControl->RepaintVideo(target->winId(), hDC) : E_POINTER;
            if (FAILED(hr) || m_dstY > 0 || m_dstX > 0) {
                const QColor c = target->palette().color(target->backgroundRole());
                COLORREF color = RGB(c.red(), c.green(), c.blue());
                HPEN hPen = ::CreatePen(PS_SOLID, 1, color);
                HBRUSH hBrush = ::CreateSolidBrush(color);
                ::SelectObject(hDC, hPen);
                ::SelectObject(hDC, hBrush);
                // repaint the video
                if (FAILED(hr)) {
                    //black background : we use the Win32 API to avoid the ghost effect of the backing store
                    ::Rectangle(hDC, 0, 0, target->width(), target->height());
                } else {
                    if (m_dstY > 0) {
                        ::Rectangle(hDC, 0, 0, target->width(), m_dstY); //top
                        ::Rectangle(hDC, 0, target->height() - m_dstY, target->width(), target->height()); //bottom
                    }
                    if (m_dstX > 0) {
                        ::Rectangle(hDC, 0, m_dstY, m_dstX, m_dstHeight + m_dstY); //left
                        ::Rectangle(hDC, m_dstWidth + m_dstX, m_dstY, target->width(), m_dstHeight + m_dstY); //right
                    }
                }
                ::DeleteObject(hPen);
                ::DeleteObject(hBrush);
            }
            target->releaseDC(hDC);

        }

        void VideoRendererVMR9::notifyResize(const QRect &rect, Phonon::VideoWidget::AspectRatio aspectRatio,
            Phonon::VideoWidget::ScaleMode scaleMode)
        {
            const QSize vsize = videoSize();
            internalNotifyResize(rect.size(), vsize, aspectRatio, scaleMode);

            RECT dstRectWin = { m_dstX, m_dstY, m_dstWidth + m_dstX, m_dstHeight + m_dstY};
            RECT srcRectWin = { 0, 0, vsize.width(), vsize.height()};

            ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
            if (windowlessControl) {
                windowlessControl->SetVideoPosition(&srcRectWin, &dstRectWin);
            }
        }

        void VideoRendererVMR9::setActive(bool b)
        {
            if (b) {
            } else {
                RECT dummyRect = { 0, 0, 0, 0};
                ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
                windowlessControl->SetVideoPosition(&dummyRect, &dummyRect);
            }
        }

        void VideoRendererVMR9::applyMixerSettings(qreal brightness, qreal contrast, qreal hue, qreal saturation)
        {
            InputPin sink = BackendNode::pins(m_filter, PINDIR_INPUT).first();
            OutputPin source;
            if (FAILED(sink->ConnectedTo(source.pparam()))) {
                return; //it must be connected to work
            }

            //get the mixer (used for brightness/contrast/saturation/hue)
            ComPointer<IVMRMixerControl9> mixer(m_filter, IID_IVMRMixerControl9);
            Q_ASSERT(mixer);

            VMR9ProcAmpControl ctrl;
            ctrl.dwSize = sizeof(ctrl);
            ctrl.dwFlags = ProcAmpControl9_Contrast | ProcAmpControl9_Brightness | ProcAmpControl9_Saturation | ProcAmpControl9_Hue;
            VMR9ProcAmpControlRange range;
            range.dwSize = sizeof(range);

            range.dwProperty = ProcAmpControl9_Contrast;
            HRESULT hr = mixer->GetProcAmpControlRange(0, &range);
            if (FAILED(hr)) {
                return;
            }
            ctrl.Contrast = ((contrast < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(contrast) + range.DefaultValue;

            //brightness
            range.dwProperty = ProcAmpControl9_Brightness;
            hr = mixer->GetProcAmpControlRange(0, &range);
            if (FAILED(hr)) {
                return;
            }
            ctrl.Brightness = ((brightness < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(brightness) + range.DefaultValue;

            //saturation
            range.dwProperty = ProcAmpControl9_Saturation;
            hr = mixer->GetProcAmpControlRange(0, &range);
            if (FAILED(hr)) {
                return;
            }
            ctrl.Saturation = ((saturation < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(saturation) + range.DefaultValue;

            //hue
            range.dwProperty = ProcAmpControl9_Hue;
            hr = mixer->GetProcAmpControlRange(0, &range);
            if (FAILED(hr)) {
                return;
            }
            ctrl.Hue = ((hue < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(hue) + range.DefaultValue;

            //finally set the settings
            mixer->SetProcAmpControl(0, &ctrl);
        }
#endif
    }
}

QT_END_NAMESPACE

#endif //QT_NO_PHONON_VIDEO
<|endoftext|>


<commit_before>//===-- StackProtector.cpp - Stack Protector Insertion --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass inserts stack protectors into functions which need them. A variable
// with a random value in it is stored onto the stack before the local variables
// are allocated. Upon exiting the block, the stored value is checked. If it's
// changed, then there was some sort of violation and the program aborts.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "stack-protector"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Attributes.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;

// SSPBufferSize - The lower bound for a buffer to be considered for stack
// smashing protection.
static cl::opt<unsigned>
SSPBufferSize("stack-protector-buffer-size", cl::init(8),
              cl::desc("Lower bound for a buffer to be considered for "
                       "stack protection"));

namespace {
  class StackProtector : public FunctionPass {
    /// TLI - Keep a pointer of a TargetLowering to consult for determining
    /// target type sizes.
    const TargetLowering *TLI;

    Function *F;
    Module *M;

    DominatorTree* DT;

    /// InsertStackProtectors - Insert code into the prologue and epilogue of
    /// the function.
    ///
    ///  - The prologue code loads and stores the stack guard onto the stack.
    ///  - The epilogue checks the value stored in the prologue against the
    ///    original value. It calls __stack_chk_fail if they differ.
    bool InsertStackProtectors();

    /// CreateFailBB - Create a basic block to jump to when the stack protector
    /// check fails.
    BasicBlock *CreateFailBB();

    /// RequiresStackProtector - Check whether or not this function needs a
    /// stack protector based upon the stack protector level.
    bool RequiresStackProtector() const;
  public:
    static char ID;             // Pass identification, replacement for typeid.
    StackProtector() : FunctionPass(ID), TLI(0) {
      initializeStackProtectorPass(*PassRegistry::getPassRegistry());
    }
    StackProtector(const TargetLowering *tli)
      : FunctionPass(ID), TLI(tli) {
        initializeStackProtectorPass(*PassRegistry::getPassRegistry());
      }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addPreserved<DominatorTree>();
    }

    virtual bool runOnFunction(Function &Fn);
  };
} // end anonymous namespace

char StackProtector::ID = 0;
INITIALIZE_PASS(StackProtector, "stack-protector",
                "Insert stack protectors", false, false)

FunctionPass *llvm::createStackProtectorPass(const TargetLowering *tli) {
  return new StackProtector(tli);
}

bool StackProtector::runOnFunction(Function &Fn) {
  F = &Fn;
  M = F->getParent();
  DT = getAnalysisIfAvailable<DominatorTree>();

  if (!RequiresStackProtector()) return false;

  return InsertStackProtectors();
}

/// RequiresStackProtector - Check whether or not this function needs a stack
/// protector based upon the stack protector level. The heuristic we use is to
/// add a guard variable to functions that call alloca, and functions with
/// buffers larger than SSPBufferSize bytes.
bool StackProtector::RequiresStackProtector() const {
  if (F->hasFnAttr(Attribute::StackProtectReq))
    return true;

  if (!F->hasFnAttr(Attribute::StackProtect))
    return false;

  const TargetData *TD = TLI->getTargetData();

  for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
    BasicBlock *BB = I;

    for (BasicBlock::iterator
           II = BB->begin(), IE = BB->end(); II != IE; ++II)
      if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
        if (AI->isArrayAllocation())
          // This is a call to alloca with a variable size. Emit stack
          // protectors.
          return true;

        if (const ArrayType *AT = dyn_cast<ArrayType>(AI->getAllocatedType())) {
          // We apparently only care about character arrays.
          if (!AT->getElementType()->isIntegerTy(8))
            continue;

          // If an array has more than SSPBufferSize bytes of allocated space,
          // then we emit stack protectors.
          if (SSPBufferSize <= TD->getTypeAllocSize(AT))
            return true;
        }
      }
  }

  return false;
}

/// InsertStackProtectors - Insert code into the prologue and epilogue of the
/// function.
///
///  - The prologue code loads and stores the stack guard onto the stack.
///  - The epilogue checks the value stored in the prologue against the original
///    value. It calls __stack_chk_fail if they differ.
bool StackProtector::InsertStackProtectors() {
  BasicBlock *FailBB = 0;       // The basic block to jump to if check fails.
  BasicBlock *FailBBDom = 0;    // FailBB's dominator.
  AllocaInst *AI = 0;           // Place on stack that stores the stack guard.
  Value *StackGuardVar = 0;  // The stack guard variable.

  for (Function::iterator I = F->begin(), E = F->end(); I != E; ) {
    BasicBlock *BB = I++;
    ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator());
    if (!RI) continue;

    if (!FailBB) {
      // Insert code into the entry block that stores the __stack_chk_guard
      // variable onto the stack:
      //
      //   entry:
      //     StackGuardSlot = alloca i8*
      //     StackGuard = load __stack_chk_guard
      //     call void @llvm.stackprotect.create(StackGuard, StackGuardSlot)
      //
      const PointerType *PtrTy = Type::getInt8PtrTy(RI->getContext());
      unsigned AddressSpace, Offset;
      if (TLI->getStackCookieLocation(AddressSpace, Offset)) {
        Constant *OffsetVal =
          ConstantInt::get(Type::getInt32Ty(RI->getContext()), Offset);

        StackGuardVar = ConstantExpr::getIntToPtr(OffsetVal,
                                      PointerType::get(PtrTy, AddressSpace));
      } else {
        StackGuardVar = M->getOrInsertGlobal("__stack_chk_guard", PtrTy);
      }

      BasicBlock &Entry = F->getEntryBlock();
      Instruction *InsPt = &Entry.front();

      AI = new AllocaInst(PtrTy, "StackGuardSlot", InsPt);
      LoadInst *LI = new LoadInst(StackGuardVar, "StackGuard", false, InsPt);

      Value *Args[] = { LI, AI };
      CallInst::
        Create(Intrinsic::getDeclaration(M, Intrinsic::stackprotector),
               &Args[0], array_endof(Args), "", InsPt);

      // Create the basic block to jump to when the guard check fails.
      FailBB = CreateFailBB();
    }

    // For each block with a return instruction, convert this:
    //
    //   return:
    //     ...
    //     ret ...
    //
    // into this:
    //
    //   return:
    //     ...
    //     %1 = load __stack_chk_guard
    //     %2 = load StackGuardSlot
    //     %3 = cmp i1 %1, %2
    //     br i1 %3, label %SP_return, label %CallStackCheckFailBlk
    //
    //   SP_return:
    //     ret ...
    //
    //   CallStackCheckFailBlk:
    //     call void @__stack_chk_fail()
    //     unreachable

    // Split the basic block before the return instruction.
    bool BBIsReachable = (DT && DT->isReachableFromEntry(BB));
    BasicBlock *NewBB = BB->splitBasicBlock(RI, "SP_return");

    if (BBIsReachable) {
      DT->addNewBlock(NewBB, BB);
      FailBBDom = FailBBDom ? DT->findNearestCommonDominator(FailBBDom, BB) :BB;
    }

    // Remove default branch instruction to the new BB.
    BB->getTerminator()->eraseFromParent();

    // Move the newly created basic block to the point right after the old basic
    // block so that it's in the "fall through" position.
    NewBB->moveAfter(BB);

    // Generate the stack protector instructions in the old basic block.
    LoadInst *LI1 = new LoadInst(StackGuardVar, "", false, BB);
    LoadInst *LI2 = new LoadInst(AI, "", true, BB);
    ICmpInst *Cmp = new ICmpInst(*BB, CmpInst::ICMP_EQ, LI1, LI2, "");
    BranchInst::Create(NewBB, FailBB, Cmp, BB);
  }

  // Return if we didn't modify any basic blocks. I.e., there are no return
  // statements in the function.
  if (!FailBB) return false;

  if (DT && FailBBDom)
    DT->addNewBlock(FailBB, FailBBDom);

  return true;
}

/// CreateFailBB - Create a basic block to jump to when the stack protector
/// check fails.
BasicBlock *StackProtector::CreateFailBB() {
  BasicBlock *FailBB = BasicBlock::Create(F->getContext(),
                                          "CallStackCheckFailBlk", F);
  Constant *StackChkFail =
    M->getOrInsertFunction("__stack_chk_fail",
                           Type::getVoidTy(F->getContext()), NULL);
  CallInst::Create(StackChkFail, "", FailBB);
  new UnreachableInst(F->getContext(), FailBB);
  return FailBB;
}
<commit_msg>Inline check that's used only once.<commit_after>//===-- StackProtector.cpp - Stack Protector Insertion --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass inserts stack protectors into functions which need them. A variable
// with a random value in it is stored onto the stack before the local variables
// are allocated. Upon exiting the block, the stored value is checked. If it's
// changed, then there was some sort of violation and the program aborts.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "stack-protector"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Attributes.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;

// SSPBufferSize - The lower bound for a buffer to be considered for stack
// smashing protection.
static cl::opt<unsigned>
SSPBufferSize("stack-protector-buffer-size", cl::init(8),
              cl::desc("Lower bound for a buffer to be considered for "
                       "stack protection"));

namespace {
  class StackProtector : public FunctionPass {
    /// TLI - Keep a pointer of a TargetLowering to consult for determining
    /// target type sizes.
    const TargetLowering *TLI;

    Function *F;
    Module *M;

    DominatorTree* DT;

    /// InsertStackProtectors - Insert code into the prologue and epilogue of
    /// the function.
    ///
    ///  - The prologue code loads and stores the stack guard onto the stack.
    ///  - The epilogue checks the value stored in the prologue against the
    ///    original value. It calls __stack_chk_fail if they differ.
    bool InsertStackProtectors();

    /// CreateFailBB - Create a basic block to jump to when the stack protector
    /// check fails.
    BasicBlock *CreateFailBB();

    /// RequiresStackProtector - Check whether or not this function needs a
    /// stack protector based upon the stack protector level.
    bool RequiresStackProtector() const;
  public:
    static char ID;             // Pass identification, replacement for typeid.
    StackProtector() : FunctionPass(ID), TLI(0) {
      initializeStackProtectorPass(*PassRegistry::getPassRegistry());
    }
    StackProtector(const TargetLowering *tli)
      : FunctionPass(ID), TLI(tli) {
        initializeStackProtectorPass(*PassRegistry::getPassRegistry());
      }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addPreserved<DominatorTree>();
    }

    virtual bool runOnFunction(Function &Fn);
  };
} // end anonymous namespace

char StackProtector::ID = 0;
INITIALIZE_PASS(StackProtector, "stack-protector",
                "Insert stack protectors", false, false)

FunctionPass *llvm::createStackProtectorPass(const TargetLowering *tli) {
  return new StackProtector(tli);
}

bool StackProtector::runOnFunction(Function &Fn) {
  F = &Fn;
  M = F->getParent();
  DT = getAnalysisIfAvailable<DominatorTree>();

  if (!RequiresStackProtector()) return false;

  return InsertStackProtectors();
}

/// RequiresStackProtector - Check whether or not this function needs a stack
/// protector based upon the stack protector level. The heuristic we use is to
/// add a guard variable to functions that call alloca, and functions with
/// buffers larger than SSPBufferSize bytes.
bool StackProtector::RequiresStackProtector() const {
  if (F->hasFnAttr(Attribute::StackProtectReq))
    return true;

  if (!F->hasFnAttr(Attribute::StackProtect))
    return false;

  const TargetData *TD = TLI->getTargetData();

  for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
    BasicBlock *BB = I;

    for (BasicBlock::iterator
           II = BB->begin(), IE = BB->end(); II != IE; ++II)
      if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
        if (AI->isArrayAllocation())
          // This is a call to alloca with a variable size. Emit stack
          // protectors.
          return true;

        if (const ArrayType *AT = dyn_cast<ArrayType>(AI->getAllocatedType())) {
          // We apparently only care about character arrays.
          if (!AT->getElementType()->isIntegerTy(8))
            continue;

          // If an array has more than SSPBufferSize bytes of allocated space,
          // then we emit stack protectors.
          if (SSPBufferSize <= TD->getTypeAllocSize(AT))
            return true;
        }
      }
  }

  return false;
}

/// InsertStackProtectors - Insert code into the prologue and epilogue of the
/// function.
///
///  - The prologue code loads and stores the stack guard onto the stack.
///  - The epilogue checks the value stored in the prologue against the original
///    value. It calls __stack_chk_fail if they differ.
bool StackProtector::InsertStackProtectors() {
  BasicBlock *FailBB = 0;       // The basic block to jump to if check fails.
  BasicBlock *FailBBDom = 0;    // FailBB's dominator.
  AllocaInst *AI = 0;           // Place on stack that stores the stack guard.
  Value *StackGuardVar = 0;  // The stack guard variable.

  for (Function::iterator I = F->begin(), E = F->end(); I != E; ) {
    BasicBlock *BB = I++;
    ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator());
    if (!RI) continue;

    if (!FailBB) {
      // Insert code into the entry block that stores the __stack_chk_guard
      // variable onto the stack:
      //
      //   entry:
      //     StackGuardSlot = alloca i8*
      //     StackGuard = load __stack_chk_guard
      //     call void @llvm.stackprotect.create(StackGuard, StackGuardSlot)
      //
      const PointerType *PtrTy = Type::getInt8PtrTy(RI->getContext());
      unsigned AddressSpace, Offset;
      if (TLI->getStackCookieLocation(AddressSpace, Offset)) {
        Constant *OffsetVal =
          ConstantInt::get(Type::getInt32Ty(RI->getContext()), Offset);

        StackGuardVar = ConstantExpr::getIntToPtr(OffsetVal,
                                      PointerType::get(PtrTy, AddressSpace));
      } else {
        StackGuardVar = M->getOrInsertGlobal("__stack_chk_guard", PtrTy);
      }

      BasicBlock &Entry = F->getEntryBlock();
      Instruction *InsPt = &Entry.front();

      AI = new AllocaInst(PtrTy, "StackGuardSlot", InsPt);
      LoadInst *LI = new LoadInst(StackGuardVar, "StackGuard", false, InsPt);

      Value *Args[] = { LI, AI };
      CallInst::
        Create(Intrinsic::getDeclaration(M, Intrinsic::stackprotector),
               &Args[0], array_endof(Args), "", InsPt);

      // Create the basic block to jump to when the guard check fails.
      FailBB = CreateFailBB();
    }

    // For each block with a return instruction, convert this:
    //
    //   return:
    //     ...
    //     ret ...
    //
    // into this:
    //
    //   return:
    //     ...
    //     %1 = load __stack_chk_guard
    //     %2 = load StackGuardSlot
    //     %3 = cmp i1 %1, %2
    //     br i1 %3, label %SP_return, label %CallStackCheckFailBlk
    //
    //   SP_return:
    //     ret ...
    //
    //   CallStackCheckFailBlk:
    //     call void @__stack_chk_fail()
    //     unreachable

    // Split the basic block before the return instruction.
    BasicBlock *NewBB = BB->splitBasicBlock(RI, "SP_return");

    if (DT && DT->isReachableFromEntry(BB)) {
      DT->addNewBlock(NewBB, BB);
      FailBBDom = FailBBDom ? DT->findNearestCommonDominator(FailBBDom, BB) :BB;
    }

    // Remove default branch instruction to the new BB.
    BB->getTerminator()->eraseFromParent();

    // Move the newly created basic block to the point right after the old basic
    // block so that it's in the "fall through" position.
    NewBB->moveAfter(BB);

    // Generate the stack protector instructions in the old basic block.
    LoadInst *LI1 = new LoadInst(StackGuardVar, "", false, BB);
    LoadInst *LI2 = new LoadInst(AI, "", true, BB);
    ICmpInst *Cmp = new ICmpInst(*BB, CmpInst::ICMP_EQ, LI1, LI2, "");
    BranchInst::Create(NewBB, FailBB, Cmp, BB);
  }

  // Return if we didn't modify any basic blocks. I.e., there are no return
  // statements in the function.
  if (!FailBB) return false;

  if (DT && FailBBDom)
    DT->addNewBlock(FailBB, FailBBDom);

  return true;
}

/// CreateFailBB - Create a basic block to jump to when the stack protector
/// check fails.
BasicBlock *StackProtector::CreateFailBB() {
  BasicBlock *FailBB = BasicBlock::Create(F->getContext(),
                                          "CallStackCheckFailBlk", F);
  Constant *StackChkFail =
    M->getOrInsertFunction("__stack_chk_fail",
                           Type::getVoidTy(F->getContext()), NULL);
  CallInst::Create(StackChkFail, "", FailBB);
  new UnreachableInst(F->getContext(), FailBB);
  return FailBB;
}
<|endoftext|>