// parseBinOp converts the provided LLVM IR binary operation into an equivalent // Go AST node (an assignment statement with a binary expression on the right- // hand side). // // Syntax: // <result> add <type> <op1>, <op2> // // References: // http://llvm.org/docs/LangRef.html#binary-operations func parseBinOp(inst llvm.Value, op token.Token) (ast.Stmt, error) { x, err := parseOperand(inst.Operand(0)) if err != nil { return nil, err } y, err := parseOperand(inst.Operand(1)) if err != nil { return nil, err } result, err := getResult(inst) if err != nil { return nil, errutil.Err(err) } lhs := []ast.Expr{result} rhs := []ast.Expr{&ast.BinaryExpr{X: x, Op: op, Y: y}} // TODO: Use "=" instead of ":=" and let go-post and grind handle the ":=" to // "=" propagation. return &ast.AssignStmt{Lhs: lhs, Tok: token.DEFINE, Rhs: rhs}, nil }
// parseRetInst converts the provided LLVM IR ret instruction into an equivalent // Go return statement. // // Syntax: // ret void // ret <type> <val> func parseRetInst(inst llvm.Value) (*ast.ReturnStmt, error) { // TODO: Make more robust by using proper parsing instead of relying on // tokens. The current approach is used for a proof of concept and would fail // for composite literals. This TODO applies to the use of tokens in all // functions. // Parse and validate tokens. tokens, err := getTokens(inst) if err != nil { return nil, err } if len(tokens) < 4 { // TODO: Remove debug output. inst.Dump() return nil, errutil.Newf("unable to parse return instruction; expected >= 4 tokens, got %d", len(tokens)) } typ := tokens[1] if typ.Kind != lltoken.Type { return nil, errutil.Newf(`invalid return instruction; expected type token, got %q`, typ) } // Create and return a void return statement. if typ.Val == "void" { return &ast.ReturnStmt{}, nil } // Create and return a return statement. val, err := parseOperand(inst.Operand(0)) if err != nil { return nil, errutil.Err(err) } ret := &ast.ReturnStmt{ Results: []ast.Expr{val}, } return ret, nil }
// 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 }
// 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 } }