def _process(self):
        """Parses the raw string data from LLVM timing report and attempts
        to improve the data by recomputing the times
        (See `_adjust_timings()``).
        """

        def parse(raw_data):
            """A generator that parses the raw_data line-by-line to extract
            timing information for each pass.
            """
            lines = raw_data.splitlines()
            colheader = r"[a-zA-Z+ ]+"
            # Take at least one column header.
            multicolheaders = fr"(?:\s*-+{colheader}-+)+"

            line_iter = iter(lines)
            # find column headers
            header_map = {
                "User Time": "user",
                "System Time": "system",
                "User+System": "user_system",
                "Wall Time": "wall",
                "Instr": "instruction",
                "Name": "pass_name",
            }
            for ln in line_iter:
                m = re.match(multicolheaders, ln)
                if m:
                    # Get all the column headers
                    raw_headers = re.findall(r"[a-zA-Z][a-zA-Z+ ]+", ln)
                    headers = [header_map[k.strip()] for k in raw_headers]
                    break

            assert headers[-1] == 'pass_name'
            # compute the list of available attributes from the column headers
            attrs = []
            n = r"\s*((?:[0-9]+\.)?[0-9]+)"
            pat = ""
            for k in headers[:-1]:
                if k == "instruction":
                    pat += n
                else:
                    attrs.append(f"{k}_time")
                    attrs.append(f"{k}_percent")
                    pat += rf"\s+(?:{n}\s*\({n}%\)|-+)"

            # put default value 0.0 to all missing attributes
            missing = {}
            for k in PassTimingRecord._fields:
                if k not in attrs and k != 'pass_name':
                    missing[k] = 0.0
            # parse timings
            pat += r"\s*(.*)"
            for ln in line_iter:
                m = re.match(pat, ln)
                if m is not None:
                    raw_data = list(m.groups())
                    data = {k: float(v) if v is not None else 0.0
                            for k, v in zip(attrs, raw_data)}
                    data.update(missing)
                    pass_name = raw_data[-1]
                    rec = PassTimingRecord(
                        pass_name=pass_name, **data,
                    )
                    yield rec
                    if rec.pass_name == "Total":
                        # "Total" means the report has ended
                        break
            # Check that we have reach the end of the report
            remaining = '\n'.join(line_iter)

            # FIXME: Need to handle parsing of Analysis execution timing report
            if "Analysis execution timing report" in remaining:
                return

            if remaining:
                raise ValueError(
                    f"unexpected text after parser finished:\n{remaining}"
                )

        # Parse raw data
        records = list(parse(self._raw_data))
        return _adjust_timings(records)
Parses the raw string data from LLVM timing report and attempts
        to improve the data by recomputing the times
        (See `_adjust_timings()``).
        
numba/misc/llvm_pass_timings.py