Example #1
0
// 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))
}
Example #2
0
// 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
}