#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>


static const char *key = 	"abort"
	"absolute"
	"access"
	"action"
	"add"
	"admin"
	"after"
	"aggregate"
	"all"
	"also"
	"alter"
	"always"
	"analyse"
	"analyze"
	"and"
	"any"
	"array"
	"as"
	"asc"
	"assertion"
	"assignment"
	"asymmetric"
	"at"
	"attach"
	"attribute"
	"authorization"
	"backward"
	"before"
	"begin"
	"between"
	"bigint"
	"binary"
	"bit"
	"boolean"
	"both"
	"by"
	"cache"
	"call"
	"called"
	"cascade"
	"cascaded"
	"case"
	"cast"
	"catalog"
	"chain"
	"char"
	"character"
	"characteristics"
	"check"
	"checkpoint"
	"class"
	"close"
	"cluster"
	"coalesce"
	"collate"
	"collation"
	"column"
	"columns"
	"comment"
	"comments"
	"commit"
	"committed"
	"concurrently"
	"configuration"
	"conflict"
	"connection"
	"constraint"
	"constraints"
	"content"
	"continue"
	"conversion"
	"copy"
	"cost"
	"create"
	"cross"
	"csv"
	"cube"
	"current"
	"current_catalog"
	"current_date"
	"current_role"
	"current_schema"
	"current_time"
	"current_timestamp"
	"current_user"
	"cursor"
	"cycle"
	"data"
	"database"
	"day"
	"deallocate"
	"dec"
	"decimal"
	"declare"
	"default"
	"defaults"
	"deferrable"
	"deferred"
	"definer"
	"delete"
	"delimiter"
	"delimiters"
	"depends"
	"desc"
	"detach"
	"dictionary"
	"disable"
	"discard"
	"distinct"
	"do"
	"document"
	"domain"
	"double"
	"drop"
	"each"
	"else"
	"enable"
	"encoding"
	"encrypted"
	"end"
	"enum"
	"escape"
	"event"
	"except"
	"exclude"
	"excluding"
	"exclusive"
	"execute"
	"exists"
	"explain"
	"expression"
	"extension"
	"external"
	"extract"
	"false"
	"family"
	"fetch"
	"filter"
	"first"
	"float"
	"following"
	"for"
	"force"
	"foreign"
	"forward"
	"freeze"
	"from"
	"full"
	"function"
	"functions"
	"generated"
	"global"
	"grant"
	"granted"
	"greatest"
	"group"
	"grouping"
	"groups"
	"handler"
	"having"
	"header"
	"hold"
	"hour"
	"identity"
	"if"
	"ilike"
	"immediate"
	"immutable"
	"implicit"
	"import"
	"in"
	"include"
	"including"
	"increment"
	"index"
	"indexes"
	"inherit"
	"inherits"
	"initially"
	"inline"
	"inner"
	"inout"
	"input"
	"insensitive"
	"insert"
	"instead"
	"int"
	"integer"
	"intersect"
	"interval"
	"into"
	"invoker"
	"is"
	"isnull"
	"isolation"
	"join"
	"key"
	"label"
	"language"
	"large"
	"last"
	"lateral"
	"leading"
	"leakproof"
	"least"
	"left"
	"level"
	"like"
	"limit"
	"listen"
	"load"
	"local"
	"localtime"
	"localtimestamp"
	"location"
	"lock"
	"locked"
	"logged"
	"mapping"
	"match"
	"materialized"
	"maxvalue"
	"method"
	"minute"
	"minvalue"
	"mode"
	"month"
	"move"
	"name"
	"names"
	"national"
	"natural"
	"nchar"
	"new"
	"next"
	"nfc"
	"nfd"
	"nfkc"
	"nfkd"
	"no"
	"none"
	"normalize"
	"normalized"
	"not"
	"nothing"
	"notify"
	"notnull"
	"nowait"
	"null"
	"nullif"
	"nulls"
	"numeric"
	"object"
	"of"
	"off"
	"offset"
	"oids"
	"old"
	"on"
	"only"
	"operator"
	"option"
	"options"
	"or"
	"order"
	"ordinality"
	"others"
	"out"
	"outer"
	"over"
	"overlaps"
	"overlay"
	"overriding"
	"owned"
	"owner"
	"parallel"
	"parser"
	"partial"
	"partition"
	"passing"
	"password"
	"placing"
	"plans"
	"policy"
	"position"
	"preceding"
	"precision"
	"prepare"
	"prepared"
	"preserve"
	"primary"
	"prior"
	"privileges"
	"procedural"
	"procedure"
	"procedures"
	"program"
	"publication"
	"quote"
	"range"
	"read"
	"real"
	"reassign"
	"recheck"
	"recursive"
	"ref"
	"references"
	"referencing"
	"refresh"
	"reindex"
	"relative"
	"release"
	"rename"
	"repeatable"
	"replace"
	"replica"
	"reset"
	"restart"
	"restrict"
	"returning"
	"returns"
	"revoke"
	"right"
	"role"
	"rollback"
	"rollup"
	"routine"
	"routines"
	"row"
	"rows"
	"rule"
	"savepoint"
	"schema"
	"schemas"
	"scroll"
	"search"
	"second"
	"security"
	"select"
	"sequence"
	"sequences"
	"serializable"
	"server"
	"session"
	"session_user"
	"set"
	"setof"
	"sets"
	"share"
	"show"
	"similar"
	"simple"
	"skip"
	"smallint"
	"snapshot"
	"some"
	"sql"
	"stable"
	"standalone"
	"start"
	"statement"
	"statistics"
	"stdin"
	"stdout"
	"storage"
	"stored"
	"strict"
	"strip"
	"subscription"
	"substring"
	"support"
	"symmetric"
	"sysid"
	"system"
	"table"
	"tables"
	"tablesample"
	"tablespace"
	"temp"
	"template"
	"temporary"
	"text"
	"then"
	"ties"
	"time"
	"timestamp"
	"to"
	"trailing"
	"transaction"
	"transform"
	"treat"
	"trigger"
	"trim"
	"true"
	"truncate"
	"trusted"
	"type"
	"types"
	"uescape"
	"unbounded"
	"uncommitted"
	"unencrypted"
	"union"
	"unique"
	"unknown"
	"unlisten"
	"unlogged"
	"until"
	"update"
	"user"
	"using"
	"vacuum"
	"valid"
	"validate"
	"validator"
	"value"
	"values"
	"varchar"
	"variadic"
	"varying"
	"verbose"
	"version"
	"view"
	"views"
	"volatile"
	"when"
	"where"
	"whitespace"
	"window"
	"with"
	"within"
	"without"
	"work"
	"wrapper"
	"write"
	"xml"
	"xmlattributes"
	"xmlconcat"
	"xmlelement"
	"xmlexists"
	"xmlforest"
	"xmlnamespaces"
	"xmlparse"
	"xmlpi"
	"xmlroot"
	"xmlserialize"
	"xmltable"
	"year"
	"yes"
	"zone";


extern unsigned int lea_lea (const char *k, int keylen);
extern unsigned int lea_leaadd (const char *k, int keylen);
extern unsigned int lea_shiftadd (const char *k, int keylen);

extern unsigned int leaadd_shiftadd (const char *k, int keylen);
extern unsigned int shiftadd_shiftadd (const char *k, int keylen);

extern unsigned int lealea_lealea (const char *k, int keylen);

extern unsigned int shiftadd_imul (const char *k, int keylen);


int main(int argc, char **argv)
{
	int len = strlen(key);// - rand() % 10;
	unsigned long res = 0;
	struct timeval before, after;
	double elapsed;
	int		count = 100000; //+ rand() % 10;

	// at least one mult. is a single lea

	gettimeofday(&before, NULL);
	for (int i=0; i<count; i++)
		res += lea_lea(key, len);
	//printf("%lu", res);
	gettimeofday(&after, NULL);
	elapsed = after.tv_sec - before.tv_sec;
	elapsed += (after.tv_usec - before.tv_usec)/1000000.0;
	printf("%20s %.3fs\n", "lea, lea", elapsed);

	gettimeofday(&before, NULL);
	for (int i=0; i<count; i++)
		res += lea_leaadd(key, len);
	//printf("%lu", res);
	gettimeofday(&after, NULL);
	elapsed = after.tv_sec - before.tv_sec;
	elapsed += (after.tv_usec - before.tv_usec)/1000000.0;
	printf("%20s %.3fs\n", "lea, lea+add", elapsed);

	gettimeofday(&before, NULL);
	for (int i=0; i<100000; i++)
		res += lea_shiftadd(key, len);
	//printf("%lu", res);
	gettimeofday(&after, NULL);
	elapsed = after.tv_sec - before.tv_sec;
	elapsed += (after.tv_usec - before.tv_usec)/1000000.0;
	printf("%20s %.3fs\n", "lea, shift+add", elapsed);

	// none are a single lea

	gettimeofday(&before, NULL);
	for (int i=0; i<100000; i++)
		res += leaadd_shiftadd(key, len);
	//printf("%lu", res);
	gettimeofday(&after, NULL);
	elapsed = after.tv_sec - before.tv_sec;
	elapsed += (after.tv_usec - before.tv_usec)/1000000.0;
	printf("%20s %.3fs\n", "lea+add, shift+add", elapsed);

	gettimeofday(&before, NULL);
	for (int i=0; i<100000; i++)
		res += shiftadd_shiftadd(key, len);
	//printf("%lu", res);
	gettimeofday(&after, NULL);
	elapsed = after.tv_sec - before.tv_sec;
	elapsed += (after.tv_usec - before.tv_usec)/1000000.0;
	printf("%20s %.3fs\n", "shift+add, shift+add", elapsed);

	// 2 leas each
	gettimeofday(&before, NULL);
	for (int i=0; i<100000; i++)
		res += lealea_lealea(key, len);
	//printf("%lu", res);
	gettimeofday(&after, NULL);
	elapsed = after.tv_sec - before.tv_sec;
	elapsed += (after.tv_usec - before.tv_usec)/1000000.0;
	printf("%20s %.3fs\n", "2 leas, 2 leas", elapsed);

	// one imul
	gettimeofday(&before, NULL);
	for (int i=0; i<100000; i++)
		res += shiftadd_imul(key, len);
	//printf("%lu", res);
	gettimeofday(&after, NULL);
	elapsed = after.tv_sec - before.tv_sec;
	elapsed += (after.tv_usec - before.tv_usec)/1000000.0;
	printf("%20s %.3fs\n", "shift+add, imul", elapsed);

}
