<commit_before>#pragma once
/*------------------------------------------------------------------------
  This is based on Paul Heckbert's "business card raytracer".
  His site is: http://www.cs.cmu.edu/~ph/

  I modified it a lot adding colors/materials, arbitrary sphere
  positions, etc.

  I also added some comments and made it readable. The original
  code was designed to be small enough to print on the back of
  a business card (hence the name) so it was very hard to read.

  FTB.
------------------------------------------------------------------------*/
#include <cmath>
#include <cstdint>

extern "C" {
	void draw_pixel(int x, int y, int r, int g, int b);
};

/*------------------------------------------------------------------------
  (For non-arduino platforms)
------------------------------------------------------------------------*/
#ifndef PROGMEM
#define PROGMEM
float pgm_read_float(const float *f) {  return *f;  }
#endif

/*------------------------------------------------------------------------
  Values you can play with...
------------------------------------------------------------------------*/

// Position of the camera (nb. 'Z' is up/down)
static const float cameraX = 0.0;
static const float cameraY = 0.0;
static const float cameraZ = 3.0;

// What the camera is pointing at
static const float targetX = 1.0;
static const float targetY = 8.0;
static const float targetZ = 4.0;

// We cast this many rays per pixel for stochastic antialiasing and soft-shadows.
//
// Large numbers produce a nicer image but it runs a lot slower
//static const int raysPerPixel = 4;

// The camera's field of view, smaller=>zoom, larger=>wide angle
static const float fov = 0.45f;

// The size of the soft shadow, larger=>wider area
static const float shadowRegion = 0.125f;

/*------------------------------------------------------------------------
  Materials
------------------------------------------------------------------------*/
static const float ambient = 0.05f;
static const float materials[] PROGMEM = {
// R,    G,    B,   REFLECTIVITY
  0.8f, 0.8f, 0.8f,   0.5f,    // Mirror
//  1.0f, 0.0f, 0.0f,   0.3f,    // Red
  0.0f, 1.0f, 0.0f,   0.2f,    // Green
//  0.0f, 0.0f, 0.1f,   0.3f     // Dark blue
  0.0f, 0.8f, 0.8f,   0.3f     // Cyan
};

/*------------------------------------------------------------------------
  The spheres in the world
------------------------------------------------------------------------*/
#define NUM_SPHERES 4
static const float spheres[] PROGMEM = {
// center  radius material
   5,15,8,   5,     0,
  -6,12,4,   3,     0,
   1,10,2,   2,     1,
   0, 9,5,   1,     2
};

/*------------------------------------------------------------------------
  A 3D vector class
------------------------------------------------------------------------*/
struct vec3 {
  float x,y,z;  // Vector has three float attributes.
  vec3(){}
  vec3(float a, float b, float c){x=a;y=b;z=c;}
  vec3 operator+(const vec3& v) const { return vec3(x+v.x,y+v.y,z+v.z);  }    // Vector add
  vec3 operator-(const vec3& v) const { return (*this)+(v*-1);           }    // Vector subtract
  vec3 operator*(float s)       const { return vec3(x*s,y*s,z*s);        }    // Vector scale
  float operator%(const vec3& v)const { return x*v.x+y*v.y+z*v.z;        }    // Scalar product
  vec3 operator^(const vec3& v) const { return vec3(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x);  } // Vector product
  vec3 operator!()              const { return *this*(1.0/sqrt(*this%*this));  }  // Normalized vector
  void operator+=(const vec3& v)      { x+=v.x;  y+=v.y;  z+=v.z;        }
  void operator*=(float s)            { x*=s;    y*=s;    z*=s;          }
};

// A ray...
struct ray {
  // This occupies 24 bytes - you could only fit 20 of these into
  // a Tiny85 even if you could use the entire RAM (which you can't...)
  vec3 o;  // Origin
  vec3 d;  // Direction
};

/*------------------------------------------------------------------------
  Intersect a ray with the world
  Return 'SKY' if no hit was found but ray goes upward
  Return 'FLOOR' if no hit was found but ray goes downward towards the floor
  Return a material index if a hit was found

  Distance to the hit is returned in 'distance'.
  The surface normal at the hit is returned in 'normal'
------------------------------------------------------------------------*/
// Values for 'SKY' and 'FLOOR'
static const uint8_t SKY=255;
static const uint8_t FLOOR=254;

uint8_t trace(const ray& r, float& distance, vec3& normal)
{
  // Assume we didn't hit anything
  uint8_t result = SKY;

  // Does the ray go downwards?
  float d = -r.o.z/r.d.z;
  if (d > 0.01) {
    // Yes, assume it hits the floor
    result = true;
    distance = d;
    result = FLOOR;
    normal = vec3(0,0,1);
  }

  // Test the objects in the scene to see if there's anything in the way
  for (uint8_t i=0; i<NUM_SPHERES; ++i) {
    vec3 oc = r.o;
    // Read a sphere from progmem, calculate vector 'oc'
    const float *n = spheres+(i*5);
    oc.x -= pgm_read_float(n++);
    oc.y -= pgm_read_float(n++);
    oc.z -= pgm_read_float(n++);
    d = pgm_read_float(n++);  // Radius

    // Ray-sphere intersection test
    // Math is here: http://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection
    const float b = r.d%oc;        // I.(o-c)
    const float c = (oc%oc)-(d*d); // (o-c).(o-c) - r^2

    // Does the ray hit the sphere?
    d = (b*b)-c;
    if (d > 0) {
      // Yes, compute the distance to the hit
      d = (-b)-sqrt(d);

      // Is it the closest hit so far?
      if ((d > 0.01) and ((result==SKY) or (d<distance))) {
        // Yes, save results
        distance = d;
        normal = !(oc+r.d*d);
        result = uint8_t(pgm_read_float(n));  // The sphere's material
      }
    }
  }
  return result;
}
float raise(float p, uint8_t n)
{
  while (n--) {
    p = p*p;
  }
  return p;
}

/*----------------------------------------------------------
  Small, fast pseudo-random number generator

  I found this in a forum and I'm not sure who originally
  wrote it. It works very well though....

  If you wrote this then get in touch and I'll put
  your name here. :-)                              FTB.
----------------------------------------------------------*/
uint8_t randomByte()
{
  static uint8_t rngA, rngB, rngC, rngX;
  ++rngX;                        // X is incremented every round and is not affected by any other variable
  rngA = (rngA ^ rngC ^ rngX);       // note the mix of addition and XOR
  rngB = (rngB + rngA);            // And the use of very few instructions
  rngC = ((rngC + (rngB >> 1)) ^ rngA);  // the right shift is to ensure that high-order bits from B can affect
  return rngC;
}

// A random float in the range [-0.5 ... 0.5]  (more or less)
float randomFloat()
{
  char r = char(randomByte());
  return float(r)/256.0;
}
#define RF randomFloat()
#define SH (RF*shadowRegion)

/*------------------------------------------------------------------------
  Sample the world and return the pixel color for a ray
------------------------------------------------------------------------*/
float sample(ray& r, vec3& color)
{
  // See if the ray hits anything in the world
  float t;  vec3& n = color;      // RAM is tight, use 'color' as temp workspace
  const uint8_t hit = trace(r,t,n);

  // Did we hit anything
  if (hit == SKY) {
    // Generate a sky color if the ray goes upwards without hitting anything
    color = vec3(0.1f,0.0f,0.3f) + vec3(.7f,.2f,0.5f)*raise(1.0-r.d.z,2);
    return 0.0;
  }

  // New ray origin
  r.o += r.d*t;

  // Half vector
  const vec3 half = !(r.d+n*((n%r.d)*-2));

// Vector that points towards the light
  r.d = vec3(9+SH, 6+SH,16); // Where the light is
  r.d = !(r.d-r.o);          // Normalized light vector

  // Lambertian factor
  float d = r.d%n;    // Light vector % surface normal

  // See if we're in shadow
  if ((d<0) or (trace(r,t,n)!=SKY)) {
    d = 0;
  }

  // Did we hit the floor?
  if (hit == FLOOR) {
    // Yes, generate a floor color
    d=(d*0.2)+0.1;   t=d*3.0;  // d=dark, t=light
    color = vec3(t,t,t);       // Assume grey color
    t = 1.0f/5.0f;     // Floor tiles are 5m across
//    int fx = int(ceil(r.o.x*t));
//    int fy = int(ceil(r.o.y*t));
//    bool dark = ((fx+fy)&1)!=0;  // Light or dark color?
    bool dark = (((int)(ceil(r.o.x*t)+ceil(r.o.y*t)))&1);  // Light or dark color? -> fix for AVR compiler
    if (dark) { color.y = color.z = d; }        // g+b => dark => 'red'
    return 0;
  }

  // No, we hit the scene, read material color from progmem
  const float *mat = materials+(hit*4);
  color.x = pgm_read_float(mat++);
  color.y = pgm_read_float(mat++);
  color.z = pgm_read_float(mat++);

  // Specular light in 't'
  t = d;
  if (t > 0) {
    t = raise(r.d%half,5);
  }

  // Calculate total color using diffuse and specular components
  color *= d*d+ambient;  // Ambient+diffuse
  color += vec3(t,t,t);  // Specular

  // We need to trace a reflection ray...need to modify 'r' for the recursion
  r.d = half;
  return pgm_read_float(mat);    // Reflectivity of this material
}

/*------------------------------------------------------------------------
  Raytrace the entire image
------------------------------------------------------------------------*/
void doRaytrace(int raysPerPixel = 4, int dw = 320, int dh = 240, int q = 1)
{
  // Trace it
  int dw2=dw/2;;
  int dh2=dh/2;
  const float pixel =  fov/float(dh2);    // Size of one pixel on screen

  // Position/target of camera
  const vec3 camera = vec3(cameraX,cameraY,cameraZ);
  const vec3 target = vec3(targetX,targetY,targetZ);

///  unsigned long t = millis();
  unsigned long t = 0;

  for (int y=0; y<dh; y+=q) {
    for (int x=0; x<dw; x+=q) {
      vec3 acc(0,0,0);     // Color accumulator
      for (int p=raysPerPixel; p--;) {
        ray r;  vec3 temp;
        float xpos = float(x-dw2), ypos=float(dh2-y);
        if (raysPerPixel>1) { xpos+=RF; ypos+=RF; }       // Stochastic antialiasing when RPP > 1

        // Calculate a ray through this pixel
        temp = !(target-camera);
        vec3& right = r.o;   right = !(temp^vec3(0,0,1));
        vec3& up = r.d;      up = !(right^temp);
        r.d = !(temp + ((right*xpos)+(up*ypos))*pixel);  // Ray direction
        r.o = camera;                                    // Ray starts at the camera

        // Sample the world, accumulate the color returned
        vec3& color = temp;
        float reflect1 = sample(r,color);
        acc += color;
        // 'sample()' would normally be recursive but there's not enough RAM to do that on a Tiny85...
        if (reflect1 > 0) {
          // ...so we do the 'recursion' manually
          float reflect2 = sample(r,color);
          acc += color*reflect1;
          if (reflect2 > 0) {
            // ...3 levels deep
            sample(r,color);
            acc += color*(reflect1*reflect2);
          }
        }
      }

      // Output the pixel
      acc = acc*(255.0/float(raysPerPixel));
      int r = acc.x;    if (r>255) { r=255; }
      int g = acc.y;    if (g>255) { g=255; }
      int b = acc.z;    if (b>255) { b=255; }
	  draw_pixel(x, y, r, g, b);
///      if(q==1) display.drawPixel(x, y, RGBTO565(r,g,b));
///      else display.fillRect(x, y, q, q, RGBTO565(r,g,b));
    }
// workaround for ESP8266 which reboots after staying too long in the loops (WTF-watchdog?)
#ifdef ESP8266
    delay(1);
#endif
///    char buf[100];
///    snprintf(buf,100,"%3d%% %3ds", (y+q)*100/dh, (millis()-t)/1000);
///    display.setCursor(8,0);
///    display.println(buf);
  }
}
<commit_msg>update: cleanup<commit_after>#pragma once
/*------------------------------------------------------------------------
  This is based on Paul Heckbert's "business card raytracer".
  His site is: http://www.cs.cmu.edu/~ph/

  I modified it a lot adding colors/materials, arbitrary sphere
  positions, etc.

  I also added some comments and made it readable. The original
  code was designed to be small enough to print on the back of
  a business card (hence the name) so it was very hard to read.

  FTB.
------------------------------------------------------------------------*/
#include <cmath>
#include <cstdint>

extern "C" {
	void draw_pixel(int x, int y, int r, int g, int b);
};

/*------------------------------------------------------------------------
  Values you can play with...
------------------------------------------------------------------------*/

// Position of the camera (nb. 'Z' is up/down)
static const float cameraX = 0.0f;
static const float cameraY = 0.0f;
static const float cameraZ = 3.0f;

// What the camera is pointing at
static const float targetX = 1.0f;
static const float targetY = 8.0f;
static const float targetZ = 4.0f;

// We cast this many rays per pixel for stochastic antialiasing and soft-shadows.
//
// Large numbers produce a nicer image but it runs a lot slower
//static const int raysPerPixel = 4;

// The camera's field of view, smaller=>zoom, larger=>wide angle
static const float fov = 0.45f;

// The size of the soft shadow, larger=>wider area
static const float shadowRegion = 0.125f;

/*------------------------------------------------------------------------
  Materials
------------------------------------------------------------------------*/
static const float ambient = 0.05f;
static const float materials[] = {
// R,    G,    B,   REFLECTIVITY
  0.8f, 0.8f, 0.8f,   0.5f,    // Mirror
//  1.0f, 0.0f, 0.0f,   0.3f,    // Red
  0.0f, 1.0f, 0.0f,   0.2f,    // Green
//  0.0f, 0.0f, 0.1f,   0.3f     // Dark blue
  0.0f, 0.8f, 0.8f,   0.3f     // Cyan
};

/*------------------------------------------------------------------------
  The spheres in the world
------------------------------------------------------------------------*/
#define NUM_SPHERES 4
static const float spheres[] = {
// center  radius material
   5,15,8,   5,     0,
  -6,12,4,   3,     0,
   1,10,2,   2,     1,
   0, 9,5,   1,     2
};

/*------------------------------------------------------------------------
  A 3D vector class
------------------------------------------------------------------------*/
struct vec3 {
  float x,y,z;  // Vector has three float attributes.
  vec3(){}
  vec3(float a, float b, float c){x=a;y=b;z=c;}
  vec3 operator+(const vec3& v) const { return vec3(x+v.x,y+v.y,z+v.z);  }    // Vector add
  vec3 operator-(const vec3& v) const { return (*this)+(v*-1);           }    // Vector subtract
  vec3 operator*(float s)       const { return vec3(x*s,y*s,z*s);        }    // Vector scale
  float operator%(const vec3& v)const { return x*v.x+y*v.y+z*v.z;        }    // Scalar product
  vec3 operator^(const vec3& v) const { return vec3(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x);  } // Vector product
  vec3 operator!()              const { return *this*(1.0/sqrt(*this%*this));  }  // Normalized vector
  void operator+=(const vec3& v)      { x+=v.x;  y+=v.y;  z+=v.z;        }
  void operator*=(float s)            { x*=s;    y*=s;    z*=s;          }
};

// A ray...
struct ray {
  // This occupies 24 bytes - you could only fit 20 of these into
  // a Tiny85 even if you could use the entire RAM (which you can't...)
  vec3 o;  // Origin
  vec3 d;  // Direction
};

/*------------------------------------------------------------------------
  Intersect a ray with the world
  Return 'SKY' if no hit was found but ray goes upward
  Return 'FLOOR' if no hit was found but ray goes downward towards the floor
  Return a material index if a hit was found

  Distance to the hit is returned in 'distance'.
  The surface normal at the hit is returned in 'normal'
------------------------------------------------------------------------*/
// Values for 'SKY' and 'FLOOR'
static const uint8_t SKY=255;
static const uint8_t FLOOR=254;

uint8_t trace(const ray& r, float& distance, vec3& normal)
{
  // Assume we didn't hit anything
  uint8_t result = SKY;

  // Does the ray go downwards?
  float d = -r.o.z/r.d.z;
  if (d > 0.01f) {
    // Yes, assume it hits the floor
    result = true;
    distance = d;
    result = FLOOR;
    normal = vec3(0,0,1);
  }

  // Test the objects in the scene to see if there's anything in the way
  for (uint8_t i=0; i<NUM_SPHERES; ++i) {
    vec3 oc = r.o;
    // Read a sphere from progmem, calculate vector 'oc'
    const float* n = spheres+(i*5);
    oc.x -= *n++;
    oc.y -= *n++;
    oc.z -= *n++;
    d = *n++;  // Radius

    // Ray-sphere intersection test
    // Math is here: http://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection
    const float b = r.d%oc;        // I.(o-c)
    const float c = (oc%oc)-(d*d); // (o-c).(o-c) - r^2

    // Does the ray hit the sphere?
    d = (b*b)-c;
    if (d > 0) {
      // Yes, compute the distance to the hit
      d = (-b)-sqrt(d);

      // Is it the closest hit so far?
      if ((d > 0.01) and ((result==SKY) or (d<distance))) {
        // Yes, save results
        distance = d;
        normal = !(oc+r.d*d);
        result = static_cast<uint8_t>(*n);  // The sphere's material
      }
    }
  }
  return result;
}
float raise(float p, uint8_t n)
{
  while (n--) {
    p = p*p;
  }
  return p;
}

/*----------------------------------------------------------
  Small, fast pseudo-random number generator

  I found this in a forum and I'm not sure who originally
  wrote it. It works very well though....

  If you wrote this then get in touch and I'll put
  your name here. :-)                              FTB.
----------------------------------------------------------*/
uint8_t randomByte()
{
  static uint8_t rngA, rngB, rngC, rngX;
  ++rngX;                        // X is incremented every round and is not affected by any other variable
  rngA = (rngA ^ rngC ^ rngX);       // note the mix of addition and XOR
  rngB = (rngB + rngA);            // And the use of very few instructions
  rngC = ((rngC + (rngB >> 1)) ^ rngA);  // the right shift is to ensure that high-order bits from B can affect
  return rngC;
}

// A random float in the range [-0.5 ... 0.5]  (more or less)
float randomFloat()
{
  char r = char(randomByte());
  return float(r)/256.0f;
}
#define RF randomFloat()
#define SH (RF*shadowRegion)

/*------------------------------------------------------------------------
  Sample the world and return the pixel color for a ray
------------------------------------------------------------------------*/
float sample(ray& r, vec3& color)
{
  // See if the ray hits anything in the world
  float t;  vec3& n = color;      // RAM is tight, use 'color' as temp workspace
  const uint8_t hit = trace(r,t,n);

  // Did we hit anything
  if (hit == SKY) {
    // Generate a sky color if the ray goes upwards without hitting anything
    color = vec3(0.1f,0.0f,0.3f) + vec3(.7f,.2f,0.5f)*raise(1.0-r.d.z,2);
    return 0.0f;
  }

  // New ray origin
  r.o += r.d*t;

  // Half vector
  const vec3 half = !(r.d+n*((n%r.d)*-2));

// Vector that points towards the light
  r.d = vec3(9+SH, 6+SH,16); // Where the light is
  r.d = !(r.d-r.o);          // Normalized light vector

  // Lambertian factor
  float d = r.d%n;    // Light vector % surface normal

  // See if we're in shadow
  if ((d<0) or (trace(r,t,n)!=SKY)) {
    d = 0;
  }

  // Did we hit the floor?
  if (hit == FLOOR) {
    // Yes, generate a floor color
    d=(d*0.2f)+0.1f;   t=d*3.0f;  // d=dark, t=light
    color = vec3(t,t,t);       // Assume grey color
    t = 1.0f/5.0f;     // Floor tiles are 5m across
//    int fx = int(ceil(r.o.x*t));
//    int fy = int(ceil(r.o.y*t));
//    bool dark = ((fx+fy)&1)!=0;  // Light or dark color?
    bool dark = (((int)(ceil(r.o.x*t)+ceil(r.o.y*t)))&1);  // Light or dark color? -> fix for AVR compiler
    if (dark) { color.y = color.z = d; }        // g+b => dark => 'red'
    return 0;
  }

  // No, we hit the scene, read material color from progmem
  const float* mat = materials+(hit*4);
  color.x = *mat++;
  color.y = *mat++;
  color.z = *mat++;

  // Specular light in 't'
  t = d;
  if (t > 0) {
    t = raise(r.d%half,5);
  }

  // Calculate total color using diffuse and specular components
  color *= d*d+ambient;  // Ambient+diffuse
  color += vec3(t,t,t);  // Specular

  // We need to trace a reflection ray...need to modify 'r' for the recursion
  r.d = half;
  return *mat;    // Reflectivity of this material
}

/*------------------------------------------------------------------------
  Raytrace the entire image
------------------------------------------------------------------------*/
void doRaytrace(int raysPerPixel = 4, int dw = 320, int dh = 240, int q = 1)
{
  // Trace it
  int dw2=dw/2;;
  int dh2=dh/2;
  const float pixel =  fov/float(dh2);    // Size of one pixel on screen

  // Position/target of camera
  const vec3 camera = vec3(cameraX,cameraY,cameraZ);
  const vec3 target = vec3(targetX,targetY,targetZ);

///  unsigned long t = millis();
  unsigned long t = 0;

  for (int y=0; y<dh; y+=q) {
    for (int x=0; x<dw; x+=q) {
      vec3 acc(0,0,0);     // Color accumulator
      for (int p=raysPerPixel; p--;) {
        ray r;  vec3 temp;
        float xpos = float(x-dw2), ypos=float(dh2-y);
        if (raysPerPixel>1) { xpos+=RF; ypos+=RF; }       // Stochastic antialiasing when RPP > 1

        // Calculate a ray through this pixel
        temp = !(target-camera);
        vec3& right = r.o;   right = !(temp^vec3(0,0,1));
        vec3& up = r.d;      up = !(right^temp);
        r.d = !(temp + ((right*xpos)+(up*ypos))*pixel);  // Ray direction
        r.o = camera;                                    // Ray starts at the camera

        // Sample the world, accumulate the color returned
        vec3& color = temp;
        float reflect1 = sample(r,color);
        acc += color;
        // 'sample()' would normally be recursive but there's not enough RAM to do that on a Tiny85...
        if (reflect1 > 0) {
          // ...so we do the 'recursion' manually
          float reflect2 = sample(r,color);
          acc += color*reflect1;
          if (reflect2 > 0) {
            // ...3 levels deep
            sample(r,color);
            acc += color*(reflect1*reflect2);
          }
        }
      }

      // Output the pixel
      acc = acc*(255.0f/float(raysPerPixel));
      int r = acc.x;    if (r>255) { r=255; }
      int g = acc.y;    if (g>255) { g=255; }
      int b = acc.z;    if (b>255) { b=255; }
	  draw_pixel(x, y, r, g, b);
///      if(q==1) display.drawPixel(x, y, RGBTO565(r,g,b));
///      else display.fillRect(x, y, q, q, RGBTO565(r,g,b));
    }
// workaround for ESP8266 which reboots after staying too long in the loops (WTF-watchdog?)
#ifdef ESP8266
    delay(1);
#endif
///    char buf[100];
///    snprintf(buf,100,"%3d%% %3ds", (y+q)*100/dh, (millis()-t)/1000);
///    display.setCursor(8,0);
///    display.println(buf);
  }
}
<|endoftext|>


<commit_before>//===-- X86FixupLEAs.cpp - use or replace LEA instructions -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the pass which will find  instructions  which
// can be re-written as LEA instructions in order to reduce pipeline
// delays for some models of the Intel Atom family.
//
//===----------------------------------------------------------------------===//

#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;

#define DEBUG_TYPE "x86-fixup-LEAs"

STATISTIC(NumLEAs, "Number of LEA instructions created");

namespace {
class FixupLEAPass : public MachineFunctionPass {
  enum RegUsageState { RU_NotUsed, RU_Write, RU_Read };
  static char ID;
  /// \brief Loop over all of the instructions in the basic block
  /// replacing applicable instructions with LEA instructions,
  /// where appropriate.
  bool processBasicBlock(MachineFunction &MF, MachineFunction::iterator MFI);

  const char *getPassName() const override { return "X86 Atom LEA Fixup"; }

  /// \brief Given a machine register, look for the instruction
  /// which writes it in the current basic block. If found,
  /// try to replace it with an equivalent LEA instruction.
  /// If replacement succeeds, then also process the the newly created
  /// instruction.
  void seekLEAFixup(MachineOperand &p, MachineBasicBlock::iterator &I,
                    MachineFunction::iterator MFI);

  /// \brief Given a memory access or LEA instruction
  /// whose address mode uses a base and/or index register, look for
  /// an opportunity to replace the instruction which sets the base or index
  /// register with an equivalent LEA instruction.
  void processInstruction(MachineBasicBlock::iterator &I,
                          MachineFunction::iterator MFI);

  /// \brief Given a LEA instruction which is unprofitable
  /// on Silvermont try to replace it with an equivalent ADD instruction
  void processInstructionForSLM(MachineBasicBlock::iterator &I,
                                MachineFunction::iterator MFI);

  /// \brief Determine if an instruction references a machine register
  /// and, if so, whether it reads or writes the register.
  RegUsageState usesRegister(MachineOperand &p, MachineBasicBlock::iterator I);

  /// \brief Step backwards through a basic block, looking
  /// for an instruction which writes a register within
  /// a maximum of INSTR_DISTANCE_THRESHOLD instruction latency cycles.
  MachineBasicBlock::iterator searchBackwards(MachineOperand &p,
                                              MachineBasicBlock::iterator &I,
                                              MachineFunction::iterator MFI);

  /// \brief if an instruction can be converted to an
  /// equivalent LEA, insert the new instruction into the basic block
  /// and return a pointer to it. Otherwise, return zero.
  MachineInstr *postRAConvertToLEA(MachineFunction::iterator &MFI,
                                   MachineBasicBlock::iterator &MBBI) const;

public:
  FixupLEAPass() : MachineFunctionPass(ID) {}

  /// \brief Loop over all of the basic blocks,
  /// replacing instructions by equivalent LEA instructions
  /// if needed and when possible.
  bool runOnMachineFunction(MachineFunction &MF) override;

private:
  MachineFunction *MF;
  const TargetMachine *TM;
  const X86InstrInfo *TII; // Machine instruction info.
};
char FixupLEAPass::ID = 0;
}

MachineInstr *
FixupLEAPass::postRAConvertToLEA(MachineFunction::iterator &MFI,
                                 MachineBasicBlock::iterator &MBBI) const {
  MachineInstr *MI = MBBI;
  MachineInstr *NewMI;
  switch (MI->getOpcode()) {
  case X86::MOV32rr:
  case X86::MOV64rr: {
    const MachineOperand &Src = MI->getOperand(1);
    const MachineOperand &Dest = MI->getOperand(0);
    NewMI = BuildMI(*MF, MI->getDebugLoc(),
                    TII->get(MI->getOpcode() == X86::MOV32rr ? X86::LEA32r
                                                             : X86::LEA64r))
                .addOperand(Dest)
                .addOperand(Src)
                .addImm(1)
                .addReg(0)
                .addImm(0)
                .addReg(0);
    MFI->insert(MBBI, NewMI); // Insert the new inst
    return NewMI;
  }
  case X86::ADD64ri32:
  case X86::ADD64ri8:
  case X86::ADD64ri32_DB:
  case X86::ADD64ri8_DB:
  case X86::ADD32ri:
  case X86::ADD32ri8:
  case X86::ADD32ri_DB:
  case X86::ADD32ri8_DB:
  case X86::ADD16ri:
  case X86::ADD16ri8:
  case X86::ADD16ri_DB:
  case X86::ADD16ri8_DB:
    if (!MI->getOperand(2).isImm()) {
      // convertToThreeAddress will call getImm()
      // which requires isImm() to be true
      return nullptr;
    }
    break;
  case X86::ADD16rr:
  case X86::ADD16rr_DB:
    if (MI->getOperand(1).getReg() != MI->getOperand(2).getReg()) {
      // if src1 != src2, then convertToThreeAddress will
      // need to create a Virtual register, which we cannot do
      // after register allocation.
      return nullptr;
    }
  }
  return TII->convertToThreeAddress(MFI, MBBI, nullptr);
}

FunctionPass *llvm::createX86FixupLEAs() { return new FixupLEAPass(); }

bool FixupLEAPass::runOnMachineFunction(MachineFunction &Func) {
  MF = &Func;
  TM = &Func.getTarget();
  const X86Subtarget &ST = TM->getSubtarget<X86Subtarget>();
  if (!ST.LEAusesAG() && !ST.slowLEA())
    return false;

  TII = static_cast<const X86InstrInfo *>(TM->getInstrInfo());

  DEBUG(dbgs() << "Start X86FixupLEAs\n";);
  // Process all basic blocks.
  for (MachineFunction::iterator I = Func.begin(), E = Func.end(); I != E; ++I)
    processBasicBlock(Func, I);
  DEBUG(dbgs() << "End X86FixupLEAs\n";);

  return true;
}

FixupLEAPass::RegUsageState
FixupLEAPass::usesRegister(MachineOperand &p, MachineBasicBlock::iterator I) {
  RegUsageState RegUsage = RU_NotUsed;
  MachineInstr *MI = I;

  for (unsigned int i = 0; i < MI->getNumOperands(); ++i) {
    MachineOperand &opnd = MI->getOperand(i);
    if (opnd.isReg() && opnd.getReg() == p.getReg()) {
      if (opnd.isDef())
        return RU_Write;
      RegUsage = RU_Read;
    }
  }
  return RegUsage;
}

/// getPreviousInstr - Given a reference to an instruction in a basic
/// block, return a reference to the previous instruction in the block,
/// wrapping around to the last instruction of the block if the block
/// branches to itself.
static inline bool getPreviousInstr(MachineBasicBlock::iterator &I,
                                    MachineFunction::iterator MFI) {
  if (I == MFI->begin()) {
    if (MFI->isPredecessor(MFI)) {
      I = --MFI->end();
      return true;
    } else
      return false;
  }
  --I;
  return true;
}

MachineBasicBlock::iterator
FixupLEAPass::searchBackwards(MachineOperand &p, MachineBasicBlock::iterator &I,
                              MachineFunction::iterator MFI) {
  int InstrDistance = 1;
  MachineBasicBlock::iterator CurInst;
  static const int INSTR_DISTANCE_THRESHOLD = 5;

  CurInst = I;
  bool Found;
  Found = getPreviousInstr(CurInst, MFI);
  while (Found && I != CurInst) {
    if (CurInst->isCall() || CurInst->isInlineAsm())
      break;
    if (InstrDistance > INSTR_DISTANCE_THRESHOLD)
      break; // too far back to make a difference
    if (usesRegister(p, CurInst) == RU_Write) {
      return CurInst;
    }
    InstrDistance += TII->getInstrLatency(TM->getInstrItineraryData(), CurInst);
    Found = getPreviousInstr(CurInst, MFI);
  }
  return nullptr;
}

void FixupLEAPass::processInstruction(MachineBasicBlock::iterator &I,
                                      MachineFunction::iterator MFI) {
  // Process a load, store, or LEA instruction.
  MachineInstr *MI = I;
  int opcode = MI->getOpcode();
  const MCInstrDesc &Desc = MI->getDesc();
  int AddrOffset = X86II::getMemoryOperandNo(Desc.TSFlags, opcode);
  if (AddrOffset >= 0) {
    AddrOffset += X86II::getOperandBias(Desc);
    MachineOperand &p = MI->getOperand(AddrOffset + X86::AddrBaseReg);
    if (p.isReg() && p.getReg() != X86::ESP) {
      seekLEAFixup(p, I, MFI);
    }
    MachineOperand &q = MI->getOperand(AddrOffset + X86::AddrIndexReg);
    if (q.isReg() && q.getReg() != X86::ESP) {
      seekLEAFixup(q, I, MFI);
    }
  }
}

void FixupLEAPass::seekLEAFixup(MachineOperand &p,
                                MachineBasicBlock::iterator &I,
                                MachineFunction::iterator MFI) {
  MachineBasicBlock::iterator MBI = searchBackwards(p, I, MFI);
  if (MBI) {
    MachineInstr *NewMI = postRAConvertToLEA(MFI, MBI);
    if (NewMI) {
      ++NumLEAs;
      DEBUG(dbgs() << "FixLEA: Candidate to replace:"; MBI->dump(););
      // now to replace with an equivalent LEA...
      DEBUG(dbgs() << "FixLEA: Replaced by: "; NewMI->dump(););
      MFI->erase(MBI);
      MachineBasicBlock::iterator J =
          static_cast<MachineBasicBlock::iterator>(NewMI);
      processInstruction(J, MFI);
    }
  }
}

void FixupLEAPass::processInstructionForSLM(MachineBasicBlock::iterator &I,
                                            MachineFunction::iterator MFI) {
  MachineInstr *MI = I;
  const int opcode = MI->getOpcode();
  if (opcode != X86::LEA16r && opcode != X86::LEA32r && opcode != X86::LEA64r &&
      opcode != X86::LEA64_32r)
    return;
  if (MI->getOperand(5).getReg() != 0 || !MI->getOperand(4).isImm() ||
      !TII->isSafeToClobberEFLAGS(*MFI, I))
    return;
  const unsigned DstR = MI->getOperand(0).getReg();
  const unsigned SrcR1 = MI->getOperand(1).getReg();
  const unsigned SrcR2 = MI->getOperand(3).getReg();
  if ((SrcR1 == 0 || SrcR1 != DstR) && (SrcR2 == 0 || SrcR2 != DstR))
    return;
  if (MI->getOperand(2).getImm() > 1)
    return;
  int addrr_opcode, addri_opcode;
  switch (opcode) {
  case X86::LEA16r:
    addrr_opcode = X86::ADD16rr;
    addri_opcode = X86::ADD16ri;
    break;
  case X86::LEA32r:
    addrr_opcode = X86::ADD32rr;
    addri_opcode = X86::ADD32ri;
    break;
  case X86::LEA64_32r:
  case X86::LEA64r:
    addrr_opcode = X86::ADD64rr;
    addri_opcode = X86::ADD64ri32;
    break;
  default:
    assert(false && "Unexpected LEA instruction");
  }
  DEBUG(dbgs() << "FixLEA: Candidate to replace:"; I->dump(););
  DEBUG(dbgs() << "FixLEA: Replaced by: ";);
  MachineInstr *NewMI = nullptr;
  const MachineOperand &Dst = MI->getOperand(0);
  // Make ADD instruction for two registers writing to LEA's destination
  if (SrcR1 != 0 && SrcR2 != 0) {
    const MachineOperand &Src1 = MI->getOperand(SrcR1 == DstR ? 1 : 3);
    const MachineOperand &Src2 = MI->getOperand(SrcR1 == DstR ? 3 : 1);
    NewMI = BuildMI(*MF, MI->getDebugLoc(), TII->get(addrr_opcode))
                .addOperand(Dst)
                .addOperand(Src1)
                .addOperand(Src2);
    MFI->insert(I, NewMI);
    DEBUG(NewMI->dump(););
  }
  // Make ADD instruction for immediate
  if (MI->getOperand(4).getImm() != 0) {
    const MachineOperand &SrcR = MI->getOperand(SrcR1 == DstR ? 1 : 3);
    NewMI = BuildMI(*MF, MI->getDebugLoc(), TII->get(addri_opcode))
                .addOperand(Dst)
                .addOperand(SrcR)
                .addImm(MI->getOperand(4).getImm());
    MFI->insert(I, NewMI);
    DEBUG(NewMI->dump(););
  }
  if (NewMI) {
    MFI->erase(I);
    I = static_cast<MachineBasicBlock::iterator>(NewMI);
  }
}

bool FixupLEAPass::processBasicBlock(MachineFunction &MF,
                                     MachineFunction::iterator MFI) {

  for (MachineBasicBlock::iterator I = MFI->begin(); I != MFI->end(); ++I) {
    if (TM->getSubtarget<X86Subtarget>().isSLM())
      processInstructionForSLM(I, MFI);
    else
      processInstruction(I, MFI);
  }
  return false;
}
<commit_msg>Remove Atom references in description.<commit_after>//===-- X86FixupLEAs.cpp - use or replace LEA instructions -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the pass that finds instructions that can be
// re-written as LEA instructions in order to reduce pipeline delays.
//
//===----------------------------------------------------------------------===//

#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;

#define DEBUG_TYPE "x86-fixup-LEAs"

STATISTIC(NumLEAs, "Number of LEA instructions created");

namespace {
class FixupLEAPass : public MachineFunctionPass {
  enum RegUsageState { RU_NotUsed, RU_Write, RU_Read };
  static char ID;
  /// \brief Loop over all of the instructions in the basic block
  /// replacing applicable instructions with LEA instructions,
  /// where appropriate.
  bool processBasicBlock(MachineFunction &MF, MachineFunction::iterator MFI);

  const char *getPassName() const override { return "X86 LEA Fixup"; }

  /// \brief Given a machine register, look for the instruction
  /// which writes it in the current basic block. If found,
  /// try to replace it with an equivalent LEA instruction.
  /// If replacement succeeds, then also process the the newly created
  /// instruction.
  void seekLEAFixup(MachineOperand &p, MachineBasicBlock::iterator &I,
                    MachineFunction::iterator MFI);

  /// \brief Given a memory access or LEA instruction
  /// whose address mode uses a base and/or index register, look for
  /// an opportunity to replace the instruction which sets the base or index
  /// register with an equivalent LEA instruction.
  void processInstruction(MachineBasicBlock::iterator &I,
                          MachineFunction::iterator MFI);

  /// \brief Given a LEA instruction which is unprofitable
  /// on Silvermont try to replace it with an equivalent ADD instruction
  void processInstructionForSLM(MachineBasicBlock::iterator &I,
                                MachineFunction::iterator MFI);

  /// \brief Determine if an instruction references a machine register
  /// and, if so, whether it reads or writes the register.
  RegUsageState usesRegister(MachineOperand &p, MachineBasicBlock::iterator I);

  /// \brief Step backwards through a basic block, looking
  /// for an instruction which writes a register within
  /// a maximum of INSTR_DISTANCE_THRESHOLD instruction latency cycles.
  MachineBasicBlock::iterator searchBackwards(MachineOperand &p,
                                              MachineBasicBlock::iterator &I,
                                              MachineFunction::iterator MFI);

  /// \brief if an instruction can be converted to an
  /// equivalent LEA, insert the new instruction into the basic block
  /// and return a pointer to it. Otherwise, return zero.
  MachineInstr *postRAConvertToLEA(MachineFunction::iterator &MFI,
                                   MachineBasicBlock::iterator &MBBI) const;

public:
  FixupLEAPass() : MachineFunctionPass(ID) {}

  /// \brief Loop over all of the basic blocks,
  /// replacing instructions by equivalent LEA instructions
  /// if needed and when possible.
  bool runOnMachineFunction(MachineFunction &MF) override;

private:
  MachineFunction *MF;
  const TargetMachine *TM;
  const X86InstrInfo *TII; // Machine instruction info.
};
char FixupLEAPass::ID = 0;
}

MachineInstr *
FixupLEAPass::postRAConvertToLEA(MachineFunction::iterator &MFI,
                                 MachineBasicBlock::iterator &MBBI) const {
  MachineInstr *MI = MBBI;
  MachineInstr *NewMI;
  switch (MI->getOpcode()) {
  case X86::MOV32rr:
  case X86::MOV64rr: {
    const MachineOperand &Src = MI->getOperand(1);
    const MachineOperand &Dest = MI->getOperand(0);
    NewMI = BuildMI(*MF, MI->getDebugLoc(),
                    TII->get(MI->getOpcode() == X86::MOV32rr ? X86::LEA32r
                                                             : X86::LEA64r))
                .addOperand(Dest)
                .addOperand(Src)
                .addImm(1)
                .addReg(0)
                .addImm(0)
                .addReg(0);
    MFI->insert(MBBI, NewMI); // Insert the new inst
    return NewMI;
  }
  case X86::ADD64ri32:
  case X86::ADD64ri8:
  case X86::ADD64ri32_DB:
  case X86::ADD64ri8_DB:
  case X86::ADD32ri:
  case X86::ADD32ri8:
  case X86::ADD32ri_DB:
  case X86::ADD32ri8_DB:
  case X86::ADD16ri:
  case X86::ADD16ri8:
  case X86::ADD16ri_DB:
  case X86::ADD16ri8_DB:
    if (!MI->getOperand(2).isImm()) {
      // convertToThreeAddress will call getImm()
      // which requires isImm() to be true
      return nullptr;
    }
    break;
  case X86::ADD16rr:
  case X86::ADD16rr_DB:
    if (MI->getOperand(1).getReg() != MI->getOperand(2).getReg()) {
      // if src1 != src2, then convertToThreeAddress will
      // need to create a Virtual register, which we cannot do
      // after register allocation.
      return nullptr;
    }
  }
  return TII->convertToThreeAddress(MFI, MBBI, nullptr);
}

FunctionPass *llvm::createX86FixupLEAs() { return new FixupLEAPass(); }

bool FixupLEAPass::runOnMachineFunction(MachineFunction &Func) {
  MF = &Func;
  TM = &Func.getTarget();
  const X86Subtarget &ST = TM->getSubtarget<X86Subtarget>();
  if (!ST.LEAusesAG() && !ST.slowLEA())
    return false;

  TII = static_cast<const X86InstrInfo *>(TM->getInstrInfo());

  DEBUG(dbgs() << "Start X86FixupLEAs\n";);
  // Process all basic blocks.
  for (MachineFunction::iterator I = Func.begin(), E = Func.end(); I != E; ++I)
    processBasicBlock(Func, I);
  DEBUG(dbgs() << "End X86FixupLEAs\n";);

  return true;
}

FixupLEAPass::RegUsageState
FixupLEAPass::usesRegister(MachineOperand &p, MachineBasicBlock::iterator I) {
  RegUsageState RegUsage = RU_NotUsed;
  MachineInstr *MI = I;

  for (unsigned int i = 0; i < MI->getNumOperands(); ++i) {
    MachineOperand &opnd = MI->getOperand(i);
    if (opnd.isReg() && opnd.getReg() == p.getReg()) {
      if (opnd.isDef())
        return RU_Write;
      RegUsage = RU_Read;
    }
  }
  return RegUsage;
}

/// getPreviousInstr - Given a reference to an instruction in a basic
/// block, return a reference to the previous instruction in the block,
/// wrapping around to the last instruction of the block if the block
/// branches to itself.
static inline bool getPreviousInstr(MachineBasicBlock::iterator &I,
                                    MachineFunction::iterator MFI) {
  if (I == MFI->begin()) {
    if (MFI->isPredecessor(MFI)) {
      I = --MFI->end();
      return true;
    } else
      return false;
  }
  --I;
  return true;
}

MachineBasicBlock::iterator
FixupLEAPass::searchBackwards(MachineOperand &p, MachineBasicBlock::iterator &I,
                              MachineFunction::iterator MFI) {
  int InstrDistance = 1;
  MachineBasicBlock::iterator CurInst;
  static const int INSTR_DISTANCE_THRESHOLD = 5;

  CurInst = I;
  bool Found;
  Found = getPreviousInstr(CurInst, MFI);
  while (Found && I != CurInst) {
    if (CurInst->isCall() || CurInst->isInlineAsm())
      break;
    if (InstrDistance > INSTR_DISTANCE_THRESHOLD)
      break; // too far back to make a difference
    if (usesRegister(p, CurInst) == RU_Write) {
      return CurInst;
    }
    InstrDistance += TII->getInstrLatency(TM->getInstrItineraryData(), CurInst);
    Found = getPreviousInstr(CurInst, MFI);
  }
  return nullptr;
}

void FixupLEAPass::processInstruction(MachineBasicBlock::iterator &I,
                                      MachineFunction::iterator MFI) {
  // Process a load, store, or LEA instruction.
  MachineInstr *MI = I;
  int opcode = MI->getOpcode();
  const MCInstrDesc &Desc = MI->getDesc();
  int AddrOffset = X86II::getMemoryOperandNo(Desc.TSFlags, opcode);
  if (AddrOffset >= 0) {
    AddrOffset += X86II::getOperandBias(Desc);
    MachineOperand &p = MI->getOperand(AddrOffset + X86::AddrBaseReg);
    if (p.isReg() && p.getReg() != X86::ESP) {
      seekLEAFixup(p, I, MFI);
    }
    MachineOperand &q = MI->getOperand(AddrOffset + X86::AddrIndexReg);
    if (q.isReg() && q.getReg() != X86::ESP) {
      seekLEAFixup(q, I, MFI);
    }
  }
}

void FixupLEAPass::seekLEAFixup(MachineOperand &p,
                                MachineBasicBlock::iterator &I,
                                MachineFunction::iterator MFI) {
  MachineBasicBlock::iterator MBI = searchBackwards(p, I, MFI);
  if (MBI) {
    MachineInstr *NewMI = postRAConvertToLEA(MFI, MBI);
    if (NewMI) {
      ++NumLEAs;
      DEBUG(dbgs() << "FixLEA: Candidate to replace:"; MBI->dump(););
      // now to replace with an equivalent LEA...
      DEBUG(dbgs() << "FixLEA: Replaced by: "; NewMI->dump(););
      MFI->erase(MBI);
      MachineBasicBlock::iterator J =
          static_cast<MachineBasicBlock::iterator>(NewMI);
      processInstruction(J, MFI);
    }
  }
}

void FixupLEAPass::processInstructionForSLM(MachineBasicBlock::iterator &I,
                                            MachineFunction::iterator MFI) {
  MachineInstr *MI = I;
  const int opcode = MI->getOpcode();
  if (opcode != X86::LEA16r && opcode != X86::LEA32r && opcode != X86::LEA64r &&
      opcode != X86::LEA64_32r)
    return;
  if (MI->getOperand(5).getReg() != 0 || !MI->getOperand(4).isImm() ||
      !TII->isSafeToClobberEFLAGS(*MFI, I))
    return;
  const unsigned DstR = MI->getOperand(0).getReg();
  const unsigned SrcR1 = MI->getOperand(1).getReg();
  const unsigned SrcR2 = MI->getOperand(3).getReg();
  if ((SrcR1 == 0 || SrcR1 != DstR) && (SrcR2 == 0 || SrcR2 != DstR))
    return;
  if (MI->getOperand(2).getImm() > 1)
    return;
  int addrr_opcode, addri_opcode;
  switch (opcode) {
  case X86::LEA16r:
    addrr_opcode = X86::ADD16rr;
    addri_opcode = X86::ADD16ri;
    break;
  case X86::LEA32r:
    addrr_opcode = X86::ADD32rr;
    addri_opcode = X86::ADD32ri;
    break;
  case X86::LEA64_32r:
  case X86::LEA64r:
    addrr_opcode = X86::ADD64rr;
    addri_opcode = X86::ADD64ri32;
    break;
  default:
    assert(false && "Unexpected LEA instruction");
  }
  DEBUG(dbgs() << "FixLEA: Candidate to replace:"; I->dump(););
  DEBUG(dbgs() << "FixLEA: Replaced by: ";);
  MachineInstr *NewMI = nullptr;
  const MachineOperand &Dst = MI->getOperand(0);
  // Make ADD instruction for two registers writing to LEA's destination
  if (SrcR1 != 0 && SrcR2 != 0) {
    const MachineOperand &Src1 = MI->getOperand(SrcR1 == DstR ? 1 : 3);
    const MachineOperand &Src2 = MI->getOperand(SrcR1 == DstR ? 3 : 1);
    NewMI = BuildMI(*MF, MI->getDebugLoc(), TII->get(addrr_opcode))
                .addOperand(Dst)
                .addOperand(Src1)
                .addOperand(Src2);
    MFI->insert(I, NewMI);
    DEBUG(NewMI->dump(););
  }
  // Make ADD instruction for immediate
  if (MI->getOperand(4).getImm() != 0) {
    const MachineOperand &SrcR = MI->getOperand(SrcR1 == DstR ? 1 : 3);
    NewMI = BuildMI(*MF, MI->getDebugLoc(), TII->get(addri_opcode))
                .addOperand(Dst)
                .addOperand(SrcR)
                .addImm(MI->getOperand(4).getImm());
    MFI->insert(I, NewMI);
    DEBUG(NewMI->dump(););
  }
  if (NewMI) {
    MFI->erase(I);
    I = static_cast<MachineBasicBlock::iterator>(NewMI);
  }
}

bool FixupLEAPass::processBasicBlock(MachineFunction &MF,
                                     MachineFunction::iterator MFI) {

  for (MachineBasicBlock::iterator I = MFI->begin(); I != MFI->end(); ++I) {
    if (TM->getSubtarget<X86Subtarget>().isSLM())
      processInstructionForSLM(I, MFI);
    else
      processInstruction(I, MFI);
  }
  return false;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2011-2019 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin.
 *
 * This program 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.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "executor.hpp"

#include <csignal>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <mutex>
#include <boost/core/null_deleter.hpp>
#include <boost/filesystem.hpp>
#include <bitcoin/server.hpp>

namespace libbitcoin {
namespace server {

using boost::format;
using namespace boost;
using namespace boost::filesystem;
using namespace boost::system;
using namespace bc::database;
using namespace bc::network;
using namespace bc::system;
using namespace bc::system::chain;
using namespace bc::system::config;
using namespace std::placeholders;

namespace keywords = boost::log::keywords;

static const auto application_name = "bs";
static constexpr int initialize_stop = 0;
static constexpr int directory_exists = 0;
static constexpr int directory_not_found = 2;
static const auto mode = std::ofstream::out | std::ofstream::app;

std::promise<code> executor::stopping_;

executor::executor(parser& metadata, std::istream& ,
    std::ostream& output, std::ostream& error)
  : metadata_(metadata), output_(output), error_(error)
{
    const auto& network = metadata_.configured.network;
    const auto verbose = network.verbose;

    const log::rotable_file debug_file
    {
        network.debug_file,
        network.archive_directory,
        network.rotation_size,
        network.maximum_archive_size,
        network.minimum_free_space,
        network.maximum_archive_files
    };

    const log::rotable_file error_file
    {
        network.error_file,
        network.archive_directory,
        network.rotation_size,
        network.maximum_archive_size,
        network.minimum_free_space,
        network.maximum_archive_files
    };

    log::stream console_out(&output_, null_deleter());
    log::stream console_err(&error_, null_deleter());

    log::initialize(debug_file, error_file, console_out, console_err, verbose);
    handle_stop(initialize_stop);
}

// Command line options.
// ----------------------------------------------------------------------------
// Emit directly to standard output (not the log).

void executor::do_help()
{
    const auto options = metadata_.load_options();
    printer help(options, application_name, BS_INFORMATION_MESSAGE);
    help.initialize();
    help.commandline(output_);
}

void executor::do_settings()
{
    const auto settings = metadata_.load_settings();
    printer print(settings, application_name, BS_SETTINGS_MESSAGE);
    print.initialize();
    print.settings(output_);
}

void executor::do_version()
{
    output_ << format(BS_VERSION_MESSAGE) %
        LIBBITCOIN_SERVER_VERSION %
        LIBBITCOIN_PROTOCOL_VERSION %
        LIBBITCOIN_NODE_VERSION %
        LIBBITCOIN_BLOCKCHAIN_VERSION %
        LIBBITCOIN_SYSTEM_VERSION << std::endl;
}

// Emit to the log.
bool executor::do_initchain()
{
    initialize_output();

    error_code ec;
    const auto& directory = metadata_.configured.database.directory;

    if (create_directories(directory, ec))
    {
        LOG_INFO(LOG_SERVER) << format(BS_INITIALIZING_CHAIN) % directory;

        const auto& bitcoin_settings = metadata_.configured.bitcoin;
        const auto result = data_base(metadata_.configured.database,
            metadata_.configured.chain.index_payments).create(
                bitcoin_settings.genesis_block);

        LOG_INFO(LOG_SERVER) << BS_INITCHAIN_COMPLETE;
        return result;
    }

    if (ec.value() == directory_exists)
    {
        LOG_ERROR(LOG_SERVER) << format(BS_INITCHAIN_EXISTS) % directory;
        return false;
    }

    LOG_ERROR(LOG_SERVER) << format(BS_INITCHAIN_NEW) % directory % ec.message();
    return false;
}

// Menu selection.
// ----------------------------------------------------------------------------

bool executor::menu()
{
    const auto& config = metadata_.configured;

    if (config.help)
    {
        do_help();
        return true;
    }

    if (config.settings)
    {
        do_settings();
        return true;
    }

    if (config.version)
    {
        do_version();
        return true;
    }

    if (config.initchain)
    {
        return do_initchain();
    }

    // There are no command line arguments, just run the server.
    return run();
}

// Run.
// ----------------------------------------------------------------------------

bool executor::run()
{
    initialize_output();

    LOG_INFO(LOG_SERVER) << BS_NODE_STARTING;

    if (!verify_directory())
        return false;

    // Now that the directory is verified we can create the node for it.
    node_ = std::make_shared<server_node>(metadata_.configured);

    // Initialize broadcast to statistics server if configured.
    log::initialize_statsd(node_->thread_pool(),
        metadata_.configured.network.statistics_server);

    // The callback may be returned on the same thread.
    node_->start(
        std::bind(&executor::handle_started,
            this, _1));

    // Wait for stop.
    stopping_.get_future().wait();

    LOG_INFO(LOG_SERVER) << BS_NODE_STOPPING;

    // Close must be called from main thread.
    if (node_->close())
        LOG_INFO(LOG_NODE) << BS_NODE_STOPPED;
    else
        LOG_INFO(LOG_NODE) << BS_NODE_STOP_FAIL;

    return true;
}

// Handle the completion of the start sequence and begin the run sequence.
void executor::handle_started(const code& ec)
{
    // TEMP: use to repro start/stop deadlock race.
    ////auto thread = std::thread([this]() { stop(error::service_stopped); });

    if (ec)
    {
        LOG_ERROR(LOG_SERVER) << format(BS_NODE_START_FAIL) % ec.message();
        stop(ec);
        return;
    }

    LOG_INFO(LOG_SERVER) << BS_NODE_SEEDED;

    // This is the beginning of the stop sequence.
    node_->subscribe_stop(
        std::bind(&executor::handle_stopped,
            this, _1));

    // This is the beginning of the run sequence.
    node_->run(
        std::bind(&executor::handle_running,
            this, _1));

    // TEMP: see above.
    ////thread.join();
}

// This is the end of the run sequence.
void executor::handle_running(const code& ec)
{
    if (ec)
    {
        LOG_INFO(LOG_SERVER) << format(BS_NODE_START_FAIL) % ec.message();
        stop(ec);
        return;
    }

    LOG_INFO(LOG_SERVER) << BS_NODE_STARTED;
}

// This is the end of the stop sequence.
void executor::handle_stopped(const code& ec)
{
    stop(ec);
}

// Stop signal.
// ----------------------------------------------------------------------------

void executor::handle_stop(int code)
{
    // Reinitialize after each capture to prevent hard shutdown.
    // Do not capture failure signals as calling stop can cause flush lock file
    // to clear due to the aborted thread dropping the flush lock mutex.
    std::signal(SIGINT, handle_stop);
    std::signal(SIGTERM, handle_stop);

    if (code == initialize_stop)
        return;

    LOG_INFO(LOG_SERVER) << format(BS_NODE_SIGNALED) % code;
    stop(error::success);
}

void executor::stop(const code& ec)
{
    static std::once_flag stop_mutex;
    std::call_once(stop_mutex, [&](){ stopping_.set_value(ec); });
}

// Utilities.
// ----------------------------------------------------------------------------

// Set up logging.
void executor::initialize_output()
{
    const auto header = format(BS_LOG_HEADER) % local_time();
    LOG_DEBUG(LOG_SERVER) << header;
    LOG_INFO(LOG_SERVER) << header;
    LOG_WARNING(LOG_SERVER) << header;
    LOG_ERROR(LOG_SERVER) << header;
    LOG_FATAL(LOG_SERVER) << header;

    const auto& file = metadata_.configured.file;

    if (file.empty())
        LOG_INFO(LOG_SERVER) << BS_USING_DEFAULT_CONFIG;
    else
        LOG_INFO(LOG_SERVER) << format(BS_USING_CONFIG_FILE) % file;
}

// Use missing directory as a sentinel indicating lack of initialization.
bool executor::verify_directory()
{
    error_code ec;
    const auto& directory = metadata_.configured.database.directory;

    if (exists(directory, ec))
        return true;

    if (ec.value() == directory_not_found)
    {
        LOG_ERROR(LOG_SERVER) << format(BS_UNINITIALIZED_CHAIN) % directory;
        return false;
    }

    const auto message = ec.message();
    LOG_ERROR(LOG_SERVER) << format(BS_INITCHAIN_TRY) % directory % message;
    return false;
}

} // namespace server
} // namespace libbitcoin
<commit_msg>Fix break introduced by signature change in libbitcoin-database.<commit_after>/**
 * Copyright (c) 2011-2019 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin.
 *
 * This program 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.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "executor.hpp"

#include <csignal>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <mutex>
#include <boost/core/null_deleter.hpp>
#include <boost/filesystem.hpp>
#include <bitcoin/server.hpp>

namespace libbitcoin {
namespace server {

using boost::format;
using namespace boost;
using namespace boost::filesystem;
using namespace boost::system;
using namespace bc::database;
using namespace bc::network;
using namespace bc::system;
using namespace bc::system::chain;
using namespace bc::system::config;
using namespace std::placeholders;

namespace keywords = boost::log::keywords;

static const auto application_name = "bs";
static constexpr int initialize_stop = 0;
static constexpr int directory_exists = 0;
static constexpr int directory_not_found = 2;
static const auto mode = std::ofstream::out | std::ofstream::app;

std::promise<code> executor::stopping_;

executor::executor(parser& metadata, std::istream& ,
    std::ostream& output, std::ostream& error)
  : metadata_(metadata), output_(output), error_(error)
{
    const auto& network = metadata_.configured.network;
    const auto verbose = network.verbose;

    const log::rotable_file debug_file
    {
        network.debug_file,
        network.archive_directory,
        network.rotation_size,
        network.maximum_archive_size,
        network.minimum_free_space,
        network.maximum_archive_files
    };

    const log::rotable_file error_file
    {
        network.error_file,
        network.archive_directory,
        network.rotation_size,
        network.maximum_archive_size,
        network.minimum_free_space,
        network.maximum_archive_files
    };

    log::stream console_out(&output_, null_deleter());
    log::stream console_err(&error_, null_deleter());

    log::initialize(debug_file, error_file, console_out, console_err, verbose);
    handle_stop(initialize_stop);
}

// Command line options.
// ----------------------------------------------------------------------------
// Emit directly to standard output (not the log).

void executor::do_help()
{
    const auto options = metadata_.load_options();
    printer help(options, application_name, BS_INFORMATION_MESSAGE);
    help.initialize();
    help.commandline(output_);
}

void executor::do_settings()
{
    const auto settings = metadata_.load_settings();
    printer print(settings, application_name, BS_SETTINGS_MESSAGE);
    print.initialize();
    print.settings(output_);
}

void executor::do_version()
{
    output_ << format(BS_VERSION_MESSAGE) %
        LIBBITCOIN_SERVER_VERSION %
        LIBBITCOIN_PROTOCOL_VERSION %
        LIBBITCOIN_NODE_VERSION %
        LIBBITCOIN_BLOCKCHAIN_VERSION %
        LIBBITCOIN_SYSTEM_VERSION << std::endl;
}

// Emit to the log.
bool executor::do_initchain()
{
    initialize_output();

    error_code ec;
    const auto& directory = metadata_.configured.database.directory;

    if (create_directories(directory, ec))
    {
        LOG_INFO(LOG_SERVER) << format(BS_INITIALIZING_CHAIN) % directory;

        const auto& bitcoin_settings = metadata_.configured.bitcoin;
        const auto result = data_base(metadata_.configured.database,
            metadata_.configured.chain.index_payments,
            metadata_.configured.chain.bip158).create(
                bitcoin_settings.genesis_block);

        LOG_INFO(LOG_SERVER) << BS_INITCHAIN_COMPLETE;
        return result;
    }

    if (ec.value() == directory_exists)
    {
        LOG_ERROR(LOG_SERVER) << format(BS_INITCHAIN_EXISTS) % directory;
        return false;
    }

    LOG_ERROR(LOG_SERVER) << format(BS_INITCHAIN_NEW) % directory % ec.message();
    return false;
}

// Menu selection.
// ----------------------------------------------------------------------------

bool executor::menu()
{
    const auto& config = metadata_.configured;

    if (config.help)
    {
        do_help();
        return true;
    }

    if (config.settings)
    {
        do_settings();
        return true;
    }

    if (config.version)
    {
        do_version();
        return true;
    }

    if (config.initchain)
    {
        return do_initchain();
    }

    // There are no command line arguments, just run the server.
    return run();
}

// Run.
// ----------------------------------------------------------------------------

bool executor::run()
{
    initialize_output();

    LOG_INFO(LOG_SERVER) << BS_NODE_STARTING;

    if (!verify_directory())
        return false;

    // Now that the directory is verified we can create the node for it.
    node_ = std::make_shared<server_node>(metadata_.configured);

    // Initialize broadcast to statistics server if configured.
    log::initialize_statsd(node_->thread_pool(),
        metadata_.configured.network.statistics_server);

    // The callback may be returned on the same thread.
    node_->start(
        std::bind(&executor::handle_started,
            this, _1));

    // Wait for stop.
    stopping_.get_future().wait();

    LOG_INFO(LOG_SERVER) << BS_NODE_STOPPING;

    // Close must be called from main thread.
    if (node_->close())
        LOG_INFO(LOG_NODE) << BS_NODE_STOPPED;
    else
        LOG_INFO(LOG_NODE) << BS_NODE_STOP_FAIL;

    return true;
}

// Handle the completion of the start sequence and begin the run sequence.
void executor::handle_started(const code& ec)
{
    // TEMP: use to repro start/stop deadlock race.
    ////auto thread = std::thread([this]() { stop(error::service_stopped); });

    if (ec)
    {
        LOG_ERROR(LOG_SERVER) << format(BS_NODE_START_FAIL) % ec.message();
        stop(ec);
        return;
    }

    LOG_INFO(LOG_SERVER) << BS_NODE_SEEDED;

    // This is the beginning of the stop sequence.
    node_->subscribe_stop(
        std::bind(&executor::handle_stopped,
            this, _1));

    // This is the beginning of the run sequence.
    node_->run(
        std::bind(&executor::handle_running,
            this, _1));

    // TEMP: see above.
    ////thread.join();
}

// This is the end of the run sequence.
void executor::handle_running(const code& ec)
{
    if (ec)
    {
        LOG_INFO(LOG_SERVER) << format(BS_NODE_START_FAIL) % ec.message();
        stop(ec);
        return;
    }

    LOG_INFO(LOG_SERVER) << BS_NODE_STARTED;
}

// This is the end of the stop sequence.
void executor::handle_stopped(const code& ec)
{
    stop(ec);
}

// Stop signal.
// ----------------------------------------------------------------------------

void executor::handle_stop(int code)
{
    // Reinitialize after each capture to prevent hard shutdown.
    // Do not capture failure signals as calling stop can cause flush lock file
    // to clear due to the aborted thread dropping the flush lock mutex.
    std::signal(SIGINT, handle_stop);
    std::signal(SIGTERM, handle_stop);

    if (code == initialize_stop)
        return;

    LOG_INFO(LOG_SERVER) << format(BS_NODE_SIGNALED) % code;
    stop(error::success);
}

void executor::stop(const code& ec)
{
    static std::once_flag stop_mutex;
    std::call_once(stop_mutex, [&](){ stopping_.set_value(ec); });
}

// Utilities.
// ----------------------------------------------------------------------------

// Set up logging.
void executor::initialize_output()
{
    const auto header = format(BS_LOG_HEADER) % local_time();
    LOG_DEBUG(LOG_SERVER) << header;
    LOG_INFO(LOG_SERVER) << header;
    LOG_WARNING(LOG_SERVER) << header;
    LOG_ERROR(LOG_SERVER) << header;
    LOG_FATAL(LOG_SERVER) << header;

    const auto& file = metadata_.configured.file;

    if (file.empty())
        LOG_INFO(LOG_SERVER) << BS_USING_DEFAULT_CONFIG;
    else
        LOG_INFO(LOG_SERVER) << format(BS_USING_CONFIG_FILE) % file;
}

// Use missing directory as a sentinel indicating lack of initialization.
bool executor::verify_directory()
{
    error_code ec;
    const auto& directory = metadata_.configured.database.directory;

    if (exists(directory, ec))
        return true;

    if (ec.value() == directory_not_found)
    {
        LOG_ERROR(LOG_SERVER) << format(BS_UNINITIALIZED_CHAIN) % directory;
        return false;
    }

    const auto message = ec.message();
    LOG_ERROR(LOG_SERVER) << format(BS_INITCHAIN_TRY) % directory % message;
    return false;
}

} // namespace server
} // namespace libbitcoin
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://www.opensource.org/licenses/MIT) //=======================================================================

#ifndef TLIB_NET_CONSTANTS_H
#define TLIB_NET_CONSTANTS_H

#include <types.hpp>

#include "tlib/config.hpp"

THOR_NAMESPACE(tlib, network) {

namespace ip {

struct address {
    uint32_t raw_address = 0;

    address(){}
    address(uint32_t raw) : raw_address(raw) {}

    uint8_t operator()(size_t index) const {
        return (raw_address >> ((3 - index) * 8)) & 0xFF;
    }

    void set_sub(size_t index, uint8_t value){
        raw_address |= uint32_t(value) << ((3 - index) * 8);
    }

    bool operator==(const address& rhs) const {
        return this->raw_address == rhs.raw_address;
    }
};

inline address make_address(uint8_t a, uint8_t b, uint8_t c, uint8_t d){
    address addr;
    addr.set_sub(0, a);
    addr.set_sub(1, b);
    addr.set_sub(2, c);
    addr.set_sub(3, d);
    return addr;
}

struct header {
    uint8_t version_ihl;
    uint8_t dscp_ecn;
    uint16_t total_len;
    uint16_t identification;
    uint16_t flags_offset;
    uint8_t ttl;
    uint8_t protocol;
    uint16_t header_checksum;
    uint32_t source_ip;
    uint32_t target_ip;
} __attribute__((packed));

struct packet_descriptor {
    size_t size;
    address destination;
    size_t protocol;
};

} // end of namespace ip

struct inet_address {
    ip::address address;
    size_t port;
};

namespace ethernet {

struct address {
    char mac[6];
} __attribute__((packed));

struct header {
    address target;
    address source;
    uint16_t type;
} __attribute__((packed));

enum class ether_type {
    IPV4,
    IPV6,
    ARP,
    UNKNOWN
};

struct packet_descriptor {
    size_t size;
    size_t destination;
    ether_type type;
};

} // end of namespace ethernet

namespace icmp {

enum class type : uint8_t {
    ECHO_REPLY = 0,
    UNREACHABLE = 3,
    SOURCE_QUENCH = 4,
    REDICT = 5,
    ECHO_REQUEST = 8,
    ROUTER_ADVERTISEMENT = 9,
    ROUTER_SOLICITATION = 10,
    TIME_EXCEEDED = 11,
    PARAMETER_PROBLEM = 12,
    TIMESTAMP = 13,
    TIMESTAMP_REPLY = 14,
    INFORMATION_REQUEST = 15,
    INFORMATION_REPLY = 16,
    ADDRESS_MASK_REQUEST = 17,
    ADDRESS_MASK_REPLY = 18,
    TRACEROUTE = 30
};

struct header {
    uint8_t type;
    uint8_t code;
    uint16_t checksum;
    uint32_t rest; ///< Depends on the type of packet type
} __attribute__((packed));

struct echo_request_header {
    uint16_t identifier;
    uint16_t sequence;
} __attribute__((packed));

struct packet_descriptor {
    size_t payload_size;
    ip::address target_ip;
    icmp::type type;
    size_t code;
};

} // end of namespace icmp

namespace http {

struct packet_descriptor {
    size_t payload_size;
    ip::address target_ip;
};

} // end of http namespace

namespace dns {

struct header {
    uint16_t identification;
    uint16_t flags;
    uint16_t questions;
    uint16_t answers;
    uint16_t authority_rrs;
    uint16_t additional_rrs;
} __attribute__((packed));

struct packet_descriptor {
    size_t payload_size;
    uint16_t identification;
    bool query;
};

} // end of dns namespace

namespace udp {

struct packet_descriptor {
    size_t payload_size;
};

} // end of udp namespace

namespace tcp {

struct header {
    uint16_t source_port;
    uint16_t target_port;
    uint32_t sequence_number;
    uint32_t ack_number;
    uint16_t flags;
    uint16_t window_size;
    uint16_t checksum;
    uint16_t urgent_pointer;
} __attribute__((packed));

struct packet_descriptor {
    size_t payload_size;
};

} // end of tcp namespace

enum class socket_domain : size_t {
    AF_INET
};

enum class socket_type : size_t {
    RAW,
    DGRAM,
    STREAM
};

enum class socket_protocol : size_t {
    ICMP,
    DNS,
    TCP,
    UDP
};

} // end of network namespace

#endif
<commit_msg>Document the network headers<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://www.opensource.org/licenses/MIT) //=======================================================================

#ifndef TLIB_NET_CONSTANTS_H
#define TLIB_NET_CONSTANTS_H

#include <types.hpp>

#include "tlib/config.hpp"

THOR_NAMESPACE(tlib, network) {

namespace ip {

/*!
 * \brief An IP Addres helper
 */
struct address {
    uint32_t raw_address = 0;

    address(){}
    address(uint32_t raw) : raw_address(raw) {}

    uint8_t operator()(size_t index) const {
        return (raw_address >> ((3 - index) * 8)) & 0xFF;
    }

    void set_sub(size_t index, uint8_t value){
        raw_address |= uint32_t(value) << ((3 - index) * 8);
    }

    bool operator==(const address& rhs) const {
        return this->raw_address == rhs.raw_address;
    }
};

inline address make_address(uint8_t a, uint8_t b, uint8_t c, uint8_t d){
    address addr;
    addr.set_sub(0, a);
    addr.set_sub(1, b);
    addr.set_sub(2, c);
    addr.set_sub(3, d);
    return addr;
}

/*!
 * \brief The header of an IP packet
 */
struct header {
    uint8_t version_ihl; ///< The version and header length
    uint8_t dscp_ecn;
    uint16_t total_len; ///< The total length of the packet
    uint16_t identification; ///< The identification of the packet
    uint16_t flags_offset; ///< The flags and data offset
    uint8_t ttl; ///< The time to live of the packet
    uint8_t protocol; ///< The protocol used
    uint16_t header_checksum; ///< The checksum
    uint32_t source_ip; ///< The source IP address
    uint32_t target_ip; ///< The target IP address
} __attribute__((packed));

struct packet_descriptor {
    size_t size;
    address destination;
    size_t protocol;
};

} // end of namespace ip

struct inet_address {
    ip::address address;
    size_t port;
};

namespace ethernet {

struct address {
    char mac[6];
} __attribute__((packed));

/*!
 * \brief The header of an ethernet packet
 */
struct header {
    address target; ///< The target MAC address
    address source; ///< The source MAC address
    uint16_t type; ///< The type of packet (the child layer)
} __attribute__((packed));

enum class ether_type {
    IPV4,
    IPV6,
    ARP,
    UNKNOWN
};

struct packet_descriptor {
    size_t size;
    size_t destination;
    ether_type type;
};

} // end of namespace ethernet

namespace icmp {

enum class type : uint8_t {
    ECHO_REPLY = 0,
    UNREACHABLE = 3,
    SOURCE_QUENCH = 4,
    REDICT = 5,
    ECHO_REQUEST = 8,
    ROUTER_ADVERTISEMENT = 9,
    ROUTER_SOLICITATION = 10,
    TIME_EXCEEDED = 11,
    PARAMETER_PROBLEM = 12,
    TIMESTAMP = 13,
    TIMESTAMP_REPLY = 14,
    INFORMATION_REQUEST = 15,
    INFORMATION_REPLY = 16,
    ADDRESS_MASK_REQUEST = 17,
    ADDRESS_MASK_REPLY = 18,
    TRACEROUTE = 30
};

/*!
 * \brief The header of an ICMP packet
 */
struct header {
    uint8_t type; ///< The type of message
    uint8_t code; ///< The code of the transmission (sub-type)
    uint16_t checksum; ///< The checksum
    uint32_t rest; ///< Depends on the type of packet type
} __attribute__((packed));

/*!
 * \brief The rest header of an ICMP request packet
 */
struct echo_request_header {
    uint16_t identifier; ///< The identifier
    uint16_t sequence;   ///< The sequence number
} __attribute__((packed));

struct packet_descriptor {
    size_t payload_size;
    ip::address target_ip;
    icmp::type type;
    size_t code;
};

} // end of namespace icmp

namespace http {

struct packet_descriptor {
    size_t payload_size;
    ip::address target_ip;
};

} // end of http namespace

namespace dns {

/*!
 * \brief The header of a DNS packet
 */
struct header {
    uint16_t identification; ///< The identification of the query
    uint16_t flags; ///< The flags
    uint16_t questions; ///< The number of questions
    uint16_t answers; ///< The number of answers
    uint16_t authority_rrs; ///< The number of authorithy Records
    uint16_t additional_rrs; ///< The number of additional Records
} __attribute__((packed));

struct packet_descriptor {
    size_t payload_size;
    uint16_t identification;
    bool query;
};

} // end of dns namespace

namespace udp {

struct packet_descriptor {
    size_t payload_size;
};

} // end of udp namespace

namespace tcp {

/*!
 * \brief The header of a TCP packet
 */
struct header {
    uint16_t source_port; ///< The TCP source port
    uint16_t target_port; ///< The TCP target port
    uint32_t sequence_number; ///< The sequence number
    uint32_t ack_number; ///< The acknowledge number
    uint16_t flags; ///< The flags
    uint16_t window_size; ///< The size of the receiving window
    uint16_t checksum; ///< The checksum
    uint16_t urgent_pointer; ///< Indicates if the packet is urgent
} __attribute__((packed));

struct packet_descriptor {
    size_t payload_size;
};

} // end of tcp namespace

enum class socket_domain : size_t {
    AF_INET
};

enum class socket_type : size_t {
    RAW,
    DGRAM,
    STREAM
};

enum class socket_protocol : size_t {
    ICMP,
    DNS,
    TCP,
    UDP
};

} // end of network namespace

#endif
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin-server.
 *
 * libbitcoin-server is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include "executor.hpp"

#include <chrono>
#include <csignal>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <boost/format.hpp>
#include <bitcoin/server.hpp>

namespace libbitcoin {
namespace server {

using boost::format;
using std::placeholders::_1;
using std::placeholders::_2;
using namespace boost::system;
using namespace bc::blockchain;
using namespace bc::config;
using namespace bc::database;
using namespace bc::network;

static constexpr int no_interrupt = 0;
static constexpr int directory_exists = 0;
static constexpr int directory_not_found = 2;
static constexpr auto append = std::ofstream::out | std::ofstream::app;

static const auto application_name = "bn";
static const auto stop_sensitivity = std::chrono::milliseconds(10);

// Class and method names must match protocol expectations (do not change).
#define ATTACH(worker, class_name, method_name, instance) \
    worker->attach(#class_name "." #method_name, \
        std::bind(&class_name::method_name, \
            instance, _1, _2));

// Static interrupt state (unavoidable).
static auto stopped_ = false;

// Static handler for catching termination signals.
static void initialize_interrupt(int code)
{
    // Reinitialize after each capture.
    signal(SIGINT, initialize_interrupt);
    signal(SIGTERM, initialize_interrupt);
    signal(SIGABRT, initialize_interrupt);

    // The no_interrupt sentinel is used for first initialization.
    if (code == no_interrupt)
    {
        log::info(LOG_NODE) << BS_NODE_INTERRUPT;
        return;
    }

    // Signal the service to stop if not already signaled.
    if (!stopped_)
    {
        log::info(LOG_NODE) << format(BS_NODE_STOPPING) % code;
        stopped_ = true;
    }
}

executor::executor(parser& metadata, std::istream& input,
    std::ostream& output, std::ostream& error)
  : metadata_(metadata), output_(output),
    debug_file_(metadata_.configured.network.debug_file.string(), append),
    error_file_(metadata_.configured.network.error_file.string(), append)
{
    initialize_logging(debug_file_, error_file_, output, error);
}

void executor::initialize_output()
{
    log::debug(LOG_NODE) << BS_LOG_HEADER;
    log::info(LOG_NODE) << BS_LOG_HEADER;
    log::warning(LOG_NODE) << BS_LOG_HEADER;
    log::error(LOG_NODE) << BS_LOG_HEADER;
    log::fatal(LOG_NODE) << BS_LOG_HEADER;

    const auto& file = metadata_.configured.file;

    if (file.empty())
        log::info(LOG_NODE) << BS_USING_DEFAULT_CONFIG;
    else
        log::info(LOG_NODE) << format(BS_USING_CONFIG_FILE) % file;
}

// ----------------------------------------------------------------------------
// Server API bindings.

// Class and method names must match protocol expectations (do not change).
void executor::attach_subscription_api()
{
    ATTACH(receive_, address, renew, notify_);
    ATTACH(receive_, address, subscribe, notify_);
}

// Class and method names must match protocol expectations (do not change).
void executor::attach_query_api()
{
    ATTACH(receive_, address, fetch_history2, node_);
    ATTACH(receive_, blockchain, fetch_history, node_);
    ATTACH(receive_, blockchain, fetch_transaction, node_);
    ATTACH(receive_, blockchain, fetch_last_height, node_);
    ATTACH(receive_, blockchain, fetch_block_header, node_);
    ATTACH(receive_, blockchain, fetch_block_transaction_hashes, node_);
    ATTACH(receive_, blockchain, fetch_transaction_index, node_);
    ATTACH(receive_, blockchain, fetch_spend, node_);
    ATTACH(receive_, blockchain, fetch_block_height, node_);
    ATTACH(receive_, blockchain, fetch_stealth, node_);
    ATTACH(receive_, transaction_pool, validate, node_);
    ATTACH(receive_, transaction_pool, fetch_transaction, node_);
    ATTACH(receive_, protocol, total_connections, node_);
    ATTACH(receive_, protocol, broadcast_transaction, node_);
}

// ----------------------------------------------------------------------------
// Command line options.
// Emit directly to standard output (not the log).

void executor::do_help()
{
    const auto options = metadata_.load_options();
    printer help(options, application_name, BS_INFORMATION_MESSAGE);
    help.initialize();
    help.commandline(output_);
}

void executor::do_settings()
{
    const auto settings = metadata_.load_settings();
    printer print(settings, application_name, BS_SETTINGS_MESSAGE);
    print.initialize();
    print.settings(output_);
}

void executor::do_version()
{
    output_ << format(BS_VERSION_MESSAGE) %
        LIBBITCOIN_SERVER_VERSION %
        LIBBITCOIN_NODE_VERSION %
        LIBBITCOIN_BLOCKCHAIN_VERSION %
        LIBBITCOIN_VERSION << std::endl;
}

// Emit to the logs.
bool executor::do_initchain()
{
    initialize_output();

    error_code ec;
    const auto& directory = metadata_.configured.database.directory;

    if (create_directories(directory, ec))
    {
        log::info(LOG_NODE) << format(BS_INITIALIZING_CHAIN) % directory;

        // Unfortunately we are still limited to a choice of hardcoded chains.
        const auto genesis = metadata_.configured.chain.use_testnet_rules ?
            chain::block::genesis_testnet() : chain::block::genesis_mainnet();

        return data_base::initialize(directory, genesis);
    }

    if (ec.value() == directory_exists)
    {
        log::error(LOG_NODE) << format(BS_INITCHAIN_EXISTS) % directory;
        return false;
    }

    log::error(LOG_NODE) << format(BS_INITCHAIN_NEW) % directory % ec.message();
    return false;
}

// ----------------------------------------------------------------------------
// Invoke an action based on command line option.

bool executor::invoke()
{
    const auto& config = metadata_.configured;

    if (config.help)
    {
        do_help();
        return true;
    }

    if (config.settings)
    {
        do_settings();
        return true;
    }

    if (config.version)
    {
        do_version();
        return true;
    }

    if (config.initchain)
    {
        return do_initchain();
    }

    // There are no command line arguments, just run the node.
    return run();
}

// ----------------------------------------------------------------------------
// Run sequence.

bool executor::run()
{
    initialize_output();
    initialize_interrupt(no_interrupt);

    log::info(LOG_NODE) << BS_NODE_STARTING;

    // Ensure the blockchain directory is initialized (at least exists).
    if (!verify())
        return false;

    // Now that the directory is verified we can create the node for it.
    node_ = std::make_shared<server_node>(metadata_.configured);

    // Start seeding the node, stop handlers are registered in start.
    node_->start(
        std::bind(&executor::handle_seeded,
            shared_from_this(), _1));

    log::info(LOG_NODE) << BS_NODE_STARTED;

    // Block until the node is stopped or there is an interrupt.
    return wait_on_stop();
}

void executor::handle_seeded(const code& ec)
{
    if (ec)
    {
        log::error(LOG_NODE) << format(BS_NODE_START_FAIL) % ec.message();
        stopped_ = true;
        return;
    }

    node_->run(
        std::bind(&executor::handle_synchronized,
            shared_from_this(), _1));

    log::info(LOG_NODE) << BS_NODE_SEEDED;
}

void executor::handle_synchronized(const code& ec)
{
    if (ec)
    {
        log::info(LOG_NODE) << format(BS_NODE_START_FAIL) % ec.message();
        stopped_ = true;
        return;
    }

    log::info(LOG_NODE) << BS_NODE_SYNCHRONIZED;

    notify_ = std::make_shared<notifier>(node_);
    receive_ = std::make_shared<receiver>(node_);
    publish_ = std::make_shared<publisher>(node_);

    // Start server services on top of the node, these log internally.
    if (!publish_->start() || !receive_->start() || !notify_->start())
    {
        stopped_ = true;
        return;
    }

    const auto& settings = metadata_.configured.server;

    if (settings.queries_enabled)
        attach_query_api();

    if (settings.subscription_limit > 0)
        attach_subscription_api();
}

// Use missing directory as a sentinel indicating lack of initialization.
bool executor::verify()
{
    error_code ec;
    const auto& directory = metadata_.configured.database.directory;

    if (exists(directory, ec))
        return true;

    if (ec.value() == directory_not_found)
    {
        log::error(LOG_NODE) << format(BS_UNINITIALIZED_CHAIN) % directory;
        return false;
    }

    const auto message = ec.message();
    log::error(LOG_NODE) << format(BS_INITCHAIN_TRY) % directory % message;
    return false;
}

bool executor::wait_on_stop()
{
    std::promise<code> promise;

    // Monitor stopped for completion.
    monitor_stop(
        std::bind(&executor::handle_stopped,
            shared_from_this(), _1, std::ref(promise)));

    // Block until the stop handler is invoked.
    const auto ec = promise.get_future().get();

    if (ec)
    {
        log::error(LOG_NODE) << format(BS_NODE_STOP_FAIL) % ec.message();
        return false;
    }

    log::info(LOG_NODE) << BS_NODE_STOPPED;
    return true;
}

void executor::handle_stopped(const code& ec, std::promise<code>& promise)
{
    promise.set_value(ec);
}

void executor::monitor_stop(p2p::result_handler handler)
{
    while (!stopped_ && !node_->stopped())
        std::this_thread::sleep_for(stop_sensitivity);

    log::info(LOG_NODE) << BS_NODE_UNMAPPING;
    node_->stop(handler);
    node_->close();

    // This is the end of the run sequence.
    node_ = nullptr;
}

} // namespace server
} // namespace libbitcoin
<commit_msg>Add missing include.<commit_after>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin-server.
 *
 * libbitcoin-server is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include "executor.hpp"

#include <chrono>
#include <csignal>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <bitcoin/server.hpp>

namespace libbitcoin {
namespace server {

using boost::format;
using std::placeholders::_1;
using std::placeholders::_2;
using namespace boost::system;
using namespace bc::blockchain;
using namespace bc::config;
using namespace bc::database;
using namespace bc::network;

static constexpr int no_interrupt = 0;
static constexpr int directory_exists = 0;
static constexpr int directory_not_found = 2;
static constexpr auto append = std::ofstream::out | std::ofstream::app;

static const auto application_name = "bn";
static const auto stop_sensitivity = std::chrono::milliseconds(10);

// Class and method names must match protocol expectations (do not change).
#define ATTACH(worker, class_name, method_name, instance) \
    worker->attach(#class_name "." #method_name, \
        std::bind(&class_name::method_name, \
            instance, _1, _2));

// Static interrupt state (unavoidable).
static auto stopped_ = false;

// Static handler for catching termination signals.
static void initialize_interrupt(int code)
{
    // Reinitialize after each capture.
    signal(SIGINT, initialize_interrupt);
    signal(SIGTERM, initialize_interrupt);
    signal(SIGABRT, initialize_interrupt);

    // The no_interrupt sentinel is used for first initialization.
    if (code == no_interrupt)
    {
        log::info(LOG_NODE) << BS_NODE_INTERRUPT;
        return;
    }

    // Signal the service to stop if not already signaled.
    if (!stopped_)
    {
        log::info(LOG_NODE) << format(BS_NODE_STOPPING) % code;
        stopped_ = true;
    }
}

executor::executor(parser& metadata, std::istream& input,
    std::ostream& output, std::ostream& error)
  : metadata_(metadata), output_(output),
    debug_file_(metadata_.configured.network.debug_file.string(), append),
    error_file_(metadata_.configured.network.error_file.string(), append)
{
    initialize_logging(debug_file_, error_file_, output, error);
}

void executor::initialize_output()
{
    log::debug(LOG_NODE) << BS_LOG_HEADER;
    log::info(LOG_NODE) << BS_LOG_HEADER;
    log::warning(LOG_NODE) << BS_LOG_HEADER;
    log::error(LOG_NODE) << BS_LOG_HEADER;
    log::fatal(LOG_NODE) << BS_LOG_HEADER;

    const auto& file = metadata_.configured.file;

    if (file.empty())
        log::info(LOG_NODE) << BS_USING_DEFAULT_CONFIG;
    else
        log::info(LOG_NODE) << format(BS_USING_CONFIG_FILE) % file;
}

// ----------------------------------------------------------------------------
// Server API bindings.

// Class and method names must match protocol expectations (do not change).
void executor::attach_subscription_api()
{
    ATTACH(receive_, address, renew, notify_);
    ATTACH(receive_, address, subscribe, notify_);
}

// Class and method names must match protocol expectations (do not change).
void executor::attach_query_api()
{
    ATTACH(receive_, address, fetch_history2, node_);
    ATTACH(receive_, blockchain, fetch_history, node_);
    ATTACH(receive_, blockchain, fetch_transaction, node_);
    ATTACH(receive_, blockchain, fetch_last_height, node_);
    ATTACH(receive_, blockchain, fetch_block_header, node_);
    ATTACH(receive_, blockchain, fetch_block_transaction_hashes, node_);
    ATTACH(receive_, blockchain, fetch_transaction_index, node_);
    ATTACH(receive_, blockchain, fetch_spend, node_);
    ATTACH(receive_, blockchain, fetch_block_height, node_);
    ATTACH(receive_, blockchain, fetch_stealth, node_);
    ATTACH(receive_, transaction_pool, validate, node_);
    ATTACH(receive_, transaction_pool, fetch_transaction, node_);
    ATTACH(receive_, protocol, total_connections, node_);
    ATTACH(receive_, protocol, broadcast_transaction, node_);
}

// ----------------------------------------------------------------------------
// Command line options.
// Emit directly to standard output (not the log).

void executor::do_help()
{
    const auto options = metadata_.load_options();
    printer help(options, application_name, BS_INFORMATION_MESSAGE);
    help.initialize();
    help.commandline(output_);
}

void executor::do_settings()
{
    const auto settings = metadata_.load_settings();
    printer print(settings, application_name, BS_SETTINGS_MESSAGE);
    print.initialize();
    print.settings(output_);
}

void executor::do_version()
{
    output_ << format(BS_VERSION_MESSAGE) %
        LIBBITCOIN_SERVER_VERSION %
        LIBBITCOIN_NODE_VERSION %
        LIBBITCOIN_BLOCKCHAIN_VERSION %
        LIBBITCOIN_VERSION << std::endl;
}

// Emit to the logs.
bool executor::do_initchain()
{
    initialize_output();

    error_code ec;
    const auto& directory = metadata_.configured.database.directory;

    if (create_directories(directory, ec))
    {
        log::info(LOG_NODE) << format(BS_INITIALIZING_CHAIN) % directory;

        // Unfortunately we are still limited to a choice of hardcoded chains.
        const auto genesis = metadata_.configured.chain.use_testnet_rules ?
            chain::block::genesis_testnet() : chain::block::genesis_mainnet();

        return data_base::initialize(directory, genesis);
    }

    if (ec.value() == directory_exists)
    {
        log::error(LOG_NODE) << format(BS_INITCHAIN_EXISTS) % directory;
        return false;
    }

    log::error(LOG_NODE) << format(BS_INITCHAIN_NEW) % directory % ec.message();
    return false;
}

// ----------------------------------------------------------------------------
// Invoke an action based on command line option.

bool executor::invoke()
{
    const auto& config = metadata_.configured;

    if (config.help)
    {
        do_help();
        return true;
    }

    if (config.settings)
    {
        do_settings();
        return true;
    }

    if (config.version)
    {
        do_version();
        return true;
    }

    if (config.initchain)
    {
        return do_initchain();
    }

    // There are no command line arguments, just run the node.
    return run();
}

// ----------------------------------------------------------------------------
// Run sequence.

bool executor::run()
{
    initialize_output();
    initialize_interrupt(no_interrupt);

    log::info(LOG_NODE) << BS_NODE_STARTING;

    // Ensure the blockchain directory is initialized (at least exists).
    if (!verify())
        return false;

    // Now that the directory is verified we can create the node for it.
    node_ = std::make_shared<server_node>(metadata_.configured);

    // Start seeding the node, stop handlers are registered in start.
    node_->start(
        std::bind(&executor::handle_seeded,
            shared_from_this(), _1));

    log::info(LOG_NODE) << BS_NODE_STARTED;

    // Block until the node is stopped or there is an interrupt.
    return wait_on_stop();
}

void executor::handle_seeded(const code& ec)
{
    if (ec)
    {
        log::error(LOG_NODE) << format(BS_NODE_START_FAIL) % ec.message();
        stopped_ = true;
        return;
    }

    node_->run(
        std::bind(&executor::handle_synchronized,
            shared_from_this(), _1));

    log::info(LOG_NODE) << BS_NODE_SEEDED;
}

void executor::handle_synchronized(const code& ec)
{
    if (ec)
    {
        log::info(LOG_NODE) << format(BS_NODE_START_FAIL) % ec.message();
        stopped_ = true;
        return;
    }

    log::info(LOG_NODE) << BS_NODE_SYNCHRONIZED;

    notify_ = std::make_shared<notifier>(node_);
    receive_ = std::make_shared<receiver>(node_);
    publish_ = std::make_shared<publisher>(node_);

    // Start server services on top of the node, these log internally.
    if (!publish_->start() || !receive_->start() || !notify_->start())
    {
        stopped_ = true;
        return;
    }

    const auto& settings = metadata_.configured.server;

    if (settings.queries_enabled)
        attach_query_api();

    if (settings.subscription_limit > 0)
        attach_subscription_api();
}

// Use missing directory as a sentinel indicating lack of initialization.
bool executor::verify()
{
    error_code ec;
    const auto& directory = metadata_.configured.database.directory;

    if (exists(directory, ec))
        return true;

    if (ec.value() == directory_not_found)
    {
        log::error(LOG_NODE) << format(BS_UNINITIALIZED_CHAIN) % directory;
        return false;
    }

    const auto message = ec.message();
    log::error(LOG_NODE) << format(BS_INITCHAIN_TRY) % directory % message;
    return false;
}

bool executor::wait_on_stop()
{
    std::promise<code> promise;

    // Monitor stopped for completion.
    monitor_stop(
        std::bind(&executor::handle_stopped,
            shared_from_this(), _1, std::ref(promise)));

    // Block until the stop handler is invoked.
    const auto ec = promise.get_future().get();

    if (ec)
    {
        log::error(LOG_NODE) << format(BS_NODE_STOP_FAIL) % ec.message();
        return false;
    }

    log::info(LOG_NODE) << BS_NODE_STOPPED;
    return true;
}

void executor::handle_stopped(const code& ec, std::promise<code>& promise)
{
    promise.set_value(ec);
}

void executor::monitor_stop(p2p::result_handler handler)
{
    while (!stopped_ && !node_->stopped())
        std::this_thread::sleep_for(stop_sensitivity);

    log::info(LOG_NODE) << BS_NODE_UNMAPPING;
    node_->stop(handler);
    node_->close();

    // This is the end of the run sequence.
    node_ = nullptr;
}

} // namespace server
} // namespace libbitcoin
<|endoftext|>