def handle_prologue(self, func_name, *operands): """Handles the prologue of the function definition in IR. """ self.memory_offset = 0 # Allocate memory for both the defined variables and the formal parameters. # Symbol table will have entry for all of them. for symtab_entry in self.ir.local_symbol_table.values(): if 'memory' in symtab_entry: symtab_entry['memory'].offset = self.memory_offset symtab_entry['memory'].size = MEMORY_WIDTH symtab_entry['memory'].base = 0 self.memory_offset += MEMORY_WIDTH elif symtab_entry.get('dimensions'): if 'memory' not in symtab_entry: symtab_entry['memory'] = Memory() symtab_entry['memory'].offset = self.memory_offset total_size = 1 for dimension in symtab_entry['dimensions']: total_size *= dimension symtab_entry['memory'].size = total_size * MEMORY_WIDTH symtab_entry['memory'].base = 0 self.memory_offset += total_size * MEMORY_WIDTH self.create_stack()
def allocate_global_memory(global_symbol_table): """Allocate memory for global datastructures. Args: global_symbol_table: Dictionary containing the global symbol table whose keys are symbol names and values are symbol table data like memory object for this symbol and type. """ memory_offset = 0 for symbol, symtab_entry in global_symbol_table.iteritems(): if symtab_entry.get('type') == 'function_name' or ( symbol in ['InputNum', 'OutputNum', 'OutputNewLine']): # These symbols are function names, don't do anything for them here. continue elif symtab_entry.get('dimensions', None) != None: # This entry is an array if 'memory' not in symtab_entry: symtab_entry['memory'] = Memory() symtab_entry['memory'].offset = memory_offset total_size = 1 for dimension in symtab_entry['dimensions']: total_size *= dimension symtab_entry['memory'].size = total_size * MEMORY_WIDTH symtab_entry['memory'].base = 'rip' memory_offset += total_size * MEMORY_WIDTH else: # This entry is a regular integer. if 'memory' not in symtab_entry: symtab_entry['memory'] = Memory() symtab_entry['memory'].offset = memory_offset symtab_entry['memory'].size = MEMORY_WIDTH symtab_entry['memory'].base = 'rip' memory_offset += MEMORY_WIDTH return memory_offset
def handle_store(self, label, result, *operands): """Handles the store instruction of IR. """ if isinstance(operands[1], Immediate) and isinstance(operands[2], Memory): memory = Memory( base=operands[2].base, offset=operands[2].offset + (operands[1].value * MEMORY_WIDTH)) elif isinstance(operands[1], Register): memory = Memory() memory.base = operands[2] memory.offset = operands[1] elif isinstance(operands[1], Memory): memory = operands[1] memory.offset = self.memory_offset self.memory_offset += MEMORY_WIDTH if isinstance(operands[0], Memory) or (isinstance(operands[0], Register) and isinstance(operands[0].color, Memory)): # Take the set difference free_registers = (REGISTERS_COLOR_SET - set(self.instruction_live_registers[label].keys())) if free_registers: # Create a dummy register for this color register = Register() # pop and add back since sets don't support indexing register.color = free_registers.pop() free_registers.add(register.color) mov1 = MOV(register, operands[0]) self.add_instruction(label, mov1) mov2 = MOV(memory, register) self.add_instruction(label, mov2) else: # We don't have any free registers :( # We can't do much, randomly pick a register, push it to the stack, # do the memory move from the source to this register and then use # this register to move the source to the destination and then # pop back our register. # NOTE: We pick %rax for this temporary operation # Create a dummy register for %rax register = Register() register.color = 0 push = PUSH(register) self.add_instruction(label, push) mov1 = MOV(register, operands[0]) self.add_instruction(label, mov1) mov2 = MOV(memory, register) self.add_instruction(label, mov2) pop = POP(register) self.add_instruction(label, pop) else: register = operands[0] mov = MOV(memory, register) self.add_instruction(label, mov)