/**
 * vec - a tiny SIMD vector library in C99
 * 
 * Copyright (c) 2024-2025 Paper
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
**/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum {
	OP_SPLAT,
	OP_LOAD_ALIGNED,
	OP_LOAD,
	OP_STORE_ALIGNED,
	OP_STORE,
	OP_ADD,
	OP_SUB,
	OP_MUL,
	OP_DIV,
	OP_MOD,
	OP_AVG,
	OP_AND,
	OP_OR,
	OP_XOR,
	OP_NOT,
	OP_CMPLT,
	OP_CMPEQ,
	OP_CMPGT,
	OP_CMPLE, /* these are after the other ones to make */
	OP_CMPGE, /* implementing them as simple as NOT(CMPLT|CMPGT) */
	OP_MIN,
	OP_MAX,
	OP_RSHIFT,
	OP_LRSHIFT,
	OP_LSHIFT,

	OP_FLOOR,
	OP_CEIL,
	OP_ROUND,
	OP_TRUNC,

	/* use this for array sizes and the like */
	OP_FINAL_,
};

enum {
	TYPE_INT,   /* signed int */
	TYPE_UINT,  /* unsigned int */
	TYPE_FLOAT, /* IEEE float */
};

struct op_info {
	const char *u;
	const char *l;

	/* print return type to stdout */
	void (*pret)(int op, int type, int bits, int size);

	/* print params type to stdout */
	void (*pparam)(int op, int type, int bits, int size);
};

struct strs {
	const char *l;
	const char *u;
};

extern struct strs type_str[];

struct op_info *gen_op_info(int op);

struct op_impl {
	/* return 1 if it's implemented for a specific set of
	 * inputs :)
	 *
	 * if this function is not implemented, and `pbody`
	 * is not NULL, then it is assumed that there are
	 * no restrictions on what type, bits, or size can
	 * be used. beware! */
	int (*check)(int op, int type, int bits, int size);

	/* prints any additional preprocessor checks needed
	 * should start with a conditional, usually && */
	void (*ppcheck)(int op, int type, int bits, int size);

	/* sherman?
	 * (this prints the actual body of the function...) */
	void (*pbody)(int op, int type, int bits, int size);
};

int gen(struct op_impl op_impl[OP_FINAL_], const char *name);

void gen_print_vtype(int type, int bits, int size);
void gen_print_stype(int type, int bits);
