#!/bin/bash

function read_yn {
  read -p "$1 [y/n]: " read_value
  while [ ! $read_value == "y" ] && [ ! $read_value == "n" ]; do
    echo "Please answer y or n; got $read_value"
    read -p "$1 [y/n]:" read_value
  done
  eval $2=$read_value
}

VERSION="9.0.0"

URL="http://releases.llvm.org"
 
WGET=wget

CURRENT_DIR=`pwd`
INSTALL_DIR=`pwd`/install
BUILD_DIR=$CURRENT_DIR/build

# Using 2 threads by default
NUM_THREADS=2

SUFFIX=".tar.xz"
CLANG_SRC="cfe-$VERSION.src"
LLVM_SRC="llvm-$VERSION.src"

HPVM_RT=hpvm-rt/hpvm-rt.bc


TARGET=all
TARGET_INPUT=all
FLAGGED=false

# Get flags
while getopts 'hmj:t:' opt; do
  case $opt in
    h) 
      echo
      echo
      echo "This is the help menu for HPVM installation"
      echo
      echo "There are 3 options for installation:"
      echo
      echo "-m is a manual installation flag. This will require you to install HPVM manually by running cmake and make manually." 
      echo "For more details, refer to README.md. Defaults to automatic installation."
      echo
      echo "-j is the threads flag. Accepts one argument: how many threads to build with." 
      echo "To build with 2 threads, enter -j2. Defaults to 2 threads."
      echo
      echo "-t is the build target flag. Accepts one argument: which build target(s) you would like to build to." 
      echo "For single target, enter -a ARM. For multiple targets, enter -t \"X86;ARM\"." 
      echo "Supports the following targets: AArch64, AMDGPU, ARM, BPF, Hexagon, Mips, MSP430, NVPTX, PowerPC, Sparc, SystemZ, X86, XCore."
      echo "Defaults to targeting all supported architectures."
      echo
      echo "If no flags are provided, the script will use command line prompts for all options."
      echo
      exit
      ;;
    m) 
      AUTOMATE=false
      FLAGGED=true
      ;;
    j) 
      if ! [[ $OPTARG =~ ^[0-9]+$ ]]; then
        echo "Invalid argument for # of threads: $OPTARG"
        exit -1;
      else
        NUM_THREADS=$OPTARG
        FLAGGED=true
      fi
      ;;
    t) 
      TARGET=$OPTARG
      FLAGGED=true
      ;;
  esac
done

if $FLAGGED; then
  echo "Running with the following options:"
  echo Automated: $AUTOMATE
  echo Threads: $NUM_THREADS
  echo Targets: $TARGET
  echo
else
  echo "No Flags found. Using command line prompts."
  read -p "Build and install HPVM automatically? (y or n): " AUTOMATE_INPUT

  if [[ $AUTOMATE_INPUT == "" ]]; then
    echo "No input given. Using default: $AUTOMATE"
  elif [[ ! $AUTOMATE_INPUT == "y" ]] && [[ ! $AUTOMATE_INPUT == "n" ]]; then 
    echo "Invalid input. Using default: $AUTOMATE"
  elif [[ $AUTOMATE_INPUT == "n" ]]; then
    AUTOMATE=false
  fi


  echo
  read -p "Number of threads: " NUM_THREADS_INPUT

  if [[ $NUM_THREADS_INPUT == "" ]]; then
    echo "No input given. Using default: $NUM_THREADS"
  elif ! [[ $NUM_THREADS_INPUT =~ ^[0-9]+$ ]]; then
    echo "Given input is not an integer. Using default: $NUM_THREADS"
  elif [ ! $NUM_THREADS_INPUT -gt 0 ]; then
    echo "Given input is not greater than 0. Using default: $NUM_THREADS"
  else
    NUM_THREADS=$NUM_THREADS_INPUT
  fi
  
  echo
  echo 
  echo "Supports the following options: AArch64, AMDGPU, ARM, BPF, Hexagon, Mips, MSP430, NVPTX, PowerPC, Sparc, SystemZ, X86, XCore."
  echo "If building for multiple targets, seperate options with semicolon:"
  echo "e.g. X86;ARM"
  read -p "Build target: " TARGET_INPUT
  if [[ $TARGET_INPUT == "" ]]; then
    echo "No input given. Using default: $TARGET"
  else
    TARGET=$TARGET_INPUT
  fi
  echo

  echo "Running with the following options:"
  echo Automated: $AUTOMATE
  echo Threads: $NUM_THREADS
  echo Targets: $TARGET
  echo
fi

if [ -d $LLVM_SRC ]; then
    echo Found $LLVM_SRC, not dowloading it again!
elif [ -d llvm ]; then
    echo Found LLVM, not downloading it again!
else
    echo $WGET $URL/$VERSION/$LLVM_SRC$SUFFIX
    $WGET $URL/$VERSION/$LLVM_SRC$SUFFIX
    tar xf $LLVM_SRC$SUFFIX
    rm $LLVM_SRC$SUFFIX
fi

if [ -d $LLVM_SRC ]; then
    echo Everything looks sane.
    mv $LLVM_SRC llvm
elif [ -d llvm ]; then
    echo Everything looks sane.
else
    echo Problem with LLVM download. Exiting!
    exit
fi

LLVM_SRC=llvm

if [ -d $CURRENT_DIR/$LLVM_SRC/tools ]; then
    cd $CURRENT_DIR/$LLVM_SRC/tools
    echo In tools.
else
    echo Something is wrong with LLVM checkout. Exiting!
    exit 1
fi

if [ -d clang ]; then
    echo Found clang! Not downloading clang again.
else
    $WGET $URL/$VERSION/$CLANG_SRC$SUFFIX
    tar xf $CLANG_SRC$SUFFIX
    rm $CLANG_SRC$SUFFIX
    mv $CLANG_SRC clang
    if [ -d clang ]; then
	echo Everything looks sane.
    else
	echo Problem with clang download. Exiting!
	exit
    fi
fi

cd $CURRENT_DIR

HPVM_DIR=$CURRENT_DIR/$LLVM_SRC/tools/hpvm

if [ ! -d $HPVM_DIR ]; then
  echo Adding HPVM sources to tree
  mkdir -p $HPVM_DIR
  ln -s $CURRENT_DIR/CMakeLists.txt $HPVM_DIR
  ln -s $CURRENT_DIR/cmake $HPVM_DIR/
  ln -s $CURRENT_DIR/include $HPVM_DIR/
  ln -s $CURRENT_DIR/lib $HPVM_DIR/
  ln -s $CURRENT_DIR/projects $HPVM_DIR/
  ln -s $CURRENT_DIR/test $HPVM_DIR/
  ln -s $CURRENT_DIR/tools $HPVM_DIR/
else
  echo $CURRENT_DIR/$LLVM_SRC/tools/hpvm exists.
fi

export LLVM_SRC_ROOT=$CURRENT_DIR/$LLVM_SRC

echo Applying HPVM patches
cd $CURRENT_DIR/llvm_patches
/bin/bash ./construct_patch.sh
/bin/bash ./apply_patch.sh

echo Patches applied.

if ! $AUTOMATE ; then
  echo
  echo "HPVM not installed."
  echo "To complete installation, follow these instructions:"
  echo "  - Create and navigate to a folder \"./build\" "
  echo "  - Run \"cmake ../llvm [options]\". Find potential options in README.md."
  echo "  - Run \"make -j<number of threads> approxhpvm.py\" and then \"make install\""
  echo "For more details refer to README.md."
  echo 
  echo "Exiting."
  exit  
fi

echo
echo Now building...

echo Using $NUM_THREADS threads to build HPVM.
echo

cd $CURRENT_DIR

if [ ! -d $BUILD_DIR ]; then
  mkdir -p $BUILD_DIR
fi

if [ ! -d $INSTALL_DIR ]; then
  mkdir -p $INSTALL_DIR
fi

export PATH=$BUILD_DIR/bin:$PATH

cd $BUILD_DIR
echo cmake ../$LLVM_SRC -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DLLVM_TARGETS_TO_BUILD=$TARGET  -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR
cmake ../$LLVM_SRC -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DLLVM_TARGETS_TO_BUILD=$TARGET  -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR

echo make -j$NUM_THREADS approxhpvm.py
make -j$NUM_THREADS approxhpvm.py
#make install

if [ -f $BUILD_DIR/tools/hpvm/projects/$HPVM_RT ]; then
    true
else
    echo $BUILD_DIR/tools/hpvm/projects/$HPVM_RT
    echo HPVM not installed properly.
    exit 0
fi

cd $CURRENT_DIR