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
// parsePHIInst converts the provided LLVM IR phi instruction into an equivalent
// variable definition mapping.
//
// Syntax:
//    %foo = phi i32 [ 42, %2 ], [ %bar, %3 ]
func parsePHIInst(inst llvm.Value) (ident string, defs []*definition, err error) {
	// Parse result.
	result, err := getResult(inst)
	if err != nil {
		return "", nil, errutil.Err(err)
	}
	ident = result.(*ast.Ident).Name

	// Parse and validate tokens.
	tokens, err := getTokens(inst)
	if err != nil {
		return "", nil, errutil.Err(err)
	}
	if len(tokens) < 10 {
		return "", nil, errutil.Newf("unable to parse PHI instruction; expected >= 10 tokens, got %d", len(tokens))
	}

	// Parse operands.
	for i := 0; i < inst.OperandsCount(); i++ {
		// Parse variable definition expression.
		expr, err := parseOperand(inst.Operand(i))
		if err != nil {
			return "", nil, errutil.Err(err)
		}

		// Parse source basic block.
		bbTok := tokens[7+i*6]
		if bbTok.Kind != lltoken.LocalID {
			return "", nil, errutil.Newf("invalid operand token, expected LocalID, got %v", bbTok.Kind)
		}
		def := &definition{bb: bbTok.Val, expr: expr}
		defs = append(defs, def)
	}

	return ident, defs, nil
}
Example #3
0
File: ssa.go Project: hinike/llgo
// If val is a constant and addr refers to a global variable which is defined in
// this module or an element thereof, simulate the effect of storing val at addr
// in the global variable's initializer and return true, otherwise return false.
// Precondition: we are compiling the init function.
func (fr *frame) maybeStoreInInitializer(val, addr llvm.Value) bool {
	if val.IsAConstant().IsNil() {
		return false
	}

	if !addr.IsAConstantExpr().IsNil() && addr.OperandsCount() >= 2 &&
		// TODO(pcc): Explicitly check that this is a constant GEP.
		// I don't think there are any other kinds of constantexpr which
		// satisfy the conditions we test for here, so this is probably safe.
		!addr.Operand(0).IsAGlobalVariable().IsNil() &&
		addr.Operand(1).IsNull() {
		gv := addr.Operand(0)
		globalInit, ok := fr.globalInits[gv]
		if !ok {
			return false
		}
		indices := make([]uint32, addr.OperandsCount()-2)
		for i := range indices {
			op := addr.Operand(i + 2)
			if op.IsAConstantInt().IsNil() {
				return false
			}
			indices[i] = uint32(op.ZExtValue())
		}
		globalInit.update(gv.Type().ElementType(), indices, val)
		return true
	} else if !addr.IsAGlobalVariable().IsNil() {
		if globalInit, ok := fr.globalInits[addr]; ok {
			globalInit.update(addr.Type().ElementType(), nil, val)
			return true
		}
		return false
	} else {
		return false
	}
}