# This file is part of libFirm.
# Copyright (C) 2018 Christoph Mallon.

$arch = "riscv";

my $mode_gp = "mode_Iu";

%reg_classes = (
	gp => {
		mode => $mode_gp,
		registers => [
			{ name => "zero", encoding =>  0 },
			{ name => "ra",   encoding =>  1 },
			{ name => "sp",   encoding =>  2 },
			{ name => "gp",   encoding =>  3 },
			{ name => "tp",   encoding =>  4 },
			{ name => "t0",   encoding =>  5 },
			{ name => "t1",   encoding =>  6 },
			{ name => "t2",   encoding =>  7 },
			{ name => "s0",   encoding =>  8 },
			{ name => "s1",   encoding =>  9 },
			{ name => "a0",   encoding => 10 },
			{ name => "a1",   encoding => 11 },
			{ name => "a2",   encoding => 12 },
			{ name => "a3",   encoding => 13 },
			{ name => "a4",   encoding => 14 },
			{ name => "a5",   encoding => 15 },
			{ name => "a6",   encoding => 16 },
			{ name => "a7",   encoding => 17 },
			{ name => "s2",   encoding => 18 },
			{ name => "s3",   encoding => 19 },
			{ name => "s4",   encoding => 20 },
			{ name => "s5",   encoding => 21 },
			{ name => "s6",   encoding => 22 },
			{ name => "s7",   encoding => 23 },
			{ name => "s8",   encoding => 24 },
			{ name => "s9",   encoding => 25 },
			{ name => "s10",  encoding => 26 },
			{ name => "s11",  encoding => 27 },
			{ name => "t3",   encoding => 28 },
			{ name => "t4",   encoding => 29 },
			{ name => "t5",   encoding => 30 },
			{ name => "t6",   encoding => 31 },
		]
	},
);

%init_attr = (
	riscv_attr_t => "",
	riscv_cond_attr_t =>
		"attr->cond = cond;",
	riscv_immediate_attr_t =>
		"attr->ent = ent;\n".
		"\tattr->val = val;",
	riscv_switch_attr_t =>
		"be_switch_attr_init(res, &attr->swtch, table, table_entity);",
);

my $binOp = {
	irn_flags => [ "rematerializable" ],
	in_reqs   => [ "cls-gp", "cls-gp" ],
	out_reqs  => [ "cls-gp" ],
	ins       => [ "left", "right" ],
	outs      => [ "res" ],
	emit      => "{name}\t%D0, %S0, %S1",
};

my $callOp = {
  state     => "exc_pinned",
  in_reqs   => "...",
  out_reqs  => "...",
  ins       => [ "mem", "stack", "first_argument" ],
  outs      => [ "M",   "stack", "first_result" ],
};

my $immediateOp = {
	irn_flags => [ "rematerializable" ],
	in_reqs   => [ "cls-gp" ],
	out_reqs  => [ "cls-gp" ],
	ins       => [ "left" ],
	outs      => [ "res" ],
	attr_type => "riscv_immediate_attr_t",
	attr      => "ir_entity *const ent, int32_t const val",
	emit      => "{name}\t%D0, %S0, %I",
};

my $loadOp = {
	state     => "exc_pinned",
	in_reqs   => [ "mem", "cls-gp" ],
	out_reqs  => [ "mem", "cls-gp" ],
	ins       => [ "mem", "base" ],
	outs      => [ "M", "res" ],
	attr_type => "riscv_immediate_attr_t",
	attr      => "ir_entity *const ent, int32_t const val",
	emit      => "{name}\t%D1, %A",
};

my $storeOp = {
	state     => "exc_pinned",
	in_reqs   => [ "mem", "cls-gp", "cls-gp" ],
	out_reqs  => [ "mem" ],
	ins       => [ "mem", "base", "value" ],
	outs      => [ "M" ],
	attr_type => "riscv_immediate_attr_t",
	attr      => "ir_entity *const ent, int32_t const val",
	emit      => "{name}\t%S2, %A",
};

%nodes = (

add => { template => $binOp },

addi => { template => $immediateOp },

and => { template => $binOp },

andi => { template => $immediateOp },

bcc => {
	state     => "pinned",
	op_flags  => [ "cfopcode", "forking" ],
	in_reqs   => [ "cls-gp", "cls-gp" ],
	ins       => [ "left", "right" ],
	out_reqs  => [ "exec", "exec" ],
	outs      => [ "false", "true" ],
	attr_type => "riscv_cond_attr_t",
	attr      => "riscv_cond_t const cond",
},

div => { template => $binOp, },

divu => { template => $binOp, },

ijmp => {
	state    => "pinned",
	op_flags => [ "cfopcode", "unknown_jump" ],
	in_reqs  => [ "cls-gp" ],
	out_reqs => [ "exec" ],
	emit     => "jr\t%S0",
},

j => {
	state     => "pinned",
	irn_flags => [ "simple_jump", "fallthrough" ],
	op_flags  => [ "cfopcode" ],
	out_reqs  => [ "exec" ],
},

jal => {
	template  => $callOp,
	attr_type => "riscv_immediate_attr_t",
	attr      => "ir_entity *const ent, int32_t const val",
	emit      => "jal\t%J",
},

jalr => {
	template => $callOp,
	emit     => "jalr\t%S2",
},

lb => { template => $loadOp },

lbu => { template => $loadOp },

lh => { template => $loadOp },

lhu => { template => $loadOp },

lui => {
	template  => $immediateOp,
	in_reqs   => [],
	ins       => [],
	emit      => "lui\t%D0, %H",
},

lw => { template => $loadOp },

mul => { template => $binOp, },

mulh => { template => $binOp, },

mulhu => { template => $binOp, },

or => { template => $binOp },

ori => { template => $immediateOp },

rem => { template => $binOp, },

remu => { template => $binOp, },

ret => {
	state    => "pinned",
	op_flags => [ "cfopcode" ],
	in_reqs  => "...",
	out_reqs => [ "exec" ],
	ins      => [ "mem", "stack", "addr", "first_result" ],
	emit     => "ret",
},

sb => { template => $storeOp },

sh => { template => $storeOp },

sll => { template => $binOp },

slli => { template => $immediateOp },

slt => { template => $binOp },

sltiu => { template => $immediateOp },

sltu => { template => $binOp },

sra => { template => $binOp },

srai => { template => $immediateOp },

srl => { template => $binOp },

srli => { template => $immediateOp },

sub => { template => $binOp },

sw => { template => $storeOp },

switch => {
	op_flags  => [ "cfopcode", "forking" ],
	state     => "pinned",
	in_reqs   => [ "cls-gp" ],
	out_reqs  => "...",
	attr_type => "riscv_switch_attr_t",
	attr      => "const ir_switch_table *table, ir_entity *table_entity",
},

xor => { template => $binOp },

xori => { template => $immediateOp },

FrameAddr => {
	op_flags  => [ "constlike" ],
	irn_flags => [ "rematerializable" ],
	attr      => "ir_entity *ent, int32_t val",
	in_reqs   => [ "cls-gp" ],
	out_reqs  => [ "cls-gp" ],
	ins       => [ "base" ],
	attr_type => "riscv_immediate_attr_t",
},

SubSP => {
	in_reqs => [ "mem", "sp", "cls-gp" ],
	ins     => [ "mem", "stack", "size" ],
	out_reqs => [ "sp:I", "cls-gp", "mem" ],
	outs     => [ "stack", "addr", "M" ],
},

SubSPimm => {
	in_reqs => [ "mem", "sp" ],
	ins      => [ "mem", "stack" ],
	out_reqs => [ "sp:I", "cls-gp", "mem" ],
	outs     => [ "stack", "addr", "M" ],
	attr_type => "riscv_immediate_attr_t",
	attr    => "ir_entity *ent, int32_t val",
},

);
