<commit_before>/*
 * Copyright (c) 2018 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "arm_int_dist.h"
#include "arm_reg_alloc.h"

static void prv_dist_handle_op2(subtilis_dist_data_t *ud,
				subtilis_arm_op2_t *op2, subtilis_error_t *err)
{
	if (op2->type == SUBTILIS_ARM_OP2_REG) {
		if (op2->op.reg == ud->reg_num) {
			subtilis_error_set_walker_failed(err);
			return;
		}
	} else if (op2->type == SUBTILIS_ARM_OP2_SHIFTED) {
		if (op2->op.shift.reg == ud->reg_num) {
			subtilis_error_set_walker_failed(err);
			return;
		}

		if (op2->op.shift.shift_reg &&
		    op2->op.shift.shift.reg == ud->reg_num) {
			subtilis_error_set_walker_failed(err);
			return;
		}
	}
	ud->last_used++;
}

static void prv_dist_mov_instr(void *user_data, subtilis_arm_op_t *op,
			       subtilis_arm_instr_type_t type,
			       subtilis_arm_data_instr_t *instr,
			       subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	/*
	 * Special case for when source = destination.  This is a NOP
	 * which can be currently generated by an interaction between the
	 * code generator and the register allocator.
	 */

	if ((type == SUBTILIS_ARM_INSTR_MOV) &&
	    (instr->op2.type == SUBTILIS_ARM_OP2_REG) &&
	    (instr->dest == instr->op2.op.reg)) {
		ud->last_used++;
		return;
	}

	prv_dist_handle_op2(ud, &instr->op2, err);
	if (err->type != SUBTILIS_ERROR_OK)
		return;

	if (instr->dest == ud->reg_num) {
		ud->last_used = -1;
		subtilis_error_set_walker_failed(err);
		return;
	}
}

static void prv_dist_data_instr(void *user_data, subtilis_arm_op_t *op,
				subtilis_arm_instr_type_t type,
				subtilis_arm_data_instr_t *instr,
				subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	if (instr->op1 == ud->reg_num) {
		subtilis_error_set_walker_failed(err);
		return;
	}

	prv_dist_handle_op2(ud, &instr->op2, err);
	if (err->type != SUBTILIS_ERROR_OK)
		return;

	if (instr->dest == ud->reg_num) {
		ud->last_used = -1;
		subtilis_error_set_walker_failed(err);
		return;
	}
}

static void prv_dist_mul_instr(void *user_data, subtilis_arm_op_t *op,
			       subtilis_arm_instr_type_t type,
			       subtilis_arm_mul_instr_t *instr,
			       subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	if ((instr->rm == ud->reg_num) || (instr->rs == ud->reg_num)) {
		subtilis_error_set_walker_failed(err);
		return;
	}

	if (instr->dest == ud->reg_num) {
		ud->last_used = -1;
		subtilis_error_set_walker_failed(err);
		return;
	}

	ud->last_used++;
}

static void prv_dist_stran_instr(void *user_data, subtilis_arm_op_t *op,
				 subtilis_arm_instr_type_t type,
				 subtilis_arm_stran_instr_t *instr,
				 subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	if (type == SUBTILIS_ARM_INSTR_LDR) {
		if (instr->dest == ud->reg_num) {
			ud->last_used = -1;
			subtilis_error_set_walker_failed(err);
			return;
		}
	} else {
		if (instr->dest == ud->reg_num) {
			subtilis_error_set_walker_failed(err);
			return;
		}
	}

	if (instr->base == ud->reg_num) {
		subtilis_error_set_walker_failed(err);
		return;
	}

	prv_dist_handle_op2(ud, &instr->offset, err);
}

static void prv_dist_mtran_instr(void *user_data, subtilis_arm_op_t *op,
				 subtilis_arm_instr_type_t type,
				 subtilis_arm_mtran_instr_t *instr,
				 subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	/*
	 * TODO: Mtran can not currently be used in distance calculations
	 * as we can only represent a subset of the virtual registers
	 * in the instruction.  As we're only currently using it to implement
	 * a stack this is okay.  But long term we'll need to fix this if
	 * we want to use the instructions for general purpose use.
	 */

	ud->last_used++;
}

static void prv_dist_br_instr(void *user_data, subtilis_arm_op_t *op,
			      subtilis_arm_instr_type_t type,
			      subtilis_arm_br_instr_t *instr,
			      subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	ud->last_used++;
}

static void prv_dist_swi_instr(void *user_data, subtilis_arm_op_t *op,
			       subtilis_arm_instr_type_t type,
			       subtilis_arm_swi_instr_t *instr,
			       subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	if ((1 << ud->reg_num) & instr->reg_mask) {
		ud->last_used = -1;<commit_msg>Fix a bug in the register allocator<commit_after>/*
 * Copyright (c) 2018 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "arm_int_dist.h"
#include "arm_reg_alloc.h"

static void prv_dist_handle_op2(subtilis_dist_data_t *ud,
				subtilis_arm_op2_t *op2, subtilis_error_t *err)
{
	if (op2->type == SUBTILIS_ARM_OP2_REG) {
		if (op2->op.reg == ud->reg_num) {
			subtilis_error_set_walker_failed(err);
			return;
		}
	} else if (op2->type == SUBTILIS_ARM_OP2_SHIFTED) {
		if (op2->op.shift.reg == ud->reg_num) {
			subtilis_error_set_walker_failed(err);
			return;
		}

		if (op2->op.shift.shift_reg &&
		    op2->op.shift.shift.reg == ud->reg_num) {
			subtilis_error_set_walker_failed(err);
			return;
		}
	}
	ud->last_used++;
}

static void prv_dist_mov_instr(void *user_data, subtilis_arm_op_t *op,
			       subtilis_arm_instr_type_t type,
			       subtilis_arm_data_instr_t *instr,
			       subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	/*
	 * Special case for when source = destination.  This is a NOP
	 * which can be currently generated by an interaction between the
	 * code generator and the register allocator.
	 */

	if ((type == SUBTILIS_ARM_INSTR_MOV) &&
	    (instr->op2.type == SUBTILIS_ARM_OP2_REG) &&
	    (instr->dest == instr->op2.op.reg)) {
		ud->last_used++;
		return;
	}

	prv_dist_handle_op2(ud, &instr->op2, err);
	if (err->type != SUBTILIS_ERROR_OK)
		return;

	if (instr->dest == ud->reg_num) {
		ud->last_used = -1;
		subtilis_error_set_walker_failed(err);
		return;
	}
}

static void prv_dist_data_instr(void *user_data, subtilis_arm_op_t *op,
				subtilis_arm_instr_type_t type,
				subtilis_arm_data_instr_t *instr,
				subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	if (instr->op1 == ud->reg_num) {
		subtilis_error_set_walker_failed(err);
		return;
	}

	prv_dist_handle_op2(ud, &instr->op2, err);
	if (err->type != SUBTILIS_ERROR_OK)
		return;

	if (instr->dest == ud->reg_num) {
		ud->last_used = -1;
		subtilis_error_set_walker_failed(err);
		return;
	}
}

static void prv_dist_mul_instr(void *user_data, subtilis_arm_op_t *op,
			       subtilis_arm_instr_type_t type,
			       subtilis_arm_mul_instr_t *instr,
			       subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	if ((instr->rm == ud->reg_num) || (instr->rs == ud->reg_num)) {
		subtilis_error_set_walker_failed(err);
		return;
	}

	if (instr->dest == ud->reg_num) {
		ud->last_used = -1;
		subtilis_error_set_walker_failed(err);
		return;
	}

	ud->last_used++;
}

static void prv_dist_stran_instr(void *user_data, subtilis_arm_op_t *op,
				 subtilis_arm_instr_type_t type,
				 subtilis_arm_stran_instr_t *instr,
				 subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	if (type == SUBTILIS_ARM_INSTR_LDR) {
		if (instr->dest == ud->reg_num) {
			ud->last_used = -1;
			subtilis_error_set_walker_failed(err);
			return;
		}
	} else {
		if (instr->dest == ud->reg_num) {
			subtilis_error_set_walker_failed(err);
			return;
		}
	}

	if (instr->base == ud->reg_num) {
		subtilis_error_set_walker_failed(err);
		return;
	}

	prv_dist_handle_op2(ud, &instr->offset, err);
}

static void prv_dist_mtran_instr(void *user_data, subtilis_arm_op_t *op,
				 subtilis_arm_instr_type_t type,
				 subtilis_arm_mtran_instr_t *instr,
				 subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	/*
	 * TODO: Mtran can not currently be used in distance calculations
	 * as we can only represent a subset of the virtual registers
	 * in the instruction.  As we're only currently using it to implement
	 * a stack this is okay.  But long term we'll need to fix this if
	 * we want to use the instructions for general purpose use.
	 */

	ud->last_used++;
}

static void prv_dist_br_instr(void *user_data, subtilis_arm_op_t *op,
			      subtilis_arm_instr_type_t type,
			      subtilis_arm_br_instr_t *instr,
			      subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	ud->last_used++;
}

static void prv_dist_swi_instr(void *user_data, subtilis_arm_op_t *op,
			       subtilis_arm_instr_type_t type,
			       subtilis_arm_swi_instr_t *instr,
			       subtilis_error_t *err)
{
	subtilis_dist_data_t *ud = user_data;

	/* SWIs can only use the first 10 regs */

	if ((ud->reg_num < 10) && (1 << ud->reg_num) & instr->reg_mask) {
		ud->last_used = -1;
{'fraction_non_alphanumeric': 0.11040714582467802, 'fraction_numerical': 0.007478188616535106, 'mean_word_length': 3.8779128672745693, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 100, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6908521', 'n_tokens_mistral': 4079, 'n_tokens_neox': 3738, 'n_words': 805}