CC=gcc
BENCH_EXAMPLE=./comp 16 0 14 9 8 7 5 0 0 1 0 0 0 4 0
LIBS=-fopenmp
CFLAGS=-O3 $(LIBS) -Wall -Werror -Wextra -Wpedantic -Wconversion -Wcast-align -Wunused -Wshadow -Wpointer-arith -Wcast-qual -Wmissing-prototypes -Wno-missing-braces

.PHONY: default clean all comps bench

all: turn comps

clean: 
	rm -f *.gcda *.o comp turn comp_alphabeta comp_openmp comp_profile comp_table comp_opt_oware

###
# Turn is not optimized !
# can be optimized by replacing oware.o with opt_oware.o
###

turn:
	$(CC) $(CFLAGS) -c turn.c -o turn.o -I.
	$(CC) $(CFLAGS) -c oware.c -o oware.o -I.
	$(CC) $(CFLAGS) turn.o oware.o -o turn

##
# Comp Program Alternatives
# 
# comp_alphabeta (default)
# comp_openmp 
# comp_opt_oware
# comp_table
##
comp: 
	make default

default: 
	make comp_alphabeta

comps: 
	make comp_openmp 
	mv ./comp ./comp_openmp
	make comp_opt_oware 
	mv ./comp ./comp_opt_oware
	make comp_profile 
	mv ./comp ./comp_profile
	make comp_table
	mv ./comp ./comp_table
	make comp_alphabeta 
	cp ./comp ./comp_alphabeta

comp_openmp: openmp_search.c openmp_search.h oware.c oware.h comp.c comp.h
	$(CC) $(CFLAGS) -c oware.c -o oware.o -I.
	$(CC) $(CFLAGS) -c openmp_search.c -o openmp_search.o -I.
	$(CC) $(CFLAGS) -D USE_OPENMP -c comp.c -o comp_openmp.o -I.
	$(CC) $(CFLAGS) comp_openmp.o openmp_search.o oware.o -o comp

comp_table: table_search.c table_search.h oware.c oware.h comp.c comp.h
	$(CC) $(CFLAGS) -c oware.c -o oware.o -I.
	$(CC) $(CFLAGS) -c table_search.c -o table_search.o -I.
	$(CC) $(CFLAGS) -D USE_TABLE -c comp.c -o comp_table.o -I.
	$(CC) $(CFLAGS) comp_table.o table_search.o oware.o -o comp

comp_alphabeta: alphabeta_search.c alphabeta_search.h oware.c oware.h comp.c comp.h
	$(CC) $(CFLAGS) -c oware.c -o oware.o -I.
	$(CC) $(CFLAGS) -c alphabeta_search.c -o alphabeta_search.o -I.
	$(CC) $(CFLAGS) -D USE_ALPHABETA -c comp.c -o comp_alphabeta.o -I.
	$(CC) $(CFLAGS) comp_alphabeta.o alphabeta_search.o oware.o -o comp

comp_opt_oware: alphabeta_search.c alphabeta_search.h opt_oware.c opt_oware.h comp.c comp.h
	$(CC) $(CFLAGS) -c opt_oware.c -o  opt_oware.o -I.
	$(CC) $(CFLAGS) -D USE_OPT_OWARE -c alphabeta_search.c -o alphabeta_search_opt_oware.o -I.
	$(CC) $(CFLAGS) -D USE_ALPHABETA -D USE_OPT_OWARE -c comp.c -o comp_opt_oware.o -I.
	$(CC) $(CFLAGS) comp_opt_oware.o alphabeta_search_opt_oware.o opt_oware.o -o comp

comp_profile:
	rm -f comp *.gcda *.o
	$(CC) -fprofile-generate $(CFLAGS) -c oware.c -o oware.o -I.
	$(CC) -fprofile-generate $(CFLAGS) -D USE_ALPHABETA -c comp.c -o comp.o -I.
	$(CC) -fprofile-generate $(CFLAGS) -c alphabeta_search.c -o alphabeta_search.o -I.
	$(CC) -fprofile-generate $(CFLAGS) comp.o alphabeta_search.o oware.o -o comp
	# OMP_NUM_THREADS=1 $(BENCH_EXAMPLE) would be for openmp
	$(BENCH_EXAMPLE)
	$(CC) -fprofile-use $(CFLAGS) -c oware.c -o oware.o -I.
	$(CC) -fprofile-use $(CFLAGS) -D USE_ALPHABETA -c comp.c -o comp.o -I.
	$(CC) -fprofile-use $(CFLAGS) -c alphabeta_search.c -o alphabeta_search.o -I.
	$(CC) -fprofile-use $(CFLAGS) comp.o alphabeta_search.o oware.o -o comp


##
# builds
# opt_oware, openmp, profiling
##
comp_all:
	rm -f comp *.gcda *.o
	$(CC) -fprofile-generate $(CFLAGS) -c opt_oware.c -o opt_oware.o -I.
	$(CC) -fprofile-generate $(CFLAGS) -D USE_OPT_OWARE -D USE_OPENMP -c comp.c -o comp.o -I.
	$(CC) -fprofile-generate $(CFLAGS) -D USE_OPT_OWARE -c openmp_search.c -o openmp_search.o -I.
	$(CC) -fprofile-generate $(CFLAGS) comp.o openmp_search.o opt_oware.o -o comp
	OMP_NUM_THREADS=1 $(BENCH_EXAMPLE) # for openmp
	$(CC) -fprofile-use $(CFLAGS) -c opt_oware.c -o opt_oware.o -I.
	$(CC) -fprofile-use $(CFLAGS) -D USE_OPT_OWARE -D USE_OPENMP -c comp.c -o comp.o -I.
	$(CC) -fprofile-use $(CFLAGS) -c openmp_search.c -o openmp_search.o -I.
	$(CC) -fprofile-use $(CFLAGS) comp.o openmp_search.o opt_oware.o -o comp


##
# Benchmark Command
##

bench: comp
	LC_NUMERIC=en_US.utf8 perf stat -B -e cycles:u -e instructions:u -e branches:u -e branch-misses:u -e L1-dcache-load-misses:u -e dTLB-load-misses:u $(BENCH_EXAMPLE)
