# Copyright 2011-2021 IBM Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
""":mod:`microprobe.passes.symbol` module
"""
# Futures
from __future__ import absolute_import, print_function
# Built-in modules
import copy
import itertools
import random
# Third party modules
# Own modules
import microprobe.code.ins
import microprobe.passes
import microprobe.utils.distrib
from microprobe.code.address import Address, InstructionAddress
from microprobe.code.ins import instruction_set_def_properties
from microprobe.code.var import Variable
from microprobe.exceptions import MicroprobeCodeGenerationError, \
MicroprobeUncheckableEnvironmentWarning
from microprobe.target.isa.instruction import InstructionType
from microprobe.utils.asm import interpret_asm
from microprobe.utils.distrib import generate_weighted_profile, \
weighted_choice
from microprobe.utils.logger import get_logger
from microprobe.utils.misc import RejectingDict, closest_divisor
# Local modules
# Constants
LOG = get_logger(__name__)
__all__ = [
'UpdateInstructionAddressesPass',
'SetInitAddressPass',
]
# Functions
# Classes
[docs]
class UpdateInstructionAddressesPass(microprobe.passes.Pass):
"""UpdateInstructionAddressesPass pass.
"""
[docs]
def __init__(self, force=False, noinit=False, init_from_first=False):
""" """
super(UpdateInstructionAddressesPass, self).__init__()
self._force = force
self._noinit = noinit
self._init_from_first = init_from_first
self._description = "Compute addresses. (Force: %s)" % force
def __call__(self, building_block, target):
"""
:param building_block:
:param target:
"""
if self._init_from_first:
caddress = building_block.cfg.bbls[0].instrs[0].address
if caddress is None:
raise NotImplementedError
for instr in reversed(building_block.init):
caddress = caddress - instr.architecture_type.format.length
instr.set_address(caddress.copy())
caddress = InstructionAddress(base_address="code", displacement=0)
# TODO: this is a hack, should not be done here. Once we implement
# a proper code generation back-end, this will be fixed
caddress += target.wrapper.init_main_pad()
if not self._noinit:
for instr in building_block.init:
instr.set_address(caddress.copy())
caddress += instr.architecture_type.format.length
# TODO: this is a hack, should not be done here. Once we implement
# a proper code generation back-end, this will be fixed
caddress += target.wrapper.init_loop_pad()
prev_bbl = None
for bbl in building_block.cfg.bbls:
if prev_bbl is not None:
LOG.debug(prev_bbl.address)
LOG.debug(prev_bbl.displacement)
LOG.debug(bbl.address)
LOG.debug(bbl.displacement)
if bbl.displacement > 0 and prev_bbl.displacement > 0:
# Relative displacement
bbl.set_address(
prev_bbl.address + (
bbl.displacement - prev_bbl.displacement
)
)
else:
bbl.set_address(caddress + bbl.displacement)
else:
bbl.set_address(caddress + bbl.displacement)
if caddress > bbl.address:
raise MicroprobeCodeGenerationError("Overlapping BBLs?")
caddress = bbl.address
for instr in bbl.instrs:
if instr.address is None or self._force:
instr.set_address(caddress.copy())
caddress += instr.architecture_type.format.length
else:
caddress = instr.address + \
instr.architecture_type.format.length
prev_bbl = bbl
for instr in building_block.fini:
instr.set_address(caddress.copy())
caddress += instr.architecture_type.format.length
# daddress = Address(base_address="data",
# displacement=0)
# for variable in building_block.registered_global_vars():
# LOG.debug(variable.address)
# daddress_var = daddress + variable.get_displacement()
# variable.set_address(daddress_var.copy())
return []
[docs]
def check(self, building_block, dummy_target):
"""
:param building_block:
:param dummy_target:
"""
pass_ok = True
caddress = InstructionAddress(base_address="code", displacement=0)
for instr in building_block.init:
pass_ok = pass_ok and caddress == instr.address
caddress += instr.architecture_type.format.length
for bbl in building_block.cfg.bbls:
for instr in bbl.instrs:
pass_ok = pass_ok and caddress == instr.address
caddress += instr.architecture_type.format.length
for instr in building_block.fini:
pass_ok = pass_ok and caddress == instr.address
caddress += instr.architecture_type.format.length
# daddress = Address(base_address="data",
# displacement=0)
# for variable in building_block.registered_global_vars():
# daddress += variable.get_displacement()
# pass_ok = variable.address == daddress
return pass_ok
[docs]
class SetInitAddressPass(microprobe.passes.Pass):
"""SetInitAddressPass pass.
"""
[docs]
def __init__(self, address):
""" """
super(SetInitAddressPass, self).__init__()
self._address = address
self._description = "Set initial address to 0x%X" % address
def __call__(self, building_block, target):
"""
:param building_block:
:param target:
"""
address = InstructionAddress(
base_address="code",
displacement=building_block.context.code_segment - self._address
)
for instr in building_block.init:
instr.set_address(address.copy())
return []
for bbl in building_block.cfg.bbls:
for instr in bbl.instrs:
instr.set_address(address.copy())
return []
for instr in building_block.fini:
instr.set_address(address.copy())
return []
return []
[docs]
def check(self, building_block, dummy_target):
"""
:param building_block:
:param dummy_target:
"""
address = InstructionAddress(
base_address="code",
displacement=building_block.context.code_segment - self._address
)
for instr in building_block.init:
return instr.address == address
for bbl in building_block.cfg.bbls:
for instr in bbl.instrs:
return instr.address == address
for instr in building_block.fini:
return instr.address == address
return False