
/*---------------------------------------------------------------*/
/*---                                                         ---*/
/*--- This file (host_arm_defs.c) is                          ---*/
/*--- Copyright (C) OpenWorks LLP.  All rights reserved.      ---*/
/*---                                                         ---*/
/*---------------------------------------------------------------*/

/*
   This file is part of LibVEX, a library for dynamic binary
   instrumentation and translation.

   Copyright (C) 2004-2009 OpenWorks LLP.  All rights reserved.

   This library is made available under a dual licensing scheme.

   If you link LibVEX against other code all of which is itself
   licensed under the GNU General Public License, version 2 dated June
   1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL
   v2, as appearing in the file LICENSE.GPL.  If the file LICENSE.GPL
   is missing, you can obtain a copy of the GPL v2 from the Free
   Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA
   02110-1301, USA.

   For any other uses of LibVEX, you must first obtain a commercial
   license from OpenWorks LLP.  Please contact info@open-works.co.uk
   for information about commercial licensing.

   This software is provided by OpenWorks LLP "as is" and any express
   or implied warranties, including, but not limited to, the implied
   warranties of merchantability and fitness for a particular purpose
   are disclaimed.  In no event shall OpenWorks LLP be liable for any
   direct, indirect, incidental, special, exemplary, or consequential
   damages (including, but not limited to, procurement of substitute
   goods or services; loss of use, data, or profits; or business
   interruption) however caused and on any theory of liability,
   whether in contract, strict liability, or tort (including
   negligence or otherwise) arising in any way out of the use of this
   software, even if advised of the possibility of such damage.

   Neither the names of the U.S. Department of Energy nor the
   University of California nor the names of its contributors may be
   used to endorse or promote products derived from this software
   without prior written permission.
*/

#include "libvex_basictypes.h"
#include "libvex.h"
#include "libvex_trc_values.h"

#include "main_util.h"
#include "host_generic_regs.h"
#include "host_arm_defs.h"



/* --------- Registers. --------- */

/* The usual HReg abstraction.
   There are 16 general purpose regs.
*/


/* --------- Registers. --------- */

void ppHRegARM ( HReg reg )  {
   Int r;
   static HChar* ireg32_names[16] 
     = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",
	 "r9", "r10", "r11", "r12", "r13", "r14", "r15" };

   /* Be generic for all virtual regs. */
   if (hregIsVirtual(reg)) {
      ppHReg(reg);
      return;
   }
   /* But specific for real regs. */
   switch (hregClass(reg)) {
      case HRcInt32:
         r = hregNumber(reg);
         vassert(r >= 0 && r < 16);
         vex_printf("%s", ireg32_names[r]);
         return;
      default:
         vpanic("ppHRegARM");
   }
}

HReg hregARM_R0 ( void ) { return mkHReg(0, HRcInt32, False); }
HReg hregARM_R1 ( void ) { return mkHReg(1, HRcInt32, False); }
HReg hregARM_R2 ( void ) { return mkHReg(2, HRcInt32, False); }
HReg hregARM_R3 ( void ) { return mkHReg(3, HRcInt32, False); }
HReg hregARM_R4 ( void ) { return mkHReg(4, HRcInt32, False); }
HReg hregARM_R5 ( void ) { return mkHReg(5, HRcInt32, False); }
HReg hregARM_R6 ( void ) { return mkHReg(6, HRcInt32, False); }
HReg hregARM_R7 ( void ) { return mkHReg(7, HRcInt32, False); }
HReg hregARM_R8 ( void ) { return mkHReg(8, HRcInt32, False); }
HReg hregARM_R9 ( void ) { return mkHReg(9, HRcInt32, False); }
HReg hregARM_R10 ( void ) { return mkHReg(10, HRcInt32, False); }
HReg hregARM_R11 ( void ) { return mkHReg(11, HRcInt32, False); }
HReg hregARM_R12 ( void ) { return mkHReg(12, HRcInt32, False); }
HReg hregARM_R13 ( void ) { return mkHReg(13, HRcInt32, False); }
HReg hregARM_R14 ( void ) { return mkHReg(14, HRcInt32, False); }
HReg hregARM_R15 ( void ) { return mkHReg(15, HRcInt32, False); }

void getAllocableRegs_ARM ( Int* nregs, HReg** arr ) {
   *nregs = 20;
   *arr = LibVEX_Alloc(*nregs * sizeof(HReg));
   (*arr)[0] = hregARM_R0();
   (*arr)[1] = hregARM_R1();
   (*arr)[2] = hregARM_R2();
   (*arr)[3] = hregARM_R3();
   (*arr)[4] = hregARM_R4();
   (*arr)[5] = hregARM_R5();
   (*arr)[6] = hregARM_R6();
   (*arr)[7] = hregARM_R7();
   (*arr)[8] = hregARM_R8();
   (*arr)[9] = hregARM_R9();
   (*arr)[10] = hregARM_R10();
   (*arr)[11] = hregARM_R11();
   (*arr)[12] = hregARM_R12();
   (*arr)[13] = hregARM_R13();
   (*arr)[14] = hregARM_R14();
   (*arr)[15] = hregARM_R15();
}



/* --------- Condition codes, ARM encoding. --------- */

HChar* showARMCondCode ( ARMCondCode cond ) {
   switch (cond) {
       case ARMccEQ:    return "eq";
       case ARMccNE:    return "ne";
       case ARMccHS:    return "hs";
       case ARMccLO:    return "lo";
       case ARMccMI:    return "mi";
       case ARMccPL:    return "pl";
       case ARMccVS:    return "vs";
       case ARMccVC:    return "vc";
       case ARMccHI:    return "hi";
       case ARMccLS:    return "ls";
       case ARMccGE:    return "ge";
       case ARMccLT:    return "lt";
       case ARMccGT:    return "gt";
       case ARMccLE:    return "le";
       case ARMccAL:    return "al"; // default
       case ARMccNV:    return "nv";
       default: vpanic("showARMCondCode");
   }
}




/* --------- ARMAMode1: memory address expressions. --------- */

ARMAMode1* ARMAMode1_I12A ( ARMImm12A imm ) {
    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
    am->tag = ARMam1_I12A;
    am->ARMam1.I12A.imm = imm;
    return am;
}
ARMAMode1* ARMAMode1_ShlI ( HReg Rm, ARMImm5 imm ) {
    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
    am->tag = ARMam1_ShlI;
    am->ARMam1.ShlI.Rm = Rm;
    am->ARMam1.ShlI.imm = imm;
    return am;
}
ARMAMode1* ARMAMode1_ShrI ( HReg Rm, ARMImm5 imm ) {
    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
    am->tag = ARMam1_ShrI;
    am->ARMam1.ShrI.Rm = Rm;
    am->ARMam1.ShrI.imm = imm;
    return am;
}
ARMAMode1* ARMAMode1_SarI ( HReg Rm, ARMImm5 imm ) {
    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
    am->tag = ARMam1_SarI;
    am->ARMam1.SarI.Rm = Rm;
    am->ARMam1.SarI.imm = imm;
    return am;
}
ARMAMode1* ARMAMode1_ShlR ( HReg Rm, HReg Rs ) {
    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
    am->tag = ARMam1_ShlR;
    am->ARMam1.ShlR.Rm = Rm;
    am->ARMam1.ShlR.Rs = Rs;
    return am;
}
ARMAMode1* ARMAMode1_ShrR ( HReg Rm, HReg Rs ) {
    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
    am->tag = ARMam1_ShrR;
    am->ARMam1.ShrR.Rm = Rm;
    am->ARMam1.ShrR.Rs = Rs;
    return am;
}
ARMAMode1* ARMAMode1_SarR ( HReg Rm, HReg Rs ) {
    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
    am->tag = ARMam1_SarR;
    am->ARMam1.SarR.Rm = Rm;
    am->ARMam1.SarR.Rs = Rs;
    return am;
}

ARMAMode1* dopyARMAMode1 ( ARMAMode1* am ) {
   switch (am->tag) {
   case ARMam1_I12A:
       return ARMAMode1_I12A( am->ARMam1.I12A.imm );
   case ARMam1_ShlI:
       return ARMAMode1_ShlI( am->ARMam1.ShlI.Rm, am->ARMam1.ShlI.imm );
   case ARMam1_ShrI:
       return ARMAMode1_ShrI( am->ARMam1.ShrI.Rm, am->ARMam1.ShrI.imm );
   case ARMam1_SarI:
       return ARMAMode1_SarI( am->ARMam1.SarI.Rm, am->ARMam1.SarI.imm );
   case ARMam1_ShlR:
       return ARMAMode1_ShlR( am->ARMam1.ShlR.Rm, am->ARMam1.ShlR.Rs );
   case ARMam1_ShrR:
       return ARMAMode1_ShrR( am->ARMam1.ShrR.Rm, am->ARMam1.ShrR.Rs );
   case ARMam1_SarR:
       return ARMAMode1_SarR( am->ARMam1.SarR.Rm, am->ARMam1.SarR.Rs );
   default:
       vpanic("dopyARMAMode1");
   }
}

void ppARMAMode1 ( ARMAMode1* am ) {
   switch (am->tag) {
   case ARMam1_I12A:
   case ARMam1_ShlI:
   case ARMam1_ShrI:
   case ARMam1_SarI:
   case ARMam1_ShlR:
   case ARMam1_ShrR:
   case ARMam1_SarR:
       vex_printf("ppARMAMode1: Not implemented");
       break;
   default:
       vpanic("ppARMAMode1");
   }
}

/*
static void addRegUsage_ARMAMode1 ( HRegUsage* u, ARMAMode1* am ) {
static void mapRegs_ARMAMode1 ( HRegRemap* m, ARMAMode1* am ) {
*/


/* ------ ARMAMode1_I12A Helper function ------
  Given imm32, find immed_8, rotate_imm.
  ARM ARM A5-6: imm32 = immed_8 ROR (rotate_imm * 2)
*/
Bool mk_ARMImm12A ( UInt imm32, ARMImm12A* imm12a ) {
//    UInt imm32_orig = imm32;
    UInt shr=0, rot=0;
    imm12a->imm = 0;
    imm12a->rot = 0;
    
    // Easiest case: no shift needed
    if (imm32 > 0xFF) {
	// Next easiest: just a shift to the right needed
	while ((imm32 & 1) == 0) { imm32 = imm32 >> 1;  shr++; }
	rot = 32 - shr;

	if (imm32 > 0xFF) {
	    // Hardest: Need to rol (some minimum amount)
	    // valid byte could be split over first and last bytes...
	    
	    // ROL 7 (worst case for still valid imm32):
	    imm32 = (imm32 << 7) | (imm32 << (32-7));
	    // ShR (reverse rol) if went too far:
	    while ((imm32 & 1) == 0) { imm32 = imm32 >> 1; shr++; }
	    rot = 7 - shr;   // if valid imm32, shr < 7
	    
	    if (imm32 > 0xFF) {  // Can't represent this value
//		vex_printf("Error: Can't represent imm32: 0x%x", imm32_orig);
		return False;
	    }
	}
    }
    // Valid imm32 so far...

    if (rot & 1) {
	rot--;
	imm32 = imm32 << 1;
	if (imm32 > 0xFF) {
	    // Can't represent this value (can only shift even n)
//	    vex_printf("Error: Can't represent imm32: 0x%x\n", imm32_orig);
	    return False;
	}
    }

    imm12a->imm = imm32;
    imm12a->rot = rot / 2;
    
    vassert((imm12a->imm & 0xFF) == imm12a->imm);
    vassert((imm12a->rot & 0xF ) == imm12a->rot);
    return True;
}





/* --------- ARMAMode2: memory address expressions. --------- */

ARMAMode2* ARMAMode2_RI ( HReg Rn, ARMImm12 imm ) {
    ARMAMode2* am = LibVEX_Alloc(sizeof(ARMAMode2));
    am->tag = ARMam2_RI;
    am->ARMam2.RI.Rn = Rn;
    am->ARMam2.RI.imm = imm;
    return am;
}
ARMAMode2* ARMAMode2_RR ( HReg Rn, HReg Rm ) {
    ARMAMode2* am = LibVEX_Alloc(sizeof(ARMAMode2));
    am->tag = ARMam2_RR;
    am->ARMam2.RR.Rn = Rn;
    am->ARMam2.RR.Rm = Rm;
    return am;
}
ARMAMode2* ARMAMode2_RRS ( HReg Rn, HReg Rm, ARMImm5 shift ) {
    ARMAMode2* am = LibVEX_Alloc(sizeof(ARMAMode2));
    am->tag = ARMam2_RRS;
    am->ARMam2.RRS.Rn = Rn;
    am->ARMam2.RRS.Rm = Rm;
    am->ARMam2.RRS.shift = shift;
    return am;
}

ARMAMode2* dopyARMAMode2 ( ARMAMode2* am ) {
   switch (am->tag) {
   case ARMam2_RI:
       return ARMAMode2_RI( am->ARMam2.RI.Rn, am->ARMam2.RI.imm );
   case ARMam2_RR:
       return ARMAMode2_RR( am->ARMam2.RR.Rn, am->ARMam2.RR.Rm );
   case ARMam2_RRS:
       return ARMAMode2_RRS( am->ARMam2.RRS.Rn, am->ARMam2.RRS.Rm,
			     am->ARMam2.RRS.shift );
   default:
       vpanic("dopyARMAMode2");
   }
}

void ppARMAMode2 ( ARMAMode2* am ) {
   switch (am->tag) {
   case ARMam2_RI:
   case ARMam2_RR:
   case ARMam2_RRS:
       vex_printf("ppARMAMode2: Not implemented");
       break;
   default:
       vpanic("ppARMAMode2");
   }
}

/*
static void addRegUsage_ARMAMode2 ( HRegUsage* u, ARMAMode1* am ) {
static void mapRegs_ARMAMode2 ( HRegRemap* m, ARMAMode1* am ) {
*/


/* --------- ARMAMode3: memory address expressions. --------- */

ARMAMode3* ARMAMode3_RI ( HReg Rn, ARMImm8 imm ) {
    ARMAMode3* am = LibVEX_Alloc(sizeof(ARMAMode3));
    am->tag = ARMam3_RI;
    am->ARMam3.RI.Rn = Rn;
    am->ARMam3.RI.imm = imm;
    return am;
}
ARMAMode3* ARMAMode3_RR ( HReg Rn, HReg Rm ) {
    ARMAMode3* am = LibVEX_Alloc(sizeof(ARMAMode3));
    am->tag = ARMam3_RR;
    am->ARMam3.RR.Rn = Rn;
    am->ARMam3.RR.Rm = Rm;
    return am;
}

ARMAMode3* dopyARMAMode3 ( ARMAMode3* am ) {
   switch (am->tag) {
   case ARMam3_RI:
       return ARMAMode3_RI( am->ARMam3.RI.Rn, am->ARMam3.RI.imm );
   case ARMam3_RR:
       return ARMAMode3_RR( am->ARMam3.RR.Rn, am->ARMam3.RR.Rm );
   default:
       vpanic("dopyARMAMode3");
   }
}

void ppARMAMode3 ( ARMAMode3* am ) {
   switch (am->tag) {
   case ARMam3_RI:
   case ARMam3_RR:
       vex_printf("ppARMAMode3: Not implemented");
       break;
   default:
       vpanic("ppARMAMode3");
   }
}

/*
static void addRegUsage_ARMAMode1 ( HRegUsage* u, ARMAMode2* am ) {
static void mapRegs_ARMAMode2 ( HRegRemap* m, ARMAMode2* am ) {
*/

/* ------ Branch destination ------ */

ARMBranchDest* ARMBranchDest_Imm ( ARMImm24 imm24 ) {
   ARMBranchDest* branch_dest = LibVEX_Alloc(sizeof(ARMBranchDest));
   branch_dest->tag = ARMbdImm;
   branch_dest->ARMbd.Imm.imm24 = imm24;
   return branch_dest;
}
ARMBranchDest* ARMBranchDest_Reg ( HReg reg ) {
   ARMBranchDest* branch_dest = LibVEX_Alloc(sizeof(ARMBranchDest));
   branch_dest->tag = ARMbdReg;
   branch_dest->ARMbd.Reg.reg = reg;
   return branch_dest;
}

void ppARMBranchDest ( ARMBranchDest* branch_dest ) {
    switch (branch_dest->tag) {
    case ARMbdImm:
    case ARMbdReg:
       vex_printf("ppARMBranchDest: Not implemented");
       break;
    default:
	vpanic("ppX86RM");
    }
}




/* --------- Instructions. --------- */

HChar* showARMAluOp ( ARMAluOp op ) {
    switch (op) {
    case ARMalu_AND:  return "and";
    case ARMalu_ORR:  return "orr";
    case ARMalu_EOR:  return "eor";
    case ARMalu_SUB:  return "sub";
    case ARMalu_RSB:  return "rsb";
    case ARMalu_ADD:  return "add";
    case ARMalu_ADC:  return "adc";
    case ARMalu_SBC:  return "sbc";
    case ARMalu_RSC:  return "rsc";
    case ARMalu_TST:  return "tst";
    case ARMalu_TEQ:  return "teq";
    case ARMalu_CMP:  return "cmp";
    case ARMalu_CMN:  return "cmn";
    case ARMalu_MOV:  return "mov";
    case ARMalu_MVN:  return "mvn";
    case ARMalu_BIC:  return "bic";
    default: vpanic("showARMAluOp");
    }
}

/* --- Addressing Mode 1 --- */
ARMInstr* ARMInstr_DPCmp ( ARMAluOp op, HReg Rn,
			   ARMAMode1* shifter_op ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_DPCmp;
    i->ARMin.DPCmp.op = op;
    i->ARMin.DPCmp.Rn = Rn;
    i->ARMin.DPCmp.shifter_op = shifter_op;
    return i;
}

ARMInstr* ARMInstr_DPInstr1 ( ARMAluOp op, HReg Rd,
			      ARMAMode1* shifter_op ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_DPInstr1;
    i->ARMin.DPInstr1.op = op;
    i->ARMin.DPInstr1.Rd = Rd;
    i->ARMin.DPInstr1.shifter_op = shifter_op;
    return i;
}

ARMInstr* ARMInstr_DPInstr2 ( ARMAluOp op, HReg Rd, HReg Rn,
			      ARMAMode1* shifter_op ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_DPInstr2;
    i->ARMin.DPInstr2.op = op;
    i->ARMin.DPInstr2.Rd = Rd;
    i->ARMin.DPInstr2.Rn = Rn;
    i->ARMin.DPInstr2.shifter_op = shifter_op;
    return i;
}

/* --- Addressing Mode 2 --- */
ARMInstr* ARMInstr_LoadUB ( HReg Rd, ARMAMode2* addr_mode ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_LoadUB;
    i->ARMin.LoadUB.Rd = Rd;
    i->ARMin.LoadUB.addr_mode = addr_mode;
    return i;
}

ARMInstr* ARMInstr_StoreB ( HReg Rd, ARMAMode2* addr_mode ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_StoreB;
    i->ARMin.StoreB.Rd = Rd;
    i->ARMin.StoreB.addr_mode = addr_mode;
    return i;
}

ARMInstr* ARMInstr_LoadW ( HReg Rd, ARMAMode2* addr_mode ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_LoadW;
    i->ARMin.LoadW.Rd = Rd;
    i->ARMin.LoadW.addr_mode = addr_mode;
    return i;
}

ARMInstr* ARMInstr_StoreW ( HReg Rd, ARMAMode2* addr_mode ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_StoreW;
    i->ARMin.StoreW.Rd = Rd;
    i->ARMin.StoreW.addr_mode = addr_mode;
    return i;
}

/* --- Addressing Mode 3 --- */
ARMInstr* ARMInstr_LoadSB ( HReg Rd, ARMAMode3* addr_mode ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_LoadSB;
    i->ARMin.LoadSB.Rd = Rd;
    i->ARMin.LoadSB.addr_mode = addr_mode;
    return i;
}

ARMInstr* ARMInstr_LoadUH ( HReg Rd, ARMAMode3* addr_mode ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_LoadUH;
    i->ARMin.LoadUH.Rd = Rd;
    i->ARMin.LoadUH.addr_mode = addr_mode;
    return i;
}

ARMInstr* ARMInstr_LoadSH ( HReg Rd, ARMAMode3* addr_mode ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_LoadSH;
    i->ARMin.LoadSH.Rd = Rd;
    i->ARMin.LoadSH.addr_mode = addr_mode;
    return i;
}

ARMInstr* ARMInstr_StoreH ( HReg Rd, ARMAMode3* addr_mode ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_StoreH;
    i->ARMin.StoreH.Rd = Rd;
    i->ARMin.StoreH.addr_mode = addr_mode;
    return i;
}

/* --- Branch --- */
ARMInstr* ARMInstr_Branch ( ARMCondCode cond, ARMBranchDest* dest ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_Branch;
    i->ARMin.Branch.cond = cond;
    i->ARMin.Branch.dest = dest;
    return i;
}

ARMInstr* ARMInstr_BranchL ( ARMCondCode cond, ARMBranchDest* dest ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_BranchL;
    i->ARMin.BranchL.dest = dest;
    return i;
}

/* --- Literal --- */
ARMInstr* ARMInstr_Literal ( HReg reg, UInt imm ) {
    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
    i->tag = ARMin_Literal;
    i->ARMin.Literal.reg = reg;
    i->ARMin.Literal.imm = imm;
    return i;
}


void ppARMInstr ( ARMInstr* i ) {
    switch (i->tag) {
    case ARMin_DPCmp:
    case ARMin_DPInstr1:
    case ARMin_DPInstr2:
    case ARMin_LoadUB:
    case ARMin_StoreB:
    case ARMin_LoadW:
    case ARMin_StoreW:
    case ARMin_LoadSB:
    case ARMin_LoadUH:
    case ARMin_LoadSH:
    case ARMin_StoreH:
    case ARMin_Branch:
    case ARMin_BranchL:
    case ARMin_Literal:
	vex_printf("ppARMInstr: Not implemented");
	break;

    default:
	vpanic("ppARMInstr");
    }
}




/* --------- Helpers for register allocation. --------- */

void getRegUsage_ARMInstr ( HRegUsage* u, ARMInstr* i ) {
//    Bool unary;
    initHRegUsage(u);
    switch (i->tag) {
    case ARMin_DPCmp:
    case ARMin_DPInstr1:
    case ARMin_DPInstr2:
    case ARMin_LoadUB:
    case ARMin_StoreB:
    case ARMin_LoadW:
    case ARMin_StoreW:
    case ARMin_LoadSB:
    case ARMin_LoadUH:
    case ARMin_LoadSH:
    case ARMin_StoreH:
    case ARMin_Branch:
    case ARMin_BranchL:
    case ARMin_Literal:

    default:
	ppARMInstr(i);
	vpanic("getRegUsage_ARMInstr");
    }
}


/* local helper */
#if 0
static void mapReg(HRegRemap* m, HReg* r) {
   *r = lookupHRegRemap(m, *r);
}
#endif

void mapRegs_ARMInstr ( HRegRemap* m, ARMInstr* i ) {
    switch (i->tag) {
    case ARMin_DPCmp:
    case ARMin_DPInstr1:
    case ARMin_DPInstr2:
    case ARMin_LoadUB:
    case ARMin_StoreB:
    case ARMin_LoadW:
    case ARMin_StoreW:
    case ARMin_LoadSB:
    case ARMin_LoadUH:
    case ARMin_LoadSH:
    case ARMin_StoreH:
    case ARMin_Branch:
    case ARMin_BranchL:
    case ARMin_Literal:

    default:
	ppARMInstr(i);
	vpanic("getRegUsage_ARMInstr");
    }
}

/* Figure out if i represents a reg-reg move, and if so assign the
   source and destination to *src and *dst.  If in doubt say No.  Used
   by the register allocator to do move coalescing. 
*/
Bool isMove_ARMInstr ( ARMInstr* i, HReg* src, HReg* dst ) {
    return False;  // No optimisations for now...
}


/* Generate x86 spill/reload instructions under the direction of the
   register allocator.  Note it's critical these don't write the
   condition codes. */

ARMInstr* genSpill_ARM ( HReg rreg, Int offsetB ) {
//   ARMAMode1* am;
   vassert(offsetB >= 0);
   vassert(!hregIsVirtual(rreg));

   switch (hregClass(rreg)) {

   default: 
       ppHRegClass(hregClass(rreg));
       vpanic("genSpill_ARM: unimplemented regclass");
   }
}

ARMInstr* genReload_ARM ( HReg rreg, Int offsetB ) {
//   ARMAMode1* am;
   vassert(offsetB >= 0);
   vassert(!hregIsVirtual(rreg));

   switch (hregClass(rreg)) {

   default: 
       ppHRegClass(hregClass(rreg));
       vpanic("genReload_ARM: unimplemented regclass");
   }
}


/* Emit an instruction into buf and return the number of bytes used.
   Note that buf is not the insn's final place, and therefore it is
   imperative to emit position-independent code. */

Int emit_ARMInstr ( UChar* buf, Int nbuf, ARMInstr* i ) {
//    UInt irno, opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
    
//    UInt   xtra;
    UChar* p = &buf[0];
//    UChar* ptmp;
    vassert(nbuf >= 32);

    switch (i->tag) {
    case ARMin_DPCmp:
    case ARMin_DPInstr1:
    case ARMin_DPInstr2:
    case ARMin_LoadUB:
    case ARMin_StoreB:
    case ARMin_LoadW:
    case ARMin_StoreW:
    case ARMin_LoadSB:
    case ARMin_LoadUH:
    case ARMin_LoadSH:
    case ARMin_StoreH:
    case ARMin_Branch:
    case ARMin_BranchL:
    case ARMin_Literal:
    default: 
	goto bad;
    }

 bad:
    ppARMInstr(i);
    vpanic("emit_ARMInstr");
    /*NOTREACHED*/
    
// done:
    vassert(p - &buf[0] <= 32);
    return p - &buf[0];
}


/*---------------------------------------------------------------*/
/*--- end                                     host_arm_defs.c ---*/
/*---------------------------------------------------------------*/
