Example #1
0
    def _set_bool(self, spotmap, get_reg, asm_code):
        """Emit code for SET command if arg is boolean type."""
        # When any scalar value is converted to _Bool, the result is 0 if the
        # value compares equal to 0; otherwise, the result is 1

        # If arg_asm is a LITERAL or conflicts with output, move to register.
        if (isinstance(spotmap[self.arg], LiteralSpot)
                or spotmap[self.arg] == spotmap[self.output]):
            r = get_reg([], [spotmap[self.output]])
            asm_code.add(
                asm_cmds.Mov(r, spotmap[self.arg], self.arg.ctype.size))
            arg_spot = r
        else:
            arg_spot = spotmap[self.arg]

        label = asm_code.get_label()
        output_spot = spotmap[self.output]

        zero = LiteralSpot("0")
        one = LiteralSpot("1")

        asm_code.add(asm_cmds.Mov(output_spot, zero, self.output.ctype.size))
        asm_code.add(asm_cmds.Cmp(arg_spot, zero, self.arg.ctype.size))
        asm_code.add(asm_cmds.Je(label))
        asm_code.add(asm_cmds.Mov(output_spot, one, self.output.ctype.size))
        asm_code.add(asm_cmds.Label(label))
Example #2
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        regs = []

        result = get_reg([spotmap[self.output]],
                         [spotmap[self.arg1], spotmap[self.arg2]])
        regs.append(result)

        out_size = self.output.ctype.size
        eq_val_spot = LiteralSpot(1)
        asm_code.add(asm_cmds.Mov(result, eq_val_spot, out_size))

        arg1_spot, arg2_spot = self._fix_both_literal_or_mem(
            spotmap[self.arg1], spotmap[self.arg2], regs, get_reg, asm_code)
        arg1_spot, arg2_spot = self._fix_either_literal64(
            arg1_spot, arg2_spot, regs, get_reg, asm_code)
        arg1_spot, arg2_spot = self._fix_literal_wrong_order(
            arg1_spot, arg2_spot)

        arg_size = self.arg1.ctype.size
        neq_val_spot = LiteralSpot(0)
        label = asm_code.get_label()

        asm_code.add(asm_cmds.Cmp(arg1_spot, arg2_spot, arg_size))
        asm_code.add(self.cmp_command()(label))
        asm_code.add(asm_cmds.Mov(result, neq_val_spot, out_size))
        asm_code.add(asm_cmds.Label(label))

        if result != spotmap[self.output]:
            asm_code.add(asm_cmds.Mov(spotmap[self.output], result, out_size))
Example #3
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102
        size = self.cond.ctype.size

        if isinstance(spotmap[self.cond], LiteralSpot):
            r = get_reg()
            asm_code.add(asm_cmds.Mov(r, spotmap[self.cond], size))
            cond_spot = r
        else:
            cond_spot = spotmap[self.cond]

        zero_spot = LiteralSpot("0")
        asm_code.add(asm_cmds.Cmp(cond_spot, zero_spot, size))
        asm_code.add(self.command(self.label))
Example #4
0
    def make_asm(self, spotmap, home_spots, get_reg, asm_code):  # noqa D102

        arg1_spot = spotmap[self.arg1]
        arg2_spot = spotmap[self.arg2]
        output_spot = spotmap[self.output]
        r12_spot = spots.RegSpot("r12")
        r13_spot = spots.RegSpot("r13")
        label = asm_code.get_label()

        # this stays here until I removed size from all functions
        size = None

        # start with setting the output reg to 1, in case of success
        asm_code.add(asm_cmds.Load(LiteralSpot(1), output_spot, size))

        self.move(arg1_spot, r12_spot, asm_code)
        self.move(arg2_spot, r13_spot, asm_code)

        # swap args when using less than instructions (to convert to gte's)
        if self.reverse_less_cmd:
            asm_code.add(self.cmp_command()(r12_spot, r13_spot,
                                            LiteralSpot(2)))
        else:
            asm_code.add(self.cmp_command()(r13_spot, r12_spot,
                                            LiteralSpot(2)))
        #not bgt r12 r0 2 -> bge r0 r12 2
        #not bge r12 r0 2 -> bgt r0 r12 2

        #not beq r12 r0 2 -> bne r0 r12 2
        #not bne r12 r0 2 -> beq r0 r12 2

        asm_code.add(asm_cmds.Jump(label))

        # in case the comparison was unsuccessful, set output reg to 0
        asm_code.add(asm_cmds.Load(LiteralSpot(0), output_spot, size))

        asm_code.add(asm_cmds.Label(label))
Example #5
0
    def _generate_asm(self, commands, live_vars, spotmap):
        """Generate assembly code."""

        # This is kinda hacky...
        max_offset = max(spot.rbp_offset() for spot in spotmap.values())
        #if max_offset % 16 != 0:
        #    max_offset += 16 - max_offset % 16

        # Back up rbp and move rsp

        #self.asm_code.add(asm_cmds.Push(spots.RBP, None, 8))
        self.asm_code.add(asm_cmds.Sub(spots.RSP, spots.LiteralSpot(1)))
        self.asm_code.add(asm_cmds.Write(spots.RSP, spots.RBP))

        self.asm_code.add(asm_cmds.Mov(spots.RBP, spots.RSP))

        offset_spot = LiteralSpot(str(max_offset))

        self.asm_code.add(asm_cmds.Sub(spots.RSP, offset_spot))

        # Generate code for each command
        for i, command in enumerate(commands):
            self.asm_code.add(asm_cmds.Comment(type(command).__name__.upper()))

            def get_reg(pref=None, conf=None):
                if not pref: pref = []
                if not conf: conf = []

                # Spot is bad if it is containing a variable that is live both
                # entering and exiting this command.
                bad_vars = set(live_vars[i][0]) & set(live_vars[i][1])
                bad_spots = set(spotmap[var] for var in bad_vars)

                # Spot is free if it is where an output is stored.
                for v in command.outputs():
                    bad_spots.discard(spotmap[v])

                # Spot is bad if it is listed as a conflicting spot.
                bad_spots |= set(conf)

                for s in (pref + self.all_registers):
                    if isinstance(s, RegSpot) and s not in bad_spots:
                        return s

                raise NotImplementedError("spill required for get_reg")

            command.make_asm(spotmap, spotmap, get_reg, self.asm_code)
Example #6
0
    def _get_global_spotmap(self):
        """Generate global spotmap and free values.

        Returns a tuple. First element is a dictionary mapping ILValue to
        spot for spots which do not need register allocation, like static
        variables or literals. The second element is a list of the free
        values; the variables which were not mapped in the global spotmap.
        """

        global_spotmap = {}
        free_values = []
        all_values = self._all_il_values()

        string_literal_number = 0
        for value in all_values:
            if value in self.il_code.literals:
                # If literal, assign it a preassigned literal spot
                s = LiteralSpot(self.il_code.literals[value])
                global_spotmap[value] = s
            elif value in self.il_code.externs:
                # If extern, assign assign spot and add the extern to asm code
                s = MemSpot(self.il_code.externs[value])
                global_spotmap[value] = s

                self.asm_code.add_extern(self.il_code.externs[value])
            elif value in self.il_code.string_literals:
                # Add the string literal representation to the output ASM.
                name = f"__strlit{string_literal_number}"
                string_literal_number += 1

                self.asm_code.add_string_literal(
                    name, self.il_code.string_literals[value])
                global_spotmap[value] = MemSpot(name)
            elif (self.arguments.variables_on_stack
                  and value in self.il_code.variables):  # pragma: no cover
                # If all variables are allocated on the stack
                self.offset += value.ctype.size
                s = MemSpot(spots.RBP, -self.offset)
                global_spotmap[value] = s
            else:
                # Value is free and needs an assignment
                free_values.append(value)

        return global_spotmap, free_values
Example #7
0
    def _get_nondynamic_spot(self, v, num):
        """Get a spot for non-dynamic values.

        In particular, assigns a spot to all literals, string literals,
        variables with no storage, and variables with static storage.

        v - value to get a spot for, or None if the value goes in a dynamic
        spot like a register
        nnum - positive integer guaranteed never to be the same for two
        distinct calls to this function
        """
        EXTERNAL = self.symbol_table.EXTERNAL
        INTERNAL = self.symbol_table.INTERNAL
        TENTATIVE = self.symbol_table.TENTATIVE

        if v in self.il_code.literals:
            return LiteralSpot(self.il_code.literals[v])

        elif v in self.il_code.string_literals:
            name = f"__strlit{num}"
            self.asm_code.add_string_literal(name,
                                             self.il_code.string_literals[v])
            return MemSpot(name)

        # Values with no storage can be referenced directly by name
        elif not self.symbol_table.storage.get(v, True):
            return MemSpot(self.symbol_table.names[v])

        elif self.symbol_table.storage.get(v) == self.symbol_table.STATIC:
            name = self.symbol_table.names[v]
            if self.symbol_table.linkage_type.get(v) != EXTERNAL:
                name = f"{name}.{num}"

            if self.symbol_table.def_state.get(v) == TENTATIVE:
                local = (self.symbol_table.linkage_type[v] == INTERNAL)
                self.asm_code.add_comm(name, v.ctype.size, local)
            else:
                init_val = self.il_code.static_inits.get(v, 0)
                self.asm_code.add_data(name, v.ctype.size, init_val)

            return MemSpot(name)