The architecture definition rules for a CPU are placed into the files jit-rules-ARCH.h and jit-rules-ARCH.c.  You should add both of these files to Makefile.am in libjit/jit.

You will also need to edit jit-rules.h in two places.  First, place detection logic at the top of the file to detect your platform and define JIT_BACKEND_ARCH to 1.  Further down the file, you should add the following two lines to the include file logic:

     #elif defined(JIT_BACKEND_ARCH)
     #include "jit-rules-ARCH.h"

Defining the registers
----------------------

Every rule header file needs to define the macro JIT_REG_INFO to an array of values that represents the properties of the CPU's registers.  The _jit_reg_info array is populated with these values.  JIT_NUM_REGS defines the number of elements in the array.  Each element in the array has the following members:

name
     The name of the register.  This is used for debugging purposes.

cpu_reg
     The raw CPU register number.  Registers in libjit are referred to by their pseudo register numbers, corresponding to their index within JIT_REG_INFO.  However, these pseudo register numbers may not necessarily correspond to the register numbers used by the actual CPU.  This field provides a mapping.

other_reg
     The second pseudo register in a 64-bit register pair, or -1 if the current register cannot be used as the first pseudo register in a 64-bit register pair.  This field only has meaning on 32-bit platforms, and should always be set to -1 on 64-bit platforms.

flags
     Flag bits that describe the pseudo register's properties.

The following flags may be present:

JIT_REG_WORD
     This register can hold an integer word value.

JIT_REG_LONG
     This register can hold a 64-bit long value without needing a second register.  Normally only used on 64-bit platforms.

JIT_REG_FLOAT32
     This register can hold a 32-bit floating-point value.

JIT_REG_FLOAT64
     This register can hold a 64-bit floating-point value.

JIT_REG_NFLOAT
     This register can hold a native floating-point value.

JIT_REG_FRAME
     This register holds the frame pointer.  You will almost always supply JIT_REG_FIXED for this register.

JIT_REG_STACK_PTR
     This register holds the stack pointer.  You will almost always supply JIT_REG_FIXED for this register.

JIT_REG_FIXED
     This register has a fixed meaning and cannot be used for general allocation.

JIT_REG_CALL_USED
     This register will be destroyed by a function call.

JIT_REG_IN_STACK
     This register is in a stack-like arrangement.

JIT_REG_GLOBAL
     This register is a candidate for global register allocation.

A CPU may have some registers arranged into a stack.  In this case operations can typically only occur at the top of the stack, and may automatically pop values as a side-effect of the operation. An example of such architecture is x87 floating point unit.  Such CPU requires three additional macros.

JIT_REG_STACK
     If defined, this indicates the presence of the register stack.

JIT_REG_STACK_START
     The index of the first register in the JIT_REG_INFO array that is used in a stack-like arrangement.

JIT_REG_STACK_END
     The index of the last register in the JIT_REG_INFO array that is used in a stack-like arrangement.

The entries in the JIT_REG_INFO array from JIT_REG_STACK_START up to JIT_REG_STACK_END must also have the JIT_REG_IN_STACK flag set.

Other architecture macros
-------------------------

The rule file may also have definitions of the following macros:

JIT_NUM_GLOBAL_REGS
     The number of registers that are used for global register allocation. Set to zero if global register allocation should not be used.

JIT_ALWAYS_REG_REG
     Define this to 1 if arithmetic operations must always be performed on registers.  Define this to 0 if register/memory and memory/register operations are possible.

JIT_PROLOG_SIZE
     If defined, this indicates the maximum size of the function prolog.

JIT_FUNCTION_ALIGNMENT
     This value indicates the alignment required for the start of a function. e.g. define this to 32 if functions should be aligned on a 32-byte boundary.

JIT_ALIGN_OVERRIDES
     Define this to 1 if the platform allows reads and writes on any byte boundary.  Define to 0 if only properly-aligned memory accesses are allowed.  Normally only defined to 1 under x86.

jit_extra_gen_state
jit_extra_gen_init
jit_extra_gen_cleanup
     The jit_extra_gen_state macro can be supplied to add extra fields to the struct jit_gencode type in jit-rules.h, for extra CPU-specific code generation state information.

     The jit_extra_gen_init macro initializes this extra information, and the jit_extra_gen_cleanup macro cleans it up when code generation is complete.

Architecture-dependent functions
--------------------------------

 -- Function: void _jit_init_backend (void)
     Initialize the backend.  This is normally used to configure registers that may not appear on all CPU's in a given family.  For example, only some ARM cores have floating-point registers.

 -- Function: void _jit_gen_get_elf_info (jit_elf_info_t *INFO)
     Get the ELF machine and ABI type information for this platform. The machine field should be set to one of the EM_* values in jit-elf-defs.h.  The abi field should be set to one of the ELFOSABI_* values in jit-elf-defs.h (ELFOSABI_SYSV will normally suffice if you are unsure). The abi_version field should be set to the ABI version, which is usually zero.

 -- Function: int _jit_create_entry_insns (jit_function_t FUNC)
     Create instructions in the entry block to initialize the registers and frame offsets that contain the parameters. Returns zero if out of memory.

     This function is called when a builder is initialized.  It should scan the signature and decide which register or frame position contains each of the parameters and then call either jit_insn_incoming_reg or jit_insn_incoming_frame_posn to notify libjit of the location.

 -- Function: int _jit_create_call_setup_insns (jit_function_t FUNC, jit_type_t SIGNATURE, jit_value_t *ARGS, unsigned int NUM_ARGS, int IS_NESTED, int NESTED_LEVEL, jit_value_t *STRUCT_RETURN, int FLAGS)
     Create instructions within FUNC necessary to set up for a function call to a function with the specified SIGNATURE. Use jit_insn_push to push values onto the system stack, or jit_insn_outgoing_reg to copy values into call registers.

     If IS_NESTED is non-zero, then it indicates that we are calling a nested function within the current function's nested relationship tree. The NESTED_LEVEL value will be -1 to call a child, zero to call a sibling of FUNC, 1 to call a sibling of the parent, 2 to call a sibling of the grandparent, etc.  The jit_insn_setup_for_nested instruction should be used to create the nested function setup code.

     If the function returns a structure by pointer, then STRUCT_RETURN must be set to a new local variable that will contain the returned structure.  Otherwise it should be set to NULL.

 -- Function: int _jit_setup_indirect_pointer (jit_function_t FUNC, jit_value_t VALUE)
     Place the indirect function pointer VALUE into a suitable register or stack location for a subsequent indirect call.

 -- Function: int _jit_create_call_return_insns (jit_function_t FUNC, jit_type_t SIGNATURE, jit_value_t *ARGS, unsigned int NUM_ARGS, jit_value_t RETURN_VALUE, int IS_NESTED)
     Create instructions within FUNC to clean up after a function call and to place the function's result into RETURN_VALUE. This should use jit_insn_pop_stack to pop values off the system stack and jit_insn_return_reg to tell libjit which register contains the return value.  In the case of a void function, RETURN_VALUE will be NULL.

     Note: the argument values are passed again because it may not be possible to determine how many bytes to pop from the stack from the SIGNATURE alone; especially if the called function is vararg.

 -- Function: int _jit_opcode_is_supported (int OPCODE)
     Not all CPU's support all arithmetic, conversion, bitwise, or comparison operators natively.  For example, most ARM platforms need to call out to helper functions to perform floating-point.

     If this function returns zero, then jit-insn.c will output a call to an intrinsic function that is equivalent to the desired opcode. This is how you tell libjit that you cannot handle the opcode natively.

     This function can also help you develop your back end incrementally. Initially, you can report that only integer operations are supported, and then once you have them working you can move on to the floating point operations.

 -- Function: void * _jit_gen_prolog (jit_gencode_t GEN, jit_function_t FUNC, void *BUF)
     Generate the prolog for a function into a previously-prepared buffer area of JIT_PROLOG_SIZE bytes in size.  Returns the start of the prolog, which may be different than BUF.

     This function is called at the end of the code generation process, not the beginning.  At this point, it is known which callee save registers must be preserved, allowing the back end to output the most compact prolog possible.

 -- Function: void _jit_gen_epilog (jit_gencode_t GEN, jit_function_t FUNC)
     Generate a function epilog, restoring the registers that were saved on entry to the function, and then returning.

     Only one epilog is generated per function.  Functions with multiple jit_insn_return instructions will all jump to the common epilog. This is needed because the code generator may not know which callee save registers need to be restored by the epilog until the full function has been processed.

 -- Function: void * _jit_gen_redirector (jit_gencode_t GEN, jit_function_t FUNC)
     Generate code for a redirector, which makes an indirect jump to the contents of FUNC->entry_point.  Redirectors are used on recompilable functions in place of the regular entry point.  This allows libjit to redirect existing calls to the new version after recompilation.

 -- Function: void _jit_gen_spill_reg (jit_gencode_t GEN, int REG, int OTHER_REG, jit_value_t VALUE)
     Generate instructions to spill a pseudo register to the local variable frame.  If OTHER_REG is not -1, then it indicates the second register in a 64-bit register pair.

     This function will typically call _jit_gen_fix_value to fix the value's frame position, and will then generate the appropriate spill instructions.

 -- Function: void _jit_gen_free_reg (jit_gencode_t GEN, int REG, int OTHER_REG, int VALUE_USED)
     Generate instructions to free a register without spilling its value. This is called when a register's contents become invalid, or its value is no longer required.  If VALUE_USED is set to a non-zero value, then it indicates that the register's value was just used. Otherwise, there is a value in the register but it was never used.

     On most platforms, this function won't need to do anything to free the register.  But some do need to take explicit action.  For example, x86 needs an explicit instruction to remove a floating-point value from the FPU's stack if its value has not been used yet.

 -- Function: void _jit_gen_load_value (jit_gencode_t GEN, int REG, int OTHER_REG, jit_value_t VALUE)
     Generate instructions to load a value into a register.  The value will either be a constant or a slot in the frame.  You should fix frame slots with _jit_gen_fix_value.

 -- Function: void _jit_gen_spill_global (jit_gencode_t GEN, int REG, jit_value_t VALUE)
     Spill the contents of VALUE from its corresponding global register. This is used in rare cases when a machine instruction requires its operand to be in the specific register that happens to be global. In such cases the register is spilled just before the instruction and loaded back immediately after it.

 -- Function: void _jit_gen_load_global (jit_gencode_t GEN, int REG, jit_value_t VALUE)
     Load the contents of VALUE into its corresponding global register. This is used at the head of a function to pull parameters out of stack slots into their global register copies.

 -- Function: void _jit_gen_exch_top (jit_gencode_t GEN, int REG)
     Generate instructions to exchange the contents of the top stack register with a stack register specified by the REG argument.

     It needs to be implemented only by backends that support stack registers.

 -- Function: void _jit_gen_move_top (jit_gencode_t GEN, int REG)
     Generate instructions to copy the contents of the top stack register into a stack register specified by the reg argument and pop the top register after this. If reg is equal to the top register then the top register is just popped without copying it.

     It needs to be implemented only by backends that support stack registers.

 -- Function: void _jit_gen_spill_top (jit_gencode_t GEN, int REG, jit_value_t VALUE, int POP)
     Generate instructions to spill the top stack register to the local variable frame. The POP argument indicates if the top register is popped from the stack.

     It needs to be implemented only by backends that support stack registers.

 -- Function: void _jit_gen_fix_value (jit_value_t VALUE)
     Fix the position of a value within the local variable frame. If it doesn't already have a position, then assign one for it.

 -- Function: void _jit_gen_insn (jit_gencode_t GEN, jit_function_t FUNC, jit_block_t BLOCK, jit_insn_t INSN)
     Generate native code for the specified INSN.  This function should call the appropriate register allocation routines, output the instruction, and then arrange for the result to be placed in an appropriate register or memory destination.

 -- Function: void _jit_gen_start_block (jit_gencode_t GEN, jit_block_t BLOCK)
     Called to notify the back end that the start of a basic block has been reached.

 -- Function: void _jit_gen_end_block (jit_gencode_t GEN)
     Called to notify the back end that the end of a basic block has been reached.

 -- Function: int _jit_gen_is_global_candidate (jit_type_t TYPE)
     Determine if TYPE is a candidate for allocation within global registers.

 -- Function: int _jit_reg_get_pair (jit_type_t TYPE, int REG)
     Determine if a type requires a register pair. If so then for the specified register REG return the other register of the corresponding pair. Return -1 if no pair is required.

     This function is used only for native 32-bit backends.