PageRenderTime 144ms CodeModel.GetById 19ms app.highlight 113ms RepoModel.GetById 1ms app.codeStats 1ms

/opengles/src/codegen/emit.c

http://ftk.googlecode.com/
C | 2481 lines | 1798 code | 501 blank | 182 comment | 261 complexity | 16e769e3fd8a62860ea5fbab505fb4b5 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/****************************************************************************/
   2/*																			*/
   3/* Copyright (c) 2004, Hans-Martin Will. All rights reserved.				*/
   4/*																			*/
   5/* Redistribution and use in source and binary forms, with or without		*/
   6/* modification, are permitted provided that the following conditions are   */
   7/* met:																		*/
   8/*																			*/
   9/* *  Redistributions of source code must retain the above copyright		*/
  10/*    notice, this list of conditions and the following disclaimer.			*/
  11/*																			*/
  12/* *  Redistributions in binary form must reproduce the above copyright		*/
  13/*    notice, this list of conditions and the following disclaimer in the   */
  14/*    documentation and/or other materials provided with the distribution.  */
  15/*																			*/
  16/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS		*/
  17/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT		*/
  18/* LIMITED TO, THEIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A   */
  19/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER */
  20/* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, */
  21/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,		*/
  22/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR		*/
  23/* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF   */
  24/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING		*/
  25/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS		*/
  26/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.				*/
  27/*																			*/
  28/****************************************************************************/
  29
  30
  31#include "emit.h"
  32#include "bitset.h"
  33#include "heap.h"
  34#include "segment.h"
  35#include "arm-codegen.h"
  36
  37
  38#define SAVE_AREA_SIZE (10 * sizeof(U32))		/* this really depends on the function prolog */
  39
  40
  41typedef struct reference_t
  42{
  43	struct reference_t *	next;
  44	cg_reference_type_t		ref_type;
  45	size_t					offset;
  46}
  47reference_t;
  48
  49
  50struct cg_label_t 
  51{
  52	cg_label_t *			next;
  53	reference_t *			refs;
  54	size_t					offset;
  55};
  56
  57
  58typedef enum physical_reg_status_t
  59{
  60	reg_status_init,
  61	reg_status_free,
  62	reg_status_allocated,
  63	reg_status_defined,
  64	reg_status_dirty,
  65	reg_status_secondary
  66}
  67physical_reg_status_t;
  68
  69
  70typedef enum physical_reg_event_t
  71{
  72	reg_event_init,
  73	reg_event_allocate,
  74	reg_event_deallocate,
  75	reg_event_load,
  76	reg_event_save,
  77	reg_event_define,
  78	reg_event_reassign
  79}
  80physical_reg_event_t;
  81
  82
  83/****************************************************************************/
  84/* This method implements the finite state machine underlying physical		*/
  85/* register allocation.														*/
  86/****************************************************************************/
  87static physical_reg_status_t update_register_status(physical_reg_status_t state, 
  88													physical_reg_event_t event)
  89{
  90	if (event == reg_event_init)
  91	{
  92		return reg_status_init;
  93	}
  94
  95	switch (state)
  96	{
  97	case reg_status_init:
  98		switch (event)
  99		{
 100		case (reg_event_init):
 101			return reg_status_free;
 102
 103		default:
 104			assert(0);
 105		}
 106		break;
 107
 108	case reg_status_free:
 109		switch (event)
 110		{
 111		case (reg_event_allocate):
 112			return reg_status_allocated;
 113
 114		default:
 115			assert(0);
 116		}
 117		break;
 118
 119	case reg_status_allocated:
 120		switch (event)
 121		{
 122		case reg_event_load:
 123			return reg_status_defined;
 124
 125		case reg_event_define:
 126			return reg_status_dirty;
 127
 128		default:
 129			assert(0);
 130		}
 131		break;
 132
 133	case reg_status_defined:
 134		switch (event)
 135		{
 136		case reg_event_deallocate:
 137			return reg_status_free;
 138
 139		case reg_event_reassign:
 140			return reg_status_secondary;
 141
 142		default:
 143			assert(0);
 144		}
 145		break;
 146
 147	case reg_status_dirty:
 148		switch (event)
 149		{
 150		case reg_event_save:
 151			return reg_status_defined;
 152
 153		default:
 154			assert(0);
 155		}
 156		break;
 157
 158	case reg_status_secondary:
 159		switch (event)
 160		{
 161		case reg_event_define:
 162			return reg_status_dirty;
 163
 164		case reg_event_reassign:
 165			return reg_status_defined;
 166
 167		default:
 168			assert(0);
 169		}
 170		break;
 171
 172	default:
 173		assert(0);
 174		break;
 175	}
 176
 177	return reg_status_init;
 178}
 179
 180
 181struct physical_reg_list_t;
 182
 183typedef struct cg_physical_reg_t 
 184{
 185	struct cg_physical_reg_t * prev;				/* for LRU chain			*/
 186	struct cg_physical_reg_t * next;				/* for LRU chain			*/
 187	struct physical_reg_list_t * list;
 188	ARMReg					regno;				/* physical register		*/
 189	cg_virtual_reg_t *		virtual_reg;		/* assigned virtual reg.	*/
 190	cg_inst_t *				next_use;			/* next use of ass. value   */
 191	physical_reg_status_t	state;				/* current register state	*/
 192	int						dirty: 1;
 193	int						defined:1;
 194}
 195cg_physical_reg_t;
 196
 197
 198typedef struct physical_reg_list_t
 199{
 200	cg_physical_reg_t *		head;
 201	cg_physical_reg_t *		tail;	
 202}
 203physical_reg_list_t;
 204
 205
 206void reg_list_add(physical_reg_list_t * list, cg_physical_reg_t * reg)
 207{
 208	assert(!reg->list);
 209	assert(!reg->prev);
 210	assert(!reg->next);
 211	
 212	if (list->tail == (cg_physical_reg_t *) 0)
 213	{
 214		assert(list->head == (cg_physical_reg_t *) 0);
 215		list->head = list->tail = reg;
 216		reg->prev = reg->next = NULL;
 217	}
 218	else 
 219	{
 220		assert(list->head != (cg_physical_reg_t *) 0);
 221		reg->prev = NULL;
 222		reg->next = list->head;
 223		list->head->prev = reg;
 224		list->head = reg;
 225	}
 226
 227	reg->list = list;
 228}
 229
 230
 231void reg_list_remove(physical_reg_list_t * list, cg_physical_reg_t * reg)
 232{
 233	assert(reg->list == list);
 234
 235	if (reg->prev != (cg_physical_reg_t *) 0)
 236	{
 237		assert(list->head != reg);
 238		reg->prev->next = reg->next;
 239	}
 240	else 
 241	{
 242		assert(list->head == reg);
 243		list->head = reg->next;
 244	}
 245	
 246	if (reg->next != (cg_physical_reg_t *) 0)
 247	{
 248		assert(list->tail != reg);
 249		reg->next->prev = reg->prev;
 250	}
 251	else 
 252	{
 253		assert(list->tail == reg);
 254		list->tail = reg->prev;
 255	}
 256	
 257	reg->prev = reg->next = (cg_physical_reg_t *) 0;
 258	reg->list = NULL;
 259}
 260
 261
 262void reg_list_move_to_front(physical_reg_list_t * list, cg_physical_reg_t * reg)
 263{
 264	reg_list_remove(list, reg);
 265	reg_list_add(list, reg);
 266}
 267
 268
 269typedef struct literal_t
 270{
 271	struct literal_t *	next;
 272	U32					value;
 273	size_t				offset;
 274}
 275literal_t;
 276
 277
 278#define PHYSICAL_REGISTERS  (ARMREG_MAX + 1)
 279
 280struct cg_codegen_t 
 281{
 282	cg_runtime_info_t *		runtime;
 283	cg_processor_info_t *	processor;
 284	cg_heap_t *				heap;
 285	cg_label_t *			labels;
 286	cg_segment_t *			cseg;
 287	
 288	cg_physical_reg_t			registers[PHYSICAL_REGISTERS];
 289	cg_physical_reg_t			flags;
 290
 291	physical_reg_list_t		free_regs;			/* phys regs free			*/
 292	physical_reg_list_t		used_regs;			/* phys regs in use			*/
 293	physical_reg_list_t		global_regs;		/* global phys regs in use	*/
 294	
 295	/************************************************************************/
 296	/* for each block, the following array will be heads to the use chains  */
 297	/* within the block currently processed.								*/
 298	/************************************************************************/
 299	
 300	cg_block_t *			current_block;
 301	literal_t *				literals;
 302	cg_label_t *			literal_base;
 303	size_t					literal_pool_size;
 304	size_t					locals_size_offset;
 305	cg_inst_list_t **		use_chains;			
 306};
 307
 308
 309int is_simple_inst(cg_inst_t * inst) {
 310	switch (inst->base.opcode)
 311	{
 312		case cg_op_finv:
 313		case cg_op_fdiv:
 314		case cg_op_fsqrt:
 315		case cg_op_div:
 316		case cg_op_mod:
 317		case cg_op_call:
 318			return 0;
 319			
 320		default:
 321			return 1;
 322	}
 323}
 324
 325
 326size_t cg_codegen_emit_literal(cg_codegen_t * gen, U32 value, int distinct)
 327{
 328	literal_t ** literal;
 329
 330	for (literal = &gen->literals; (*literal) != (literal_t *) 0; literal = &(*literal)->next)
 331	{
 332		if (!distinct && (*literal)->value == value)
 333			return (*literal)->offset;
 334	}
 335
 336	*literal = cg_heap_allocate(gen->heap, sizeof (literal_t));
 337
 338	(*literal)->value = value;
 339	(*literal)->offset = gen->literal_pool_size;
 340	gen->literal_pool_size += sizeof(U32);
 341
 342	return (*literal)->offset;
 343}
 344
 345
 346cg_codegen_t * cg_codegen_create(cg_heap_t * heap, cg_runtime_info_t * runtime,
 347								 cg_processor_info_t * processor) 
 348{
 349	size_t regno;
 350	
 351	cg_codegen_t * gen = 
 352		(cg_codegen_t *) cg_heap_allocate(heap, sizeof(cg_codegen_t));
 353	memset(gen, 0, sizeof *gen);
 354	
 355	gen->runtime = runtime;
 356	gen->processor = processor;
 357	gen->heap = heap;
 358	gen->labels = (cg_label_t *) 0;
 359	gen->cseg = cg_segment_create("CSEG");
 360	
 361	for (regno = 0; regno != PHYSICAL_REGISTERS; ++regno)
 362	{
 363		gen->registers[regno].regno = (ARMReg) (ARMREG_R0 + regno);
 364	}
 365	
 366	gen->flags.regno = ARMREG_CPSR;
 367
 368	return gen;
 369}
 370
 371
 372void cg_codegen_destroy(cg_codegen_t * gen)
 373{
 374	cg_segment_destroy(gen->cseg);
 375}
 376
 377
 378/****************************************************************************/
 379/* Processing of individual instructions									*/
 380/****************************************************************************/
 381
 382
 383static cg_physical_reg_t * allocate_reg(cg_codegen_t * gen, cg_virtual_reg_t * reg,
 384									 U32 mask);
 385static void deallocate_reg(cg_codegen_t * gen, cg_physical_reg_t * physical_reg);
 386static void assign_reg(cg_codegen_t * gen,
 387					   cg_physical_reg_t * physical_reg, 
 388					   cg_virtual_reg_t * reg);
 389static void make_global(cg_codegen_t * gen, cg_physical_reg_t * reg);
 390static cg_physical_reg_t * load_reg(cg_codegen_t * gen, cg_virtual_reg_t * reg,
 391									 U32 mask);
 392
 393
 394static ARMShiftType arm_shift_type(cg_shift_op_t shift_op)
 395{
 396	switch (shift_op)
 397	{
 398		default:
 399			assert(0);
 400
 401		case cg_shift_lsl:
 402			return ARMSHIFT_LSL;
 403			
 404		case cg_shift_lsr:
 405			return ARMSHIFT_LSR;
 406			
 407		case cg_shift_asr:
 408			return ARMSHIFT_ASR;
 409			
 410		case cg_shift_ror:
 411			return ARMSHIFT_ROR;
 412	}
 413}
 414
 415
 416static void branch_cond(cg_codegen_t * gen, cg_label_t * target, ARMCond cond)
 417{
 418	/* insert a conditional branch to the specified target label */
 419	cg_codegen_reference(gen, target, cg_reference_branch24);
 420	/* compensate for PC pointing 2 instruction words ahead */
 421	ARM_B_COND(gen->cseg, cond, -2 & 0xFFFFFF);
 422}
 423
 424
 425static void branch(cg_codegen_t * gen, cg_label_t * target)
 426{
 427	branch_cond(gen, target, ARMCOND_AL);
 428}
 429
 430
 431static void save_flags(cg_codegen_t * gen, cg_physical_reg_t * physical_reg)
 432{
 433	ARM_MRS_CPSR(gen->cseg, physical_reg->regno);
 434}
 435
 436
 437static void restore_flags(cg_codegen_t * gen, cg_physical_reg_t * reg)
 438{
 439	ARM_MSR_REG(gen->cseg, ARM_PSR_F, reg->regno, ARM_CPSR);
 440}
 441
 442
 443static void call_store_additional_args(cg_codegen_t * gen, cg_virtual_reg_list_t * args, cg_inst_t * inst)
 444{
 445	/* In case we have more than 4 arguments: store all remaining args onto the stack */
 446
 447	ARMReg regno;
 448
 449	for (regno = ARMREG_A1; regno <= ARMREG_A4 && args != (cg_virtual_reg_list_t *) 0; 
 450		 ++regno, args = args->next)
 451		;										/* skip register arguments */
 452
 453	if (args != (cg_virtual_reg_list_t *) 0) 
 454	{
 455		size_t argument_base_offset = 0;
 456
 457		do
 458		{
 459			cg_virtual_reg_t * reg = args->reg;
 460			cg_physical_reg_t * physical_reg;
 461			cg_inst_list_t ** plist = &gen->use_chains[reg->reg_no];
 462			
 463			while (*plist != (cg_inst_list_t *) 0 &&
 464				(*plist)->inst != inst)
 465			{
 466				plist = &(*plist)->next;
 467			}
 468			
 469			if (*plist != 0)
 470			{
 471				*plist = (*plist)->next;
 472			}
 473			
 474			physical_reg = load_reg(gen, reg, 0);
 475		
 476			/* save the register into the parameter area */
 477			ARM_STR_IMM(gen->cseg, physical_reg->regno, ARMREG_FP, argument_base_offset);
 478
 479			if (gen->use_chains[reg->reg_no] == (cg_inst_list_t *) 0)
 480			{
 481				deallocate_reg(gen, physical_reg);
 482			}
 483
 484			args = args->next;
 485			argument_base_offset += sizeof(U32);
 486		}
 487		while (args != (cg_virtual_reg_list_t *) 0);
 488	}
 489}
 490
 491
 492static void load_register_arg(cg_codegen_t * gen, cg_virtual_reg_t * reg, ARMReg regno, cg_inst_t * inst)
 493{
 494	U32 mask = 1u << regno;
 495
 496	/* force argument into the specified register */
 497	cg_physical_reg_t * physical_reg;
 498	cg_inst_list_t ** plist = &gen->use_chains[reg->reg_no];
 499	
 500	while (*plist != (cg_inst_list_t *) 0 &&
 501		(*plist)->inst != inst)
 502	{
 503		plist = &(*plist)->next;
 504	}
 505	
 506	if (*plist != 0)
 507	{
 508		*plist = (*plist)->next;
 509	}
 510	
 511	physical_reg = load_reg(gen, reg, mask);
 512	assert(physical_reg->virtual_reg == reg);
 513}
 514
 515
 516static void kill_argument_registers(cg_codegen_t * gen)
 517{
 518	ARMReg regno;
 519
 520	for (regno = ARMREG_A1; regno <= ARMREG_A4; ++regno)
 521	{
 522		cg_physical_reg_t * physical_reg = gen->registers + regno;
 523		cg_virtual_reg_t * reg = physical_reg->virtual_reg;
 524
 525		if (reg != NULL)
 526		{
 527			if (reg->physical_reg == physical_reg)
 528			{
 529				deallocate_reg(gen, physical_reg);
 530			}
 531			else
 532			{
 533				/* register is a duplicate of another register, just free it up */
 534				reg_list_remove(&gen->used_regs, physical_reg);
 535				reg_list_add(&gen->free_regs, physical_reg);
 536				
 537				physical_reg->virtual_reg = 0;
 538			}
 539		}
 540	}
 541}
 542
 543
 544static void kill_flags(cg_codegen_t * gen)
 545{
 546	if (gen->flags.virtual_reg != NULL &&
 547		gen->flags.virtual_reg->physical_reg == &gen->flags)
 548	{
 549		cg_virtual_reg_t * reg = gen->flags.virtual_reg;
 550
 551		 int used = CG_BITSET_TEST(gen->current_block->live_out, reg->reg_no) ||
 552			gen->use_chains[reg->reg_no];
 553
 554		if (used) 
 555		{
 556			cg_physical_reg_t * physical_reg = allocate_reg(gen, reg, 0);
 557			assign_reg(gen, physical_reg, reg);
 558			save_flags(gen, physical_reg);
 559			physical_reg->dirty = physical_reg->defined = 1;
 560		}
 561	}
 562}
 563
 564
 565static void call_load_register_args(cg_codegen_t * gen, cg_virtual_reg_list_t * begin_args, cg_inst_t * inst)
 566{
 567	ARMReg regno;
 568	cg_virtual_reg_list_t * args;
 569
 570	for (regno = ARMREG_A1, args = begin_args; regno <= ARMREG_A4 && args != (cg_virtual_reg_list_t *) 0; 
 571		 ++regno, args = args->next)
 572	{
 573		load_register_arg(gen, args->reg, regno, inst);
 574	}
 575
 576	kill_flags(gen);
 577	kill_argument_registers(gen);
 578}
 579
 580	
 581
 582static void call_runtime(cg_codegen_t * gen, void * target)
 583{
 584	/* create the necessary code sequence to call into a procedure that is  */
 585	/* part of the runtime library											*/
 586
 587	ARM_MOV_REG_REG(gen->cseg, ARMREG_LR, ARMREG_PC);
 588	cg_codegen_reference(gen, gen->literal_base, cg_reference_offset12);
 589	ARM_LDR_IMM(gen->cseg, ARMREG_PC, ARMREG_PC, 
 590		(cg_codegen_emit_literal(gen, (U32) target, 0) - 8) & 0xfff);
 591}
 592
 593
 594static void call(cg_codegen_t * gen, cg_label_t * target,
 595				 cg_virtual_reg_list_t * args, cg_inst_t * inst)
 596{
 597	/* create the necessary code sequence to call into a procedure */
 598
 599	call_store_additional_args(gen, args, inst);
 600	call_load_register_args(gen, args, inst);
 601	cg_codegen_reference(gen, target, cg_reference_branch24);
 602	ARM_BL(gen->cseg, -2);
 603}
 604
 605
 606static void emit_unary_negate(cg_codegen_t * gen, cg_inst_unary_t * inst,
 607							  int update_flags)
 608{
 609	switch (inst->base.kind)
 610	{
 611		case cg_inst_unary:
 612			if (update_flags)
 613				ARM_RSBS_REG_IMM(gen->cseg,
 614								 inst->dest_value->physical_reg->regno,
 615								 inst->operand.source->physical_reg->regno,
 616								 0, 0);
 617			else
 618				ARM_RSB_REG_IMM(gen->cseg,
 619								inst->dest_value->physical_reg->regno,
 620								inst->operand.source->physical_reg->regno,
 621								0, 0);
 622
 623			break;
 624						
 625		default:
 626			assert(0);
 627	}
 628}
 629
 630
 631static void emit_unary_complement(cg_codegen_t * gen, cg_inst_unary_t * inst,
 632								  int update_flags)
 633{
 634	switch (inst->base.kind)
 635	{
 636		case cg_inst_unary:
 637			if (update_flags)
 638				ARM_MVNS_REG_REG(gen->cseg,
 639								 inst->dest_value->physical_reg->regno,
 640								 inst->operand.source->physical_reg->regno);
 641			else
 642				ARM_MVN_REG_REG(gen->cseg,
 643								inst->dest_value->physical_reg->regno,
 644								inst->operand.source->physical_reg->regno);
 645
 646			break;
 647			
 648		case cg_inst_arm_unary_immed:
 649			assert(inst->operand.immed >= 0 && inst->operand.immed <= 0xff);
 650
 651			if (update_flags)
 652				ARM_MVNS_REG_IMM(gen->cseg,
 653								 inst->dest_value->physical_reg->regno,
 654								 inst->operand.immed, 0);
 655			else
 656				ARM_MVN_REG_IMM(gen->cseg,
 657								inst->dest_value->physical_reg->regno,
 658								inst->operand.immed, 0);
 659
 660			break;
 661			
 662		case cg_inst_arm_unary_shift_reg:
 663			if (update_flags)
 664				ARM_MVNS_REG_REGSHIFT(gen->cseg,
 665									 inst->dest_value->physical_reg->regno,
 666									 inst->operand.shift_reg.source->physical_reg->regno, 
 667									 arm_shift_type(inst->operand.shift_reg.op),
 668									 inst->operand.shift_reg.shift->physical_reg->regno);
 669			else
 670				ARM_MVN_REG_REGSHIFT(gen->cseg,
 671									inst->dest_value->physical_reg->regno,
 672									inst->operand.shift_reg.source->physical_reg->regno, 
 673									arm_shift_type(inst->operand.shift_reg.op),
 674									inst->operand.shift_reg.shift->physical_reg->regno);
 675			break;
 676			
 677		case cg_inst_arm_unary_shift_immed:
 678			if (update_flags)
 679				ARM_MVNS_REG_IMMSHIFT(gen->cseg,
 680									 inst->dest_value->physical_reg->regno,
 681									 inst->operand.shift_immed.source->physical_reg->regno, 
 682									 arm_shift_type(inst->operand.shift_immed.op),
 683									 inst->operand.shift_immed.shift);
 684			else
 685				ARM_MVN_REG_IMMSHIFT(gen->cseg,
 686									inst->dest_value->physical_reg->regno,
 687									inst->operand.shift_immed.source->physical_reg->regno, 
 688									arm_shift_type(inst->operand.shift_immed.op),
 689									inst->operand.shift_immed.shift);
 690
 691			break;
 692			
 693		default:
 694			assert(0);
 695	}
 696}
 697
 698
 699static void emit_unary_trunc(cg_codegen_t * gen, cg_inst_unary_t * inst,
 700							 int update_flags)
 701{
 702	assert(inst->base.kind == cg_inst_unary);
 703	
 704	if (update_flags)
 705		ARM_MOVS_REG_IMMSHIFT(gen->cseg,
 706							  inst->dest_value->physical_reg->regno,
 707							  inst->operand.source->physical_reg->regno,
 708							  ARMSHIFT_ASR, 16);						 
 709	else
 710		ARM_MOV_REG_IMMSHIFT(gen->cseg,
 711							 inst->dest_value->physical_reg->regno,
 712							 inst->operand.source->physical_reg->regno,
 713							 ARMSHIFT_ASR, 16);						 
 714
 715}
 716
 717
 718static void emit_unary_round(cg_codegen_t * gen, cg_inst_unary_t * inst,
 719							 int update_flags)
 720{
 721	assert(inst->base.kind == cg_inst_unary);
 722	
 723	ARM_ADD_REG_IMM(gen->cseg,
 724					inst->dest_value->physical_reg->regno,
 725					inst->operand.source->physical_reg->regno,
 726					0x80, 24);
 727	
 728	if (update_flags)
 729		ARM_MOVS_REG_IMMSHIFT(gen->cseg,
 730							  inst->dest_value->physical_reg->regno,
 731							  inst->dest_value->physical_reg->regno,
 732							  ARMSHIFT_ASR, 16);						 
 733	else
 734		ARM_MOV_REG_IMMSHIFT(gen->cseg,
 735							 inst->dest_value->physical_reg->regno,
 736							 inst->dest_value->physical_reg->regno,
 737							 ARMSHIFT_ASR, 16);						 
 738
 739}
 740
 741
 742static void emit_unary_fcnv(cg_codegen_t * gen, cg_inst_unary_t * inst,
 743							int update_flags)
 744{
 745	assert(inst->base.kind == cg_inst_unary);
 746	
 747	if (update_flags)
 748		ARM_MOVS_REG_IMMSHIFT(gen->cseg,
 749							  inst->dest_value->physical_reg->regno,
 750							  inst->operand.source->physical_reg->regno,
 751							  ARMSHIFT_LSL, 16);						 
 752	else
 753		ARM_MOV_REG_IMMSHIFT(gen->cseg,
 754							 inst->dest_value->physical_reg->regno,
 755							 inst->operand.source->physical_reg->regno,
 756							 ARMSHIFT_LSL, 16);						 
 757}
 758
 759
 760static void emit_unary_abs(cg_codegen_t * gen, cg_inst_unary_t * inst, int update_flags)
 761{
 762	assert(!update_flags);
 763	assert(inst->base.kind == cg_inst_unary);
 764
 765	ARM_CMP_REG_IMM8(gen->cseg, 
 766					inst->operand.source->physical_reg->regno,
 767					0);
 768
 769	ARM_MOV_REG_REG_COND(gen->cseg,
 770						 inst->dest_value->physical_reg->regno,
 771						 inst->operand.source->physical_reg->regno,
 772						 ARMCOND_GE);
 773					
 774	ARM_MVN_REG_REG_COND(gen->cseg,
 775						 inst->dest_value->physical_reg->regno,
 776						 inst->operand.source->physical_reg->regno,
 777						 ARMCOND_LT);
 778}
 779
 780
 781static void emit_unary_log2(cg_codegen_t * gen, cg_inst_unary_t * inst, int update_flags)
 782{
 783	assert(!update_flags);
 784	assert(inst->base.kind == cg_inst_unary);
 785
 786	if (gen->processor->useV5) {
 787		ARM_CLZ(gen->cseg, 
 788				inst->dest_value->physical_reg->regno, 
 789				inst->operand.source->physical_reg->regno);
 790		ARM_RSBS_REG_IMM8(gen->cseg,
 791				inst->dest_value->physical_reg->regno, 
 792				inst->dest_value->physical_reg->regno, 
 793				31);
 794		ARM_MOV_REG_IMM8_COND(gen->cseg,
 795				inst->dest_value->physical_reg->regno,
 796				0,
 797				ARMCOND_MI);
 798	} else {
 799		// allocate a temporary register
 800		cg_virtual_reg_t temp_reg0, temp_reg1;
 801		cg_physical_reg_t * temp_physical_reg0, *temp_physical_reg1;
 802		U32 mask;
 803
 804		memset(&temp_reg0, 0, sizeof temp_reg0);
 805		memset(&temp_reg1, 0, sizeof temp_reg1);
 806		
 807		/* may need to create a mask based on the registers allocated for		*/
 808		/* the other operands													*/
 809		mask = ~((1u << inst->dest_value->physical_reg->regno)  |
 810				 (1u << inst->operand.source->physical_reg->regno));
 811		
 812		temp_physical_reg0 = allocate_reg(gen, &temp_reg0, mask);
 813		assign_reg(gen, temp_physical_reg0, &temp_reg0);
 814
 815		mask &= ~(1u << temp_physical_reg0->regno);
 816		
 817		temp_physical_reg1 = allocate_reg(gen, &temp_reg1, mask);
 818		assign_reg(gen, temp_physical_reg1, &temp_reg1);
 819
 820		//exp = 0;
 821		ARM_MOV_REG_IMM8(gen->cseg,
 822						 inst->dest_value->physical_reg->regno,
 823						 0);
 824		ARM_MOV_REG_REG(gen->cseg,
 825						temp_physical_reg0->regno,
 826						inst->operand.source->physical_reg->regno);	    
 827
 828		//if (f & 0xff00) { exp += 8; f >>= 8; }
 829		ARM_ANDS_REG_IMM(gen->cseg,
 830						 temp_physical_reg1->regno,
 831						 temp_physical_reg0->regno,
 832						 0xff, 
 833						 calc_arm_mov_const_shift(0xff00));
 834		ARM_MOV_REG_IMM8_COND(gen->cseg,
 835							  inst->dest_value->physical_reg->regno,
 836							  8, ARMCOND_NE);
 837		ARM_MOV_REG_IMMSHIFT_COND(gen->cseg,
 838							 temp_physical_reg0->regno,
 839							 temp_physical_reg0->regno,
 840							 ARMSHIFT_ASR, 8, ARMCOND_NE);	    
 841		//if (f & 0xf0) { exp += 4; f >>= 4; }
 842		ARM_ANDS_REG_IMM8(gen->cseg,
 843						  temp_physical_reg1->regno,
 844						  temp_physical_reg0->regno,
 845						  0xf0);
 846		ARM_ADD_REG_IMM8_COND(gen->cseg,
 847							  inst->dest_value->physical_reg->regno,
 848							  inst->dest_value->physical_reg->regno,
 849							  4, ARMCOND_NE);
 850		ARM_MOV_REG_IMMSHIFT_COND(gen->cseg,
 851							 temp_physical_reg0->regno,
 852							 temp_physical_reg0->regno,
 853							 ARMSHIFT_ASR, 4, ARMCOND_NE);	    
 854
 855		//if (f & 0xc) { exp += 2; f >>= 2; }
 856		ARM_ANDS_REG_IMM8(gen->cseg,
 857						  temp_physical_reg1->regno,
 858						  temp_physical_reg0->regno,
 859						  0xc);
 860		ARM_ADD_REG_IMM8_COND(gen->cseg,
 861							  inst->dest_value->physical_reg->regno,
 862							  inst->dest_value->physical_reg->regno,
 863							  2, ARMCOND_NE);
 864		ARM_MOV_REG_IMMSHIFT_COND(gen->cseg,
 865							 temp_physical_reg0->regno,
 866							 temp_physical_reg0->regno,
 867							 ARMSHIFT_ASR, 2, ARMCOND_NE);	    
 868
 869		//if (f & 0x2) { exp += 1; }
 870		ARM_ANDS_REG_IMM8(gen->cseg,
 871						  temp_physical_reg1->regno,
 872						  temp_physical_reg0->regno,
 873						  0x2);
 874		ARM_ADD_REG_IMM8_COND(gen->cseg,
 875							  inst->dest_value->physical_reg->regno,
 876							  inst->dest_value->physical_reg->regno,
 877							  1, ARMCOND_NE);
 878
 879		// release the temporary register
 880		deallocate_reg(gen, temp_physical_reg0);
 881		deallocate_reg(gen, temp_physical_reg1);
 882	}
 883}
 884
 885
 886static void emit_unary(cg_codegen_t * gen, cg_inst_unary_t * inst,
 887					   int update_flags)
 888{
 889	// distinguish operations that map directly to ARM instructions
 890	// operations that require sequence of instructions
 891	// operations that map into a function call
 892
 893	switch (inst->base.opcode)
 894	{
 895		/* regular unary operation */
 896		case cg_op_neg:
 897		case cg_op_fneg:
 898			emit_unary_negate(gen, inst, update_flags);
 899			break;
 900			
 901		case cg_op_not:		
 902			emit_unary_complement(gen, inst, update_flags);
 903			break;
 904			
 905		/* sequences */
 906		case cg_op_trunc:	
 907			emit_unary_trunc(gen, inst, update_flags);
 908			break;
 909			
 910		case cg_op_round:	
 911			emit_unary_round(gen, inst, update_flags);
 912			break;
 913			
 914		case cg_op_fcnv:															
 915			emit_unary_fcnv(gen, inst, update_flags);
 916			break;
 917
 918		case cg_op_abs:
 919			emit_unary_abs(gen, inst, update_flags);
 920			break;
 921
 922		case cg_op_log2:
 923			emit_unary_log2(gen, inst, update_flags);
 924			break;
 925
 926		default:
 927			assert(0);
 928	}
 929}
 930
 931
 932static void emit_binary_shifter(cg_codegen_t * gen, cg_inst_binary_t * inst,
 933								int update_flags)
 934{
 935	ARMShiftType shift_type;
 936	
 937	switch (inst->base.opcode)
 938	{
 939		default:
 940			assert(0);
 941			
 942		case cg_op_lsl:
 943			shift_type = ARMSHIFT_LSL;
 944			break;
 945			
 946		case cg_op_lsr:
 947			shift_type = ARMSHIFT_LSR;
 948			break;
 949			
 950		case cg_op_asr:
 951			shift_type = ARMSHIFT_ASR;
 952			break;
 953	}
 954	
 955	switch (inst->base.kind)
 956	{
 957		case cg_inst_binary:
 958			if (update_flags)
 959				ARM_MOVS_REG_REGSHIFT(gen->cseg,
 960									  inst->dest_value->physical_reg->regno,
 961									  inst->source->physical_reg->regno,
 962									  shift_type,
 963									  inst->operand.source->physical_reg->regno);
 964			else
 965				ARM_MOV_REG_REGSHIFT(gen->cseg,
 966									 inst->dest_value->physical_reg->regno,
 967									 inst->source->physical_reg->regno,
 968									 shift_type,
 969									 inst->operand.source->physical_reg->regno);
 970
 971			break;
 972			
 973		case cg_inst_arm_binary_immed:
 974			if (update_flags)
 975				ARM_MOVS_REG_IMMSHIFT(gen->cseg,
 976									  inst->dest_value->physical_reg->regno,
 977									  inst->source->physical_reg->regno,
 978									  shift_type,
 979									  inst->operand.immed);
 980			else
 981				ARM_MOV_REG_IMMSHIFT(gen->cseg,
 982									 inst->dest_value->physical_reg->regno,
 983									 inst->source->physical_reg->regno,
 984									 shift_type,
 985									 inst->operand.immed);
 986
 987			break;
 988			
 989		default:
 990			assert(0);
 991	}
 992}
 993
 994
 995static void emit_binary_regular(cg_codegen_t * gen, cg_inst_binary_t * inst,
 996								ARMOpcode opcode, int update_flags)
 997{
 998	int shift;
 999
1000	switch (inst->base.kind)
1001	{
1002		case cg_inst_binary:
1003			if (update_flags)
1004				ARM_DPIOP_S_REG_REG_COND(gen->cseg, 
1005										 opcode, 
1006										 inst->dest_value->physical_reg->regno, 
1007										 inst->source->physical_reg->regno, 
1008										 inst->operand.source->physical_reg->regno, 
1009										 ARMCOND_AL);
1010			else
1011				ARM_DPIOP_REG_REG_COND(gen->cseg, 
1012									   opcode, 
1013									   inst->dest_value->physical_reg->regno, 
1014									   inst->source->physical_reg->regno, 
1015									   inst->operand.source->physical_reg->regno, 
1016									   ARMCOND_AL);
1017
1018			break;
1019			
1020		case cg_inst_arm_binary_immed:
1021			shift = calc_arm_mov_const_shift(inst->operand.immed);
1022			assert((shift & 0x80000001) != 1 && shift >= 0);
1023
1024			if (update_flags)
1025				ARM_DPIOP_S_REG_IMM8ROT_COND(gen->cseg, 
1026											 opcode, 
1027											 inst->dest_value->physical_reg->regno, 
1028											 inst->source->physical_reg->regno, 
1029											 inst->operand.immed >> ((32 - shift) & 31), shift,
1030											 ARMCOND_AL);
1031			else
1032				ARM_DPIOP_REG_IMM8ROT_COND(gen->cseg, 
1033										   opcode, 
1034										   inst->dest_value->physical_reg->regno, 
1035										   inst->source->physical_reg->regno, 
1036										   inst->operand.immed >> ((32 - shift) & 31), shift,
1037										   ARMCOND_AL);
1038
1039			break;
1040			
1041		case cg_inst_arm_binary_shift_reg:
1042			if (update_flags)
1043				ARM_DPIOP_S_REG_REGSHIFT_COND(gen->cseg, 
1044											  opcode, 
1045											  inst->dest_value->physical_reg->regno, 
1046											  inst->source->physical_reg->regno, 
1047											  inst->operand.shift_reg.source->physical_reg->regno, 
1048											  arm_shift_type(inst->operand.shift_reg.op),
1049											  inst->operand.shift_reg.shift->physical_reg->regno, 
1050											  ARMCOND_AL);
1051			else
1052				ARM_DPIOP_REG_REGSHIFT_COND(gen->cseg, 
1053											opcode, 
1054											inst->dest_value->physical_reg->regno, 
1055											inst->source->physical_reg->regno, 
1056											inst->operand.shift_reg.source->physical_reg->regno, 
1057											arm_shift_type(inst->operand.shift_reg.op),
1058											inst->operand.shift_reg.shift->physical_reg->regno, 
1059											ARMCOND_AL);
1060
1061			break;
1062			
1063		case cg_inst_arm_binary_shift_immed:
1064			if (update_flags)
1065				ARM_DPIOP_S_REG_IMMSHIFT_COND(gen->cseg, 
1066											  opcode, 
1067											  inst->dest_value->physical_reg->regno, 
1068											  inst->source->physical_reg->regno, 
1069											  inst->operand.shift_immed.source->physical_reg->regno, 
1070											  arm_shift_type(inst->operand.shift_immed.op),
1071											  inst->operand.shift_immed.shift, 
1072											  ARMCOND_AL);
1073			else
1074				ARM_DPIOP_REG_IMMSHIFT_COND(gen->cseg, 
1075											opcode, 
1076											inst->dest_value->physical_reg->regno, 
1077											inst->source->physical_reg->regno, 
1078											inst->operand.shift_immed.source->physical_reg->regno, 
1079											arm_shift_type(inst->operand.shift_immed.op),
1080											inst->operand.shift_immed.shift, 
1081											ARMCOND_AL);
1082
1083			break;
1084			
1085		default:
1086			assert(0);
1087	}
1088}
1089
1090
1091static void emit_binary_multiply_int(cg_codegen_t * gen, cg_inst_binary_t * inst,
1092									 int update_flags)
1093{
1094	assert(inst->base.kind == cg_inst_binary);
1095	
1096	if (update_flags)
1097		ARM_MULS(gen->cseg, 
1098				 inst->dest_value->physical_reg->regno, 
1099				 inst->source->physical_reg->regno, 
1100				 inst->operand.source->physical_reg->regno);
1101	else
1102		ARM_MUL(gen->cseg, 
1103				inst->dest_value->physical_reg->regno, 
1104				inst->source->physical_reg->regno, 
1105				inst->operand.source->physical_reg->regno);
1106
1107}
1108
1109
1110static void emit_binary_multiply_fixed(cg_codegen_t * gen, cg_inst_binary_t * inst,
1111									   int update_flags)
1112{
1113	// alloacte a temporary register
1114	cg_virtual_reg_t temp_reg;
1115	cg_physical_reg_t * temp_physical_reg;
1116	U32 mask;
1117
1118	assert(inst->base.kind == cg_inst_binary);
1119	
1120	memset(&temp_reg, 0, sizeof temp_reg);
1121	
1122	/* may need to create a mask based on the registers allocated for		*/
1123	/* the other operands													*/
1124	mask = ~((1u << inst->dest_value->physical_reg->regno)  |
1125			 (1u << inst->source->physical_reg->regno)		|
1126			 (1u << inst->operand.source->physical_reg->regno));
1127	
1128	temp_physical_reg = allocate_reg(gen, &temp_reg, mask);
1129	assign_reg(gen, temp_physical_reg, &temp_reg);
1130	
1131	ARM_SMULL(gen->cseg, 
1132			  inst->dest_value->physical_reg->regno, 
1133			  temp_physical_reg->regno, 
1134			  inst->source->physical_reg->regno, 
1135			  inst->operand.source->physical_reg->regno);
1136	
1137	ARM_MOV_REG_IMMSHIFT(gen->cseg,
1138						 inst->dest_value->physical_reg->regno,
1139						 inst->dest_value->physical_reg->regno,
1140						 ARMSHIFT_LSR,
1141						 16);
1142	
1143	if (update_flags)
1144		ARM_ORRS_REG_IMMSHIFT(gen->cseg,
1145							  inst->dest_value->physical_reg->regno,
1146							  inst->dest_value->physical_reg->regno,
1147							  temp_physical_reg->regno, 
1148							  ARMSHIFT_LSL,
1149							  16);
1150	else
1151		ARM_ORR_REG_IMMSHIFT(gen->cseg,
1152							inst->dest_value->physical_reg->regno,
1153							inst->dest_value->physical_reg->regno,
1154							temp_physical_reg->regno, 
1155							ARMSHIFT_LSL,
1156							16);
1157
1158	
1159	// release the temporary register
1160	deallocate_reg(gen, temp_physical_reg);
1161}
1162
1163
1164static void emit_binary_minmax(cg_codegen_t * gen, cg_inst_binary_t * inst, int update_flags)
1165{
1166	ARMCond condition;
1167	ARMCond neg_condition;
1168	int shift;
1169
1170	assert(!update_flags);
1171
1172	emit_binary_regular(gen, inst, ARMOP_CMP, 1);
1173
1174	switch (inst->base.opcode) {
1175	case cg_op_min:
1176		condition = ARMCOND_LE;
1177		neg_condition = ARMCOND_GT;
1178		break;
1179
1180	case cg_op_max:
1181		condition = ARMCOND_GE;
1182		neg_condition = ARMCOND_LT;
1183		break;
1184
1185	default:
1186		assert(0);
1187		break;
1188	}
1189
1190	if (inst->dest_value->physical_reg->regno != inst->source->physical_reg->regno) {
1191		ARM_MOV_REG_REG_COND(gen->cseg,
1192							 inst->dest_value->physical_reg->regno,
1193							 inst->source->physical_reg->regno,
1194							 condition);
1195	}
1196	
1197	/*ARM_MOV_REG_REG_COND(gen->cseg,
1198						 inst->dest_value->physical_reg->regno,
1199						 inst->operand.source->physical_reg->regno,
1200						 neg_condition);*/
1201					
1202	switch (inst->base.kind)
1203	{
1204		case cg_inst_binary:
1205			ARM_DPIOP_REG_REG_COND(gen->cseg, 
1206								   ARMOP_MOV, 
1207								   inst->dest_value->physical_reg->regno, 
1208								   0, 
1209								   inst->operand.source->physical_reg->regno, 
1210								   neg_condition);
1211
1212			break;
1213			
1214		case cg_inst_arm_binary_immed:
1215			shift = calc_arm_mov_const_shift(inst->operand.immed);
1216			assert((shift & 0x80000001) != 1 && shift >= 0);
1217
1218			ARM_DPIOP_REG_IMM8ROT_COND(gen->cseg, 
1219									   ARMOP_MOV, 
1220									   inst->dest_value->physical_reg->regno, 
1221									   0, 
1222									   inst->operand.immed >> ((32 - shift) & 31), shift,
1223									   neg_condition);
1224
1225			break;
1226			
1227		case cg_inst_arm_binary_shift_reg:
1228			ARM_DPIOP_REG_REGSHIFT_COND(gen->cseg, 
1229										ARMOP_MOV, 
1230										inst->dest_value->physical_reg->regno, 
1231									    0, 
1232										inst->operand.shift_reg.source->physical_reg->regno, 
1233										arm_shift_type(inst->operand.shift_reg.op),
1234										inst->operand.shift_reg.shift->physical_reg->regno, 
1235										neg_condition);
1236
1237			break;
1238			
1239		case cg_inst_arm_binary_shift_immed:
1240			ARM_DPIOP_REG_IMMSHIFT_COND(gen->cseg, 
1241										ARMOP_MOV, 
1242										inst->dest_value->physical_reg->regno, 
1243										0, 
1244										inst->operand.shift_immed.source->physical_reg->regno, 
1245										arm_shift_type(inst->operand.shift_immed.op),
1246										inst->operand.shift_immed.shift, 
1247										neg_condition);
1248
1249			break;
1250			
1251		default:
1252			assert(0);
1253	}
1254}
1255
1256
1257static void emit_binary(cg_codegen_t * gen, cg_inst_binary_t * inst, int update_flags)
1258{
1259	// distinguish operations that map directly to ARM instructions
1260	// shifter-type instructions (MOV plus shifter operand)
1261	// operations that require sequence of instructions
1262	// operations that map into a function call
1263
1264	switch (inst->base.opcode)
1265	{
1266		/* shifter type */
1267		case cg_op_asr:
1268		case cg_op_lsl:
1269		case cg_op_lsr:
1270			emit_binary_shifter(gen, inst, update_flags);
1271			break;
1272	
1273		/* regular binary operation */
1274		case cg_op_add:
1275		case cg_op_fadd:
1276			emit_binary_regular(gen, inst, ARMOP_ADD, update_flags);
1277			break;
1278			
1279		case cg_op_sub:
1280		case cg_op_fsub:
1281			emit_binary_regular(gen, inst, ARMOP_SUB, update_flags);
1282			break;
1283			
1284		case cg_op_and:
1285			emit_binary_regular(gen, inst, ARMOP_AND, update_flags);
1286			break;
1287			
1288		case cg_op_or:
1289			emit_binary_regular(gen, inst, ARMOP_ORR, update_flags);
1290			break;
1291			
1292		case cg_op_xor:
1293			emit_binary_regular(gen, inst, ARMOP_EOR, update_flags);
1294			break;
1295	
1296		/* multiplication */
1297		case cg_op_mul:
1298			emit_binary_multiply_int(gen, inst, update_flags);
1299			break;
1300			
1301		case cg_op_fmul:
1302			emit_binary_multiply_fixed(gen, inst, update_flags);
1303			break;
1304			
1305		/* min and max */
1306		case cg_op_min:
1307		case cg_op_max:
1308			emit_binary_minmax(gen, inst, update_flags);
1309			break;
1310
1311		default:
1312			assert(0);
1313	}
1314}
1315
1316
1317static void emit_compare(cg_codegen_t * gen, cg_inst_compare_t * inst)
1318{
1319	ARMShiftType shift_type;
1320	int shift;
1321	
1322	assert(inst->base.opcode == cg_op_cmp ||
1323		   inst->base.opcode == cg_op_fcmp);
1324	
1325	switch (inst->base.kind)
1326	{
1327		case cg_inst_compare:
1328			ARM_CMP_REG_REG(gen->cseg, 
1329							inst->source->physical_reg->regno,
1330							inst->operand.source->physical_reg->regno);
1331			break;
1332			
1333		case cg_inst_arm_compare_immed:
1334			shift = calc_arm_mov_const_shift(inst->operand.immed);
1335
1336			if ((shift & 0x80000001) != 1) {
1337				if (shift >= 0) {
1338					ARM_CMP_REG_IMM(gen->cseg, inst->source->physical_reg->regno, inst->operand.immed >> ((32 - shift) & 31), shift);
1339				} else {
1340					ARM_CMN_REG_IMM(gen->cseg, inst->source->physical_reg->regno, (inst->operand.immed ^ (~0)) >> ((32 + 2 + shift) & 31), (-shift - 2));
1341				}
1342			} else {
1343				assert(0);
1344			}
1345
1346			break;
1347			
1348		case cg_inst_arm_compare_shift_reg:
1349			shift_type = arm_shift_type(inst->operand.shift_reg.op);
1350			
1351			ARM_CMP_REG_REGSHIFT(gen->cseg, 
1352								 inst->source->physical_reg->regno, 
1353								 inst->operand.shift_reg.source->physical_reg->regno, 
1354								 shift_type, 
1355								 inst->operand.shift_reg.shift->physical_reg->regno);
1356			break;
1357			
1358		case cg_inst_arm_compare_shift_immed:
1359			shift_type = arm_shift_type(inst->operand.shift_immed.op);
1360			
1361			ARM_CMP_REG_IMMSHIFT(gen->cseg, 
1362								 inst->source->physical_reg->regno, 
1363								 inst->operand.shift_immed.source->physical_reg->regno, 
1364								 shift_type, 
1365								 inst->operand.shift_immed.shift);
1366			break;
1367			
1368		default:
1369			assert(0);
1370	}
1371}
1372
1373
1374static void emit_load(cg_codegen_t * gen, cg_inst_load_t * inst) 
1375{
1376	switch (inst->base.opcode)
1377	{
1378		case cg_op_ldb:
1379			switch (inst->base.kind)
1380			{
1381				case cg_inst_load:
1382					ARM_LDRB_IMM(gen->cseg, inst->dest->physical_reg->regno, 
1383								 inst->mem.base->physical_reg->regno, 0);
1384					break;
1385					
1386				case cg_inst_arm_load_immed_offset:
1387					ARM_LDRB_IMM(gen->cseg, inst->dest->physical_reg->regno, 
1388								 inst->mem.immed_offset.base->physical_reg->regno, 
1389								 inst->mem.immed_offset.offset);
1390					break;
1391					
1392				case cg_inst_arm_load_reg_offset:
1393					ARM_LDRB_REG_REG(gen->cseg, inst->dest->physical_reg->regno, 
1394									 inst->mem.reg_offset.base->physical_reg->regno, 
1395									 inst->mem.reg_offset.offset->physical_reg->regno);
1396					break;
1397					
1398				default:
1399					assert(0);
1400			}
1401			
1402			break;
1403			
1404		case cg_op_ldh:
1405			switch (inst->base.kind)
1406			{
1407				case cg_inst_load:
1408					ARM_LDRH_IMM(gen->cseg, inst->dest->physical_reg->regno, 
1409								 inst->mem.base->physical_reg->regno, 0);
1410					break;
1411					
1412				case cg_inst_arm_load_immed_offset:
1413					ARM_LDRH_IMM(gen->cseg, inst->dest->physical_reg->regno, 
1414								 inst->mem.immed_offset.base->physical_reg->regno, 
1415								 inst->mem.immed_offset.offset);
1416					break;
1417					
1418				case cg_inst_arm_load_reg_offset:
1419					ARM_LDRH_REG_REG(gen->cseg, inst->dest->physical_reg->regno, 
1420									 inst->mem.reg_offset.base->physical_reg->regno, 
1421									 inst->mem.reg_offset.offset->physical_reg->regno);
1422					break;
1423					
1424				default:
1425					assert(0);
1426			}
1427			
1428			break;
1429			
1430		case cg_op_ldw:
1431			switch (inst->base.kind)
1432			{
1433				case cg_inst_load:
1434					ARM_LDR_IMM(gen->cseg, inst->dest->physical_reg->regno, 
1435								inst->mem.base->physical_reg->regno, 0);
1436					break;
1437					
1438				case cg_inst_arm_load_immed_offset:
1439					ARM_LDR_IMM(gen->cseg, inst->dest->physical_reg->regno, 
1440								inst->mem.immed_offset.base->physical_reg->regno, 
1441								inst->mem.immed_offset.offset);
1442					break;
1443					
1444				case cg_inst_arm_load_reg_offset:
1445					ARM_LDR_REG_REG(gen->cseg, inst->dest->physical_reg->regno, 
1446									inst->mem.reg_offset.base->physical_reg->regno, 
1447									inst->mem.reg_offset.offset->physical_reg->regno);
1448					break;
1449					
1450				default:
1451					assert(0);
1452			}
1453			
1454			break;
1455			
1456		default:
1457			assert(0);
1458	}
1459}
1460
1461
1462static void emit_store(cg_codegen_t * gen, cg_inst_store_t * inst)
1463{
1464	switch (inst->base.opcode)
1465	{
1466		case cg_op_stb:
1467			switch (inst->base.kind)
1468			{
1469				case cg_inst_store:
1470					ARM_STRB_IMM(gen->cseg, inst->source->physical_reg->regno, 
1471								 inst->mem.base->physical_reg->regno, 0);
1472					break;
1473					
1474				case cg_inst_arm_store_immed_offset:
1475					ARM_STRB_IMM(gen->cseg, inst->source->physical_reg->regno, 
1476								 inst->mem.immed_offset.base->physical_reg->regno, 
1477								 inst->mem.immed_offset.offset);
1478					break;
1479					
1480				case cg_inst_arm_store_reg_offset:
1481					ARM_STRB_REG_REG(gen->cseg, inst->source->physical_reg->regno, 
1482									 inst->mem.reg_offset.base->physical_reg->regno, 
1483									 inst->mem.reg_offset.offset->physical_reg->regno);
1484					break;
1485					
1486				default:
1487					assert(0);
1488			}
1489			
1490			break;
1491			
1492		case cg_op_sth:
1493			switch (inst->base.kind)
1494			{
1495				case cg_inst_store:
1496					ARM_STRH_IMM(gen->cseg, inst->source->physical_reg->regno, 
1497								 inst->mem.base->physical_reg->regno, 0);
1498					break;
1499					
1500				case cg_inst_arm_store_immed_offset:
1501					ARM_STRH_IMM(gen->cseg, inst->source->physical_reg->regno, 
1502								 inst->mem.immed_offset.base->physical_reg->regno, 
1503								 inst->mem.immed_offset.offset);
1504					break;
1505					
1506				case cg_inst_arm_store_reg_offset:
1507					ARM_STRH_REG_REG(gen->cseg, inst->source->physical_reg->regno, 
1508									 inst->mem.reg_offset.base->physical_reg->regno, 
1509									 inst->mem.reg_offset.offset->physical_reg->regno);
1510					break;
1511					
1512				default:
1513					assert(0);
1514			}
1515			
1516			break;
1517			
1518		case cg_op_stw:
1519			switch (inst->base.kind)
1520			{
1521				case cg_inst_store:
1522					ARM_STR_IMM(gen->cseg, inst->source->physical_reg->regno, 
1523								inst->mem.base->physical_reg->regno, 0);
1524					break;
1525					
1526				case cg_inst_arm_store_immed_offset:
1527					ARM_STR_IMM(gen->cseg, inst->source->physical_reg->regno, 
1528								inst->mem.immed_offset.base->physical_reg->regno, 
1529								inst->mem.immed_offset.offset);
1530					break;
1531					
1532				case cg_inst_arm_store_reg_offset:
1533					ARM_STR_REG_REG(gen->cseg, inst->source->physical_reg->regno, 
1534									inst->mem.reg_offset.base->physical_reg->regno, 
1535									inst->mem.reg_offset.offset->physical_reg->regno);
1536					break;
1537					
1538				default:
1539					assert(0);
1540			}
1541			
1542			break;
1543			
1544		default:
1545			assert(0);
1546	}
1547}
1548
1549
1550static void emit_load_immediate(cg_codegen_t * gen, 
1551								cg_inst_load_immed_t * inst)
1552{
1553	assert(inst->base.opcode == cg_op_ldi);
1554	
1555	arm_mov_reg_imm32(gen->cseg, inst->dest->physical_reg->regno,
1556					  inst->value);
1557}
1558
1559static void flush_dirty_regs(cg_codegen_t * gen, cg_bitset_t * live);
1560static void flush_dirty_args(cg_codegen_t * gen);
1561
1562static void emit_branch(cg_codegen_t * gen, cg_inst_branch_t * inst)
1563{
1564	ARMCond cond;
1565	flush_dirty_regs(gen, inst->target->block->live_in);
1566	
1567	switch (inst->base.kind) 
1568	{
1569		case cg_inst_branch_label:
1570			assert(inst->base.opcode == cg_op_bra);
1571			branch(gen, inst->target->block->label);
1572			return;
1573			
1574		case cg_inst_branch_cond:
1575			/* ensure condition flag is bound to virtual reg.				*/
1576			
1577			switch (inst->base.opcode) 
1578			{
1579				case cg_op_beq:		cond = ARMCOND_EQ; break;
1580				case cg_op_bge:		cond = ARMCOND_GE; break;
1581				case cg_op_ble:		cond = ARMCOND_LE; break;
1582				case cg_op_bgt:		cond = ARMCOND_GT; break;
1583				case cg_op_blt:		cond = ARMCOND_LT; break;
1584				case cg_op_bne:		cond = ARMCOND_NE; break;
1585				case cg_op_bra:		cond = ARMCOND_AL; break;
1586				case cg_op_nop:		cond = ARMCOND_NV; break;
1587					
1588				default:
1589					assert(0);
1590			}
1591			
1592			branch_cond(gen, inst->target->block->label, cond);
1593			break;
1594			
1595		default:
1596			assert(0);
1597	}
1598}
1599
1600
1601static void emit_call(cg_codegen_t * gen, cg_inst_call_t * inst)
1602{
1603	call(gen, inst->proc->prologue, inst->args, (cg_inst_t *) inst);
1604	
1605	// deal with results
1606	if (inst->dest)
1607	{
1608		cg_physical_reg_t * physical_reg = allocate_reg(gen, inst->dest, 1 << ARMREG_A1);
1609		assign_reg(gen, physical_reg, inst->dest);
1610		physical_reg->dirty = physical_reg->defined = 1;
1611	}
1612}
1613
1614
1615static void emit_ret(cg_codegen_t * gen, cg_inst_ret_t * inst)
1616{
1617	if (inst->result)
1618	{
1619		/********************************************************************/
1620		/* Make sure that result is in correct register						*/
1621		/********************************************************************/
1622		
1623		if (inst->result->physical_reg->regno != ARMREG_A1)
1624		{
1625			ARM_MOV_REG_REG(gen->cseg, ARMREG_A1, 
1626							inst->result->physical_reg->regno);
1627		}
1628	}
1629	
1630	if (inst->base.next || inst->base.block->next) 
1631	{
1632		/* if this is not the last instruction in its block, and it's not the last block of the procedure */
1633		branch(gen, inst->base.block->proc->epilogue);
1634	}
1635}
1636
1637
1638static void dispatch_inst(cg_codegen_t * gen, cg_inst_t * inst, int update_flags)
1639{
1640	switch (inst->base.kind) 
1641	{		
1642		case cg_inst_unary:		
1643		case cg_inst_arm_unary_immed:	
1644		case cg_inst_arm_unary_shift_reg:	
1645		case cg_inst_arm_unary_shift_immed:	
1646			emit_unary(gen, &inst->unary, update_flags);
1647			break;
1648			
1649		case cg_inst_binary:		
1650		case cg_inst_arm_binary_immed:	
1651		case cg_inst_arm_binary_shift_reg:	
1652		case cg_inst_arm_binary_shift_immed:	
1653			emit_binary(gen, &inst->binary, update_flags);
1654			break;
1655			
1656		case cg_inst_compare:	
1657		case cg_inst_arm_compare_immed:	
1658		case cg_inst_arm_compare_shift_reg:	
1659		case cg_inst_arm_compare_shift_immed:	
1660			emit_compare(gen, &inst->compare);
1661			break;
1662			
1663		case cg_inst_load:	
1664		case cg_inst_arm_load_immed_offset:	
1665		case cg_inst_arm_load_reg_offset:	
1666			emit_load(gen, &inst->load);
1667			break;
1668			
1669		case cg_inst_store:	
1670		case cg_inst_arm_store_immed_offset:	
1671		case cg_inst_arm_store_reg_offset:	
1672			emit_store(gen, &inst->store);
1673			break;
1674			
1675		case cg_inst_load_immed:
1676			emit_load_immediate(gen, &inst->immed);
1677			break;
1678			
1679		case cg_inst_branch_label:	
1680		case cg_inst_branch_cond:	
1681			emit_branch(gen, &inst->branch);
1682			break;
1683			
1684		case cg_inst_call:
1685			emit_call(gen, &inst->call);
1686			break;
1687			
1688		case cg_inst_ret:			
1689			emit_ret(gen, &inst->ret);
1690			break;
1691			
1692			// ARM specific formats
1693		case cg_inst_phi:	
1694		default:
1695			assert(0);
1696	}
1697	
1698}
1699
1700
1701static cg_physical_reg_t * spill_candidate(cg_codegen_t * gen, 
1702										cg_virtual_reg_t * reg, U32 mask)
1703	/************************************************************************/
1704	/* Determine a spill candidate because we need a register for the given */
1705	/* virtual register														*/
1706	/************************************************************************/
1707{
1708	// pick the register whose next use is most far away
1709	// if possible, select a register that is not dirty
1710	
1711	cg_physical_reg_t * physical_reg = gen->used_regs.tail;
1712	
1713	while (physical_reg != 0 && 
1714		   !((1u << physical_reg->regno) & mask)) 
1715	{
1716		physical_reg = physical_reg->prev;
1717	}
1718	
1719	return physical_reg;
1720}
1721
1722
1723static I32 fp_offset(cg_codegen_t * gen, cg_virtual_reg_t * reg) {
1724
1725	if (reg->fp_offset == ~0) {
1726
1727		if (reg->representative->fp_offset == ~0)
1728		{
1729			cg_proc_t * proc = gen->current_block->proc;
1730
1731			proc->local_storage += sizeof(U32);
1732			reg->representative->fp_offset = - (int) proc->local_storage - SAVE_AREA_SIZE;	
1733		}
1734
1735		reg->fp_offset = reg->representative->fp_offset;
1736	}
1737
1738	return reg->fp_offset;
1739}
1740
1741
1742static void save_reg(cg_codegen_t * gen, cg_physical_reg_t * physical_reg,
1743					 cg_virtual_reg_t * reg)
1744	/************************************************************************/
1745	/* Save a given physical register										*/
1746	/************************************************************************/
1747{
1748	assert(physical_reg->dirty);
1749	
1750	// generate code to save the register; reg -> FP + offset
1751	ARM_STR_IMM(gen->cseg, physical_reg->regno, ARMREG_FP, 
1752			    fp_offset(gen, reg));
1753	
1754	physical_reg->dirty = 0;
1755	
1756}
1757
1758
1759static void restore_reg(cg_codegen_t * gen, cg_physical_reg_t * physical_reg,
1760						cg_virtual_reg_t * reg)
1761	/************************************************************************/
1762	/* Restore a given physical register									*/
1763	/************************************************************************/
1764{
1765	assert(!physical_reg->defined);
1766	
1767	// generate code to save the register; FP + offset -> reg
1768	ARM_LDR_IMM(gen->cseg, physical_reg->regno, ARMREG_FP, 
1769				fp_offset(gen, reg));
1770	
1771	physical_reg->defined = 1;
1772	
1773}
1774
1775
1776static void deallocate_reg(cg_codegen_t * gen, cg_physical_reg_t * physical_reg)
1777	/************************************************************************/
1778	/* free up a register because it is no longer used						*/
1779	/************************************************************************/
1780{
1781	cg_virtual_reg_t * reg = physical_reg->virtual_reg;
1782
1783	int used;
1784	
1785	if (reg != 0 && reg->physical_reg == physical_reg)
1786	{
1787		//reg->physical_reg = (cg_physical_reg_t *) 0;
1788		
1789		used = CG_BITSET_TEST(gen->current_block->live_out, reg->reg_no) ||
1790			gen->use_chains[reg->reg_no];
1791		
1792		if (physical_reg->dirty && used)
1793		{
1794			save_reg(gen, physical_reg, reg);
1795		}
1796	}
1797		
1798	physical_reg->virtual_reg = (cg_virtual_reg_t *) 0;
1799
1800	if (physical_reg->list == &gen->used_regs) 
1801	{
1802		reg_list_remove(&gen->used_regs, physical_reg);
1803		reg_list_add(&gen->free_regs, physical_reg);
1804	}
1805
1806	assert(physical_reg->list == &gen->free_regs);
1807
1808	physical_reg->dirty = physical_reg->defined = 0;
1809}
1810
1811
1812static cg_physical_reg_t * allocate_reg(cg_codegen_t * gen, cg_virtual_reg_t * reg,
1813									 U32 mask)
1814	/************************************************************************/
1815	/* Allocate a specific physical register for a virtual register			*/
1816	/************************************************************************/
1817{
1818	cg_physical_reg_t * physical_reg;
1819	
1820	if (mask == 0)
1821	{
1822		mask = ~0u;
1823	}
1824	
1825	// check if the virtual register is already present in a matching
1826	// physical register
1827	// if so, return that register
1828	
1829	if (reg->representative)
1830		physical_reg = reg->representative->physical_reg;
1831	else
1832		physical_reg = reg->physical_reg;
1833	
1834	if (physical_reg != 0 && physical_reg->virtual_reg && physical_reg->virtual_reg->representative == reg->representative &&
1835		((1u << physical_reg->regno) & mask))
1836	{
1837		reg_list_move_to_front(physical_reg->list, physical_reg);
1838		return physical_reg;
1839	}
1840	
1841	physical_reg = gen->free_regs.tail;
1842
1843	while (physical_reg)
1844	{
1845		if ((1u << physical_reg->regno) & mask)
1846		{
1847			reg_list_remove(&gen->free_regs, physical_reg);
1848			reg_list_add(&gen->used_regs, physical_reg);
1849			return physical_reg;
1850		}
1851
1852		physical_reg = physical_reg->prev;
1853	}
1854
1855	// determine a spill candidate
1856	physical_reg = spill_candidate(gen, reg, mask);
1857	assert(physical_reg->list == &gen->used_regs);
1858	deallocate_reg(gen, physical_reg);
1859	assert(physical_reg->list == &gen->free_regs);
1860	reg_list_remove(&gen->free_regs, physical_reg);
1861	reg_list_add(&gen->used_regs, physical_reg);
1862		
1863	return physical_reg;
1864}
1865
1866
1867static void assign_reg(cg_codegen_t * gen,
1868					   cg_physical_reg_t * physical_reg, 
1869					   cg_virtual_reg_t * reg)
1870	/************************************************************************/
1871	/* Bind a specific physical register to a virtual register				*/
1872	/************************************************************************/
1873{
1874	// associate the physical register with the virtual register
1875	// but mark the register as no holding the value yet
1876
1877	if (physical_reg->virtual_reg != reg)
1878	{
1879		cg_virtual_reg_t * old_reg = physical_reg->virtual_reg;
1880
1881		physical_reg->virtual_reg = reg;
1882
1883		if (old_reg == NULL || reg->representative != old_reg->representative)
1884			physical_reg->defined = physical_reg->dirty = 0;
1885	}
1886
1887	if (reg->physical_reg == (cg_physical_reg_t *) 0 ||
1888		reg->physical_reg->virtual_reg != reg)
1889	{
1890		reg->physical_reg = physical_reg;
1891	}
1892		
1893}
1894
1895
1896static void ensure_loaded(cg_codegen_t * gen,
1897						  cg_physical_reg_t * physical_reg, 
1898						  cg_virtual_reg_t * reg)
1899	/************************************************************************/
1900	/* Allocate a specific physical register for a virtual register			*/
1901	/************************************************************************/
1902{
1903	assert(physical_reg->virtual_reg == reg);
1904	//assert(reg->physical_reg == physical_reg);
1905	
1906	if (!physical_reg->defined) 
1907	{
1908		if (reg->physical_reg != physical_reg && reg->physical_reg->defined)
1909		{
1910			reg_list_move_to_front(reg->physical_reg->list, reg->physical_reg);
1911			ARM_MOV_REG_REG(gen->cseg, physical_reg->regno, reg->physical_reg->regno);
1912			physical_reg->defined = 1;
1913		} 
1914		else 
1915		{
1916			assert(!physical_reg->dirty);
1917			restore_reg(gen, physical_reg, reg);
1918			assert(physical_reg->defined);
1919		}
1920	}
1921}
1922
1923
1924static void make_global(cg_codegen_t * gen, cg_physical_reg_t * reg)
1925{
1926	assert(reg->virtual_reg->is_global);
1927	assert(reg->list == &gen->used_regs);
1928
1929	reg_list_remove(reg->list, reg);
1930	reg_list_add(&gen->global_regs, reg);
1931}
1932
1933
1934static cg_physical_reg_t * load_reg(cg_codegen_t * gen, cg_virtual_reg_t * reg,
1935									 U32 mask)
1936{
1937	cg_physical_reg_t * physical_reg;
1938
1939	physical_reg = allocate_reg(gen, reg, mask);
1940	assign_reg(gen, physical_reg, reg);
1941	en

Large files files are truncated, but you can click here to view the full file