// parseInst converts the provided LLVM IR instruction into an equivalent Go AST // node (a statement). func parseInst(inst llvm.Value) (ast.Stmt, error) { // TODO: Remove debug output. if flagVerbose { fmt.Println("parseInst:") fmt.Println(" nops:", inst.OperandsCount()) inst.Dump() fmt.Println() } // Assignment operation. // %foo = ... opcode := inst.InstructionOpcode() if _, err := getResult(inst); err == nil { // Binary Operations switch opcode { case llvm.Add, llvm.FAdd: return parseBinOp(inst, token.ADD) case llvm.Sub, llvm.FSub: return parseBinOp(inst, token.SUB) case llvm.Mul, llvm.FMul: return parseBinOp(inst, token.MUL) case llvm.UDiv, llvm.SDiv, llvm.FDiv: // TODO: Handle signed and unsigned div separately. return parseBinOp(inst, token.QUO) case llvm.URem, llvm.SRem, llvm.FRem: // TODO: Handle signed and unsigned mod separately. return parseBinOp(inst, token.REM) // Bitwise Binary Operations case llvm.Shl: return parseBinOp(inst, token.SHL) case llvm.LShr, llvm.AShr: // TODO: Handle logical and arithmetic shift right separately. return parseBinOp(inst, token.SHR) case llvm.And: return parseBinOp(inst, token.AND) case llvm.Or: return parseBinOp(inst, token.OR) case llvm.Xor: return parseBinOp(inst, token.XOR) // Other Operators case llvm.ICmp, llvm.FCmp: pred, err := getCmpPred(inst) if err != nil { return nil, errutil.Err(err) } return parseBinOp(inst, pred) } } return nil, errutil.Newf("support for LLVM IR instruction %q not yet implemented", prettyOpcode(opcode)) }
// addTerm adds the provided terminator instruction to the basic block. If the // terminator instruction doesn't have a target basic block (e.g. ret) it is // parsed and added to the statements list of the basic block instead. func (bb *basicBlock) addTerm(term llvm.Value) error { // TODO: Check why there is no opcode in the llvm library for the resume // terminator instruction. switch opcode := term.InstructionOpcode(); opcode { case llvm.Ret: // The return instruction doesn't have any target basic blocks so treat it // like a regular instruction and append it to the list of statements. ret, err := parseRetInst(term) if err != nil { return err } bb.stmts = append(bb.stmts, ret) case llvm.Br, llvm.Switch, llvm.IndirectBr, llvm.Invoke, llvm.Unreachable: // Parse the terminator instruction during the control flow analysis. bb.term = term default: return errutil.Newf("non-terminator instruction %q at end of basic block", prettyOpcode(opcode)) } return nil }