Files
armorpaint/base/sources/libs/kong/transformer.c
T
luboslenco bfc471eb34 Update kong
2025-06-04 20:38:42 +02:00

331 lines
9.7 KiB
C

#include "transformer.h"
#include "compiler.h"
#include "functions.h"
#include "types.h"
#include <assert.h>
#include <string.h>
opcodes new_code;
static void copy_opcode(opcode *o) {
uint8_t *new_data = &new_code.o[new_code.size];
assert(new_code.size + o->size < OPCODES_SIZE);
memcpy(new_data, o, o->size);
new_code.size += o->size;
}
void transform(uint32_t flags) {
for (function_id i = 0; get_function(i) != NULL; ++i) {
function *f = get_function(i);
if (f->block == NULL) {
continue;
}
uint8_t *data = f->code.o;
size_t size = f->code.size;
new_code.size = 0;
size_t index = 0;
while (index < size) {
opcode *o = (opcode *)&data[index];
switch (o->type) {
case OPCODE_STORE_ACCESS_LIST: {
access a = o->op_store_access_list.access_list[o->op_store_access_list.access_list_size - 1];
if ((flags & TRANSFORM_FLAG_ONE_COMPONENT_SWIZZLE) != 0 && a.kind == ACCESS_SWIZZLE && a.access_swizzle.swizzle.size > 1) {
assert(is_vector(o->op_store_access_list.from.type.type));
type_id from_base_type = vector_base_type(o->op_store_access_list.from.type.type);
type_ref from_base_type_ref;
init_type_ref(&from_base_type_ref, NO_NAME);
from_base_type_ref.type = from_base_type;
for (uint32_t swizzle_index = 0; swizzle_index < a.access_swizzle.swizzle.size; ++swizzle_index) {
variable from = allocate_variable(from_base_type_ref, o->op_store_access_list.from.kind);
opcode from_opcode = {
.type = OPCODE_LOAD_ACCESS_LIST,
.op_load_access_list =
{
.from = o->op_store_access_list.from,
.to = from,
.access_list_size = 1,
.access_list = {{
.type = from_base_type,
.kind = ACCESS_SWIZZLE,
.access_swizzle =
{
.swizzle =
{
.size = 1,
.indices = {swizzle_index},
},
},
}},
},
};
from_opcode.size = OP_SIZE(from_opcode, op_load_access_list);
copy_opcode(&from_opcode);
opcode new_opcode = *o;
new_opcode.op_store_access_list.from = from;
access *new_access = &new_opcode.op_store_access_list.access_list[new_opcode.op_store_access_list.access_list_size - 1];
new_access->access_swizzle.swizzle.size = 1;
new_access->access_swizzle.swizzle.indices[0] = a.access_swizzle.swizzle.indices[swizzle_index];
new_access->type = from_base_type;
copy_opcode(&new_opcode);
}
}
else {
copy_opcode(o);
}
break;
}
case OPCODE_LOAD_ACCESS_LIST: {
access a = o->op_load_access_list.access_list[o->op_load_access_list.access_list_size - 1];
if ((flags & TRANSFORM_FLAG_ONE_COMPONENT_SWIZZLE) != 0 && a.kind == ACCESS_SWIZZLE && a.access_swizzle.swizzle.size > 1) {
assert(is_vector(o->op_load_access_list.to.type.type));
type_id to_type = vector_base_type(o->op_load_access_list.to.type.type);
type_ref t;
init_type_ref(&t, NO_NAME);
t.type = to_type;
variable to[4];
for (uint32_t swizzle_index = 0; swizzle_index < a.access_swizzle.swizzle.size; ++swizzle_index) {
to[swizzle_index] = allocate_variable(t, o->op_load_access_list.to.kind);
opcode new_opcode = *o;
new_opcode.op_load_access_list.to = to[swizzle_index];
access *new_access = &new_opcode.op_load_access_list.access_list[new_opcode.op_load_access_list.access_list_size - 1];
new_access->access_swizzle.swizzle.size = 1;
new_access->access_swizzle.swizzle.indices[0] = a.access_swizzle.swizzle.indices[swizzle_index];
new_access->type = to_type;
copy_opcode(&new_opcode);
}
opcode constructor_call = {
.type = OPCODE_CALL,
.op_call =
{
.func = get_type(o->op_load_access_list.to.type.type)->name,
.parameters = {to[0], to[1], to[2], to[3]},
.parameters_size = a.access_swizzle.swizzle.size,
.var = o->op_load_access_list.to,
},
};
constructor_call.size = OP_SIZE(constructor_call, op_call);
copy_opcode(&constructor_call);
}
else {
copy_opcode(o);
}
break;
}
case OPCODE_ADD:
case OPCODE_SUB:
case OPCODE_MULTIPLY:
case OPCODE_DIVIDE: {
type_id left_type = o->op_binary.left.type.type;
type_id right_type = o->op_binary.right.type.type;
if (is_matrix(left_type) || is_matrix(right_type)) {
copy_opcode(o);
break;
}
uint32_t left_size = vector_size(left_type);
uint32_t right_size = vector_size(right_type);
if ((flags & TRANSFORM_FLAG_BINARY_UNIFY_LENGTH) != 0 && left_size != right_size) {
if (left_size < right_size) {
variable last;
if (is_vector(left_type)) {
type_ref t;
init_type_ref(&t, NO_NAME);
t.type = vector_base_type(left_type);
last = allocate_variable(t, o->op_binary.left.kind);
opcode load_call = {
.type = OPCODE_LOAD_ACCESS_LIST,
.op_load_access_list =
{
.from = o->op_binary.left,
.to = last,
.access_list =
{
{
.kind = ACCESS_SWIZZLE,
.type = t.type,
.access_swizzle =
{
.swizzle =
{
.indices = {left_size - 1},
.size = 1,
},
},
},
},
.access_list_size = 1,
},
};
load_call.size = OP_SIZE(load_call, op_load_access_list);
copy_opcode(&load_call);
}
else {
last = o->op_binary.left;
}
variable vec;
{
type_ref t;
init_type_ref(&t, NO_NAME);
t.type = vector_to_size(left_type, right_size);
vec = allocate_variable(t, VARIABLE_INTERNAL);
opcode constructor_call = {
.type = OPCODE_CALL,
.op_call =
{
.func = get_type(right_type)->name,
.parameters_size = right_size,
.var = vec,
},
};
constructor_call.size = OP_SIZE(constructor_call, op_call);
constructor_call.op_call.parameters[0] = o->op_binary.left;
for (uint32_t index = left_size; index < right_size; ++index) {
constructor_call.op_call.parameters[index] = last;
}
copy_opcode(&constructor_call);
}
{
opcode bin = *o;
bin.op_binary.left = vec;
copy_opcode(&bin);
}
}
else {
variable last;
if (is_vector(right_type)) {
type_ref t;
init_type_ref(&t, NO_NAME);
t.type = vector_base_type(right_type);
last = allocate_variable(t, o->op_binary.right.kind);
opcode load_call = {
.type = OPCODE_LOAD_ACCESS_LIST,
.op_load_access_list =
{
.from = o->op_binary.right,
.to = last,
.access_list =
{
{
.kind = ACCESS_SWIZZLE,
.type = t.type,
.access_swizzle =
{
.swizzle =
{
.indices = {right_size - 1},
.size = 1,
},
},
},
},
.access_list_size = 1,
},
};
load_call.size = OP_SIZE(load_call, op_load_access_list);
copy_opcode(&load_call);
}
else {
last = o->op_binary.right;
}
variable vec;
{
type_ref t;
init_type_ref(&t, NO_NAME);
t.type = vector_to_size(left_type, left_size);
vec = allocate_variable(t, VARIABLE_INTERNAL);
opcode constructor_call = {
.type = OPCODE_CALL,
.op_call =
{
.func = get_type(left_type)->name,
.parameters_size = left_size,
.var = vec,
},
};
constructor_call.size = OP_SIZE(constructor_call, op_call);
constructor_call.op_call.parameters[0] = o->op_binary.right;
for (uint32_t index = right_size; index < left_size; ++index) {
constructor_call.op_call.parameters[index] = last;
}
copy_opcode(&constructor_call);
}
{
opcode bin = *o;
bin.op_binary.right = vec;
copy_opcode(&bin);
}
}
}
else {
copy_opcode(o);
}
break;
}
default:
copy_opcode(o);
break;
}
index += o->size;
}
f->code = new_code;
}
}