def ProcessLine(token: List, unit: ir.Unit, fun: Optional[ir.Fun], cpu_regs: Dict[str, ir.Reg]): opc = o.Opcode.Table.get(token[0]) if not opc: raise ir.ParseError(f"unknown opcode/directive: {token}") if opc == o.LEA: if token[2] in unit.fun_syms: opc = o.LEA_FUN elif token[2] in unit.mem_syms: opc = o.LEA_MEM elif token[2] in fun.stk_syms: opc = o.LEA_STK if opc != o.LEA_FUN and len(token) < 4: token.append("0") if len(token) - 1 != len(opc.operand_kinds): raise ir.ParseError("operand number %d mismatch: %s" % (len(opc.operand_kinds), token)) if token[0].startswith("."): operands = RetrieveActualOperands(unit, fun, opc, token, {}) directive = DIR_DISPATCHER[token[0]] directive(unit, operands) else: assert fun is not None operands = RetrieveActualOperands(unit, fun, opc, token, cpu_regs) assert fun.bbls, f"no bbl specified to contain instruction" bbl = fun.bbls[-1] ins = ir.Ins(opc, operands) bbl.AddIns(ins) sanity.InsCheckConstraints(ins)
def ProcessLine(token: List, unit: ir.Unit, fun: Optional[ir.Fun], cpu_regs: Dict[str, ir.Reg]): opc = o.Opcode.Table.get(token[0]) if not opc: raise ir.ParseError(f"unknown opcode/directive: {token}") # TODO: get rid of this hack which simplifies FrontEndC/translate.py a bit if opc == o.LEA: if token[2] in fun.reg_syms: pass # in case the register name is shadows a global elif token[2] in unit.fun_syms: opc = o.LEA_FUN elif token[2] in unit.mem_syms: opc = o.LEA_MEM elif token[2] in fun.stk_syms: opc = o.LEA_STK if opc != o.LEA_FUN and len(token) < 4: token.append("0") if len(token) - 1 != len(opc.operand_kinds): raise ir.ParseError( f"operand number {len(opc.operand_kinds)} mismatch: {token}") if token[0].startswith("."): operands = RetrieveActualOperands(unit, fun, opc, token, {}) directive = DIR_DISPATCHER[token[0]] directive(unit, operands) else: assert fun is not None operands = RetrieveActualOperands(unit, fun, opc, token, cpu_regs) assert fun.bbls, f"no bbl specified to contain instruction" bbl = fun.bbls[-1] ins = ir.Ins(opc, operands) bbl.AddIns(ins) sanity.InsCheckConstraints(ins)
def _CheckIns(ins, fun, unit): for n, op in enumerate(ins.operands): ot = ins.opcode.operand_kinds[n] if isinstance(op, ir.Reg): assert ot is o.OP_KIND.REG or ot is o.OP_KIND.REG_OR_CONST assert op.name in fun.reg_syms, f"UNKNOWN REG: {ins} {op} {fun.reg_syms}" elif isinstance(op, ir.Fun): assert ot is o.OP_KIND.FUN assert (op.kind in {o.FUN_KIND.BUILTIN, o.FUN_KIND.SIGNATURE, o.FUN_KIND.EXTERN} or op.bbls), f"undefined call to {op.name} in {fun.name} [{fun.kind}]" if unit: assert op.name in unit.fun_syms elif isinstance(op, ir.Bbl): assert ot is o.OP_KIND.BBL assert op.name in fun.bbl_syms elif isinstance(op, ir.Mem): assert ot is o.OP_KIND.MEM elif isinstance(op, ir.Stk): assert ot is o.OP_KIND.STK assert op.name in fun.stk_syms elif isinstance(op, ir.Jtb): assert ot is o.OP_KIND.JTB assert op.name in fun.jtb_syms elif isinstance(op, ir.Const): assert ot is o.OP_KIND.CONST or ot is o.OP_KIND.REG_OR_CONST, f"got const wanted {ot} for {ins}" else: raise ir.ParseError(f"cannot read op type: {op} {ot}")
def _GetOperand(unit: ir.Unit, fun: ir.Fun, ok: o.OP_KIND, v: Any) -> Any: if ok in o.OKS_LIST: assert isinstance(v, list) or v[0] == v[-1] == '"', f"operand {ok}: [{v}]" else: assert isinstance(v, str), f"bad operand {v} of type [{ok}]" if ok is o.OP_KIND.TYPE_LIST: out = [] for kind_name in v: kind = o.SHORT_STR_TO_RK.get(kind_name) assert kind is not None, f"bad kind name [{kind_name}]" out.append(kind) return out elif ok is o.OP_KIND.FUN: return unit.GetFunOrAddForwardDeclaration(v) elif ok is o.OP_KIND.BBL: return fun.GetBblOrAddForwardDeclaration(v) elif ok is o.OP_KIND.BBL_TAB: return ExtractBblTable(fun, v) elif ok is o.OP_KIND.MEM: return unit.GetMem(v) elif ok is o.OP_KIND.STK: return fun.GetStk(v) elif ok is o.OP_KIND.FUN_KIND: return o.SHORT_STR_TO_FK[v] elif ok is o.OP_KIND.DATA_KIND: rk = o.SHORT_STR_TO_RK.get(v) assert rk is not None, f"bad kind name [{v}]" return rk elif ok is o.OP_KIND.NAME: assert parse.RE_IDENTIFIER.match(v), f"bad identifier [{v}]" return v elif ok is o.OP_KIND.NAME_LIST: for x in v: assert parse.RE_IDENTIFIER.match(x), f"bad identifier [{x}]" return v elif ok is o.OP_KIND.MEM_KIND: return o.SHORT_STR_TO_MK[v] elif ok is o.OP_KIND.VALUE: return v elif ok is o.OP_KIND.BYTES: return ExtractBytes(v) elif ok is o.OP_KIND.JTB: return fun.GetJbl(v) else: raise ir.ParseError(f"cannot read op type: {ok}")
def RetrieveActualOperands(unit: ir.Unit, fun: ir.Fun, opc: o.Opcode, token: List, regs_cpu: Dict[str, ir.Reg]): out = [] assert len(opc.operand_kinds) == len(token) - 1 last_type: o.DK = o.DK.INVALID for ok, tc, token in zip(opc.operand_kinds, opc.constraints, token[1:]): if ok in {o.OP_KIND.REG_OR_CONST, o.OP_KIND.REG, o.OP_KIND.CONST}: assert isinstance(token, str), f"bad operand {token} of type [{ok}]" x = _GetRegOrConstOperand(fun, last_type, ok, tc, token, regs_cpu) last_type = x.kind else: x = _GetOperand(unit, fun, ok, token) if x is None: raise ir.ParseError(f"cannot read [{ok}] in ops: {token}") out.append(x) return out
def RenderOperand(v: Any, tc: o.TC): if isinstance(v, ir.Reg): if v.HasCpuReg(): return f"{v.name}@{v.cpu_reg.name}" return v.name elif isinstance(v, ir.Fun): return PREFIX + v.name elif isinstance(v, ir.Bbl): return v.name elif isinstance(v, ir.Mem): return PREFIX + v.name elif isinstance(v, ir.Stk): return v.name elif isinstance(v, ir.Const): if tc in {o.TC.OFFSET, o.TC.SAME_AS_PREV}: return str(v.value) return str(v) elif isinstance(v, ir.Jtb): return v.name else: raise ir.ParseError(f"cannot read op type: {v}")
def RenderOperand(v: Any, tc: o.TC): if isinstance(v, ir.Reg): return _RenderReg(v) elif isinstance(v, ir.Fun): return PREFIX + v.name elif isinstance(v, ir.Bbl): return v.name elif isinstance(v, ir.Mem): return PREFIX + v.name elif isinstance(v, ir.Stk): return v.name elif isinstance(v, ir.Const): if tc in {o.TC.OFFSET, o.TC.SAME_AS_PREV}: s = str(v.value) else: s = str(v) if s.startswith("inf") or s.startswith("nan"): s = "+" + s return s elif isinstance(v, ir.Jtb): return v.name else: raise ir.ParseError(f"cannot read op type: {v}")