<commit_before>/*
 * Copyright (c) 2011 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */  

#include "BasicBlockGenerator.hpp"
#include <cassert>
#include <algorithm>

using namespace std;

BasicBlockGenerator::BasicBlockGenerator(Environment* env, Machine* mach) :
    env_(env),
    machine_(mach),
    label_(0) {

    if (env_->errors()) {
        return;
    }
    for (Feature::Ptr m = env_->modules(); m; m = m->next()) {
        m(this);
    }    
}

void BasicBlockGenerator::operator()(Class* feature) {
    // Output intermediate-level code for the class given by 'feature'.  
    // This function also sets up the vtable for the class.
    class_ = feature;
    calculate_size(feature);

    enter_scope();
    for (Feature::Ptr f = feature->features(); f; f = f->next()) {
        f(this);
    }
    exit_scope();

    if (!feature->is_object()) { return; }

    emit_vtable(feature);
    class_ = 0;
}

void BasicBlockGenerator::operator()(Module* feature) {
    module_ = feature;
    for (Feature::Ptr f = feature->features(); f; f = f->next()) {
        f(this);
    }
}

void BasicBlockGenerator::operator()(Formal* formal) {
    
}

void BasicBlockGenerator::operator()(StringLiteral* expr) {
    // Load a pointer to the string from the string table.  Strings must
    // always be loaded first, since they are specified by address.
    return_ = load(expr);
}

void BasicBlockGenerator::operator()(IntegerLiteral* expr) {
    // Load the literal value with load-immediate
    return_ = load(expr);
}

void BasicBlockGenerator::operator()(FloatLiteral* expr) {
    // Load the literal value with load-immediate
    return_ = load(expr);
}

void BasicBlockGenerator::operator()(BooleanLiteral* expr) {
    // Load the literal value with load-immediate
    return_ = load(expr);
}

void BasicBlockGenerator::operator()(Binary* expr) {
    // Emit the left and right exprs, then perform the operation on
    // the two operands, and return the result.

    if (env_->name("and") == expr->operation()) {
        BasicBlock::Ptr left_true = basic_block();
        
        // Don't use the 'real' true branch; on true we want to emit the    
        // test for the second side of the and
        Operand left = emit(expr->left(), left_true, false_, false);
        if (!block_->is_terminated()) {
            bz(left, false_, left_true);
        }
        emit(left_true); 

        return_ = emit(expr->right(), true_, false_, invert_branch_);
        
    } else if (env_->name("or") == expr->operation()) {
        BasicBlock::Ptr left_false = basic_block();
        
        // Don't use the 'real' false branch; on false we want to emit
        // the test for the second side of the or
        Operand left = emit(expr->left(), true_, left_false, true);
        if (!block_->is_terminated()) {
            bnz(left, true_, left_false);
        }
        emit(left_false);
    
        return_ = emit(expr->right(), true_, false_, invert_branch_);

    } else {
        assert(!"Unsupported binary operation");
    }
}

void BasicBlockGenerator::operator()(Unary* expr) {
    // Emit the code for the expression, then perform the operation on the
    // operand and return the result.

    if (env_->name("not")) {
        // Swap the false and true branches while calling the child, since 
        // the 'not' inverts the conditional 
        Operand op = emit(expr->child(), false_, true_, !invert_branch_);
    } else {
        assert(!"Unsupported unary operation");
    }
}

void BasicBlockGenerator::operator()(Call* expr) {
    // Push objects in anticipation of the call instruction.  Arguments must
    // be pushed in reverse order.
    vector<Operand> args;
    for (Expression::Ptr a = expr->arguments(); a; a = a->next()) {
        args.push_back(emit(a));
    }
    for (int i = args.size()-1; i >= 0; i--) {
        emit_push_arg(i, args[i]);
    }

    // Look up the function by name in the current context.
    String::Ptr id = expr->identifier();
    String::Ptr scope = expr->scope();
    Function::Ptr func = expr->file()->function(scope, id);

    // Insert a call expression, then pop the return value off the stack.
    call(func->label());
    if (!func->type()->is_void()) {
        return_ = emit_pop_ret();
    } else {
        return_ = 0;
    }
}

void BasicBlockGenerator::operator()(Dispatch* expr) {
    // The call expression may actually be an operator, if the type of the
    // expression is primitive.
    Type::Ptr type = expr->arguments()->type();
    String::Ptr id = expr->identifier();
    if (id->string()[0] == '@' && type->is_primitive()) {
        emit_operator(expr);
        return; 
    }

    // Push objects in anticipation of the call instruction.
    vector<Operand> args;
    for (Expression::Ptr a = expr->arguments(); a; a = a->next()) {
        args.push_back(emit(a));
    }

    // Look up the function by name in the current context.
    Expression::Ptr receiver = expr->arguments();
    Class::Ptr clazz = receiver->type()->clazz();
    Function::Ptr func = clazz->function(id);

    Operand fnptr;
    if (type->is_interface()) { 
        // Dynamic dispatch: call the object dispatch function with the
        // receiver and function name as arguments.
        
        String::Ptr name = env_->string(func->name()->string());
        emit_push_arg(1, load(new StringLiteral(Location(), name)));
        emit_push_arg(0, args[0]); // Receiver
        call(env_->name("_Object__dispatch"));
        fnptr = emit_pop_ret();
    }

    for (int i = args.size()-1; i >= 0; i--) {
        emit_push_arg(i, args[i]);
    }

    if (type->is_interface()) {
        // Dynamic dispatch: call the function pointer.
        call(fnptr);
    } else {
        // Static dispatch: insert a call expression, then pop the return value
        // off the stack.
        call(func->label());
    }

    if (!func->type()->is_void()) {
        return_ = emit_pop_ret();
    } else {
        return_ = 0;
    }
}

void BasicBlockGenerator::operator()(Construct* expr) {
    // Push objects in anticipation of the call instruction.  Arguments must
    // be pushed in reverse order.
    vector<Operand> args;
    for (Expression::Ptr a = expr->arguments(); a; a = a->next()) {
        args.push_back(emit(a));
    }
    for (int i = args.size()-1; i >= 0; i--) {
        emit_push_arg(i, args[i]);
    }

    // Look up the function by name in the current context.
    String::Ptr id = env_->name("@init");
    Class::Ptr clazz = expr->type()->clazz();
    Function::Ptr func = clazz->function(id);

    // Insert a call expression, then pop the return value off the stack.
    call(func->label());
    return_ = emit_pop_ret();
}

void BasicBlockGenerator::operator()(Identifier* expr) {
    // Simply look up the value of the variable as stored previously.
    String::Ptr id = expr->identifier();
    Variable::Ptr var = variable(id);
    Attribute::Ptr attr = class_ ? class_->attribute(id) : 0;
    if (var) {
        return_ = var->operand();
    } else if (attr) {
        Variable::Ptr self = variable(env_->name("self"));
        return_ = load(Operand::addr(self->operand().temp(), attr->slot()+2));
        // +2 is for refcount, vtable slots
    } else {
        // Variable can't be found in a temporary; it must be an argument 
        // passed on the stack.

        int offset = stack(id);
        assert(offset);
        return_ = load(Operand::addr(offset)); 
        // A load operand of zero means the variable must be loaded relative
        // to the base pointer.

        variable(new Variable(id, return_, 0));
    }
}

void BasicBlockGenerator::operator()(Empty* expr) {
    // Do nothing
    return_ = load(env_->integer("0"));
}

void BasicBlockGenerator::operator()(Block* statement) {
    enter_scope();
    for (Statement::Ptr s = statement->children(); s; s = s->next()) {
        s(this);
    }
    exit_scope();
}

void BasicBlockGenerator::operator()(Simple* statement) {
    Expression::Ptr expr = statement->expression();
    expr(this);
}

void BasicBlockGenerator::operator()(Let* statement) {
    // Enter a new scope, then emit code for initializing all the let
    // variables, and initialize code for the body.
    enter_scope();
    for (Statement::Ptr v = statement->variables(); v; v = v->next()) {
        emit(v);
    } 
    emit(statement->block());
    exit_scope();
}

void BasicBlockGenerator::operator()(While* statement) {
    // Emit the guard expression in a new basic block
    BasicBlock::Ptr guard_block = basic_block();
    BasicBlock::Ptr body_block = basic_block();
    BasicBlock::Ptr done_block = basic_block();

    emit(guard_block);

    // Recursively emit the boolean guard expression.  
    Operand guard = emit(statement->guard(), body_block, done_block, false);
    if (!block_->is_terminated()) {
        bz(guard, done_block, body_block);
    }

    // Now emit the body of the loop
    emit(body_block);
    emit(statement->block());

    // Jump back up to re-evaluate the guard expression
    jump(guard_block);
    emit(done_block);    
}

void BasicBlockGenerator::operator()(Conditional* statement) {
    // Emit a conditional if/then expression with boolean guard expr.
    BasicBlock::Ptr then_block = basic_block();
    BasicBlock::Ptr else_block;
    BasicBlock::Ptr done_block = basic_block();
    if (statement->false_branch()) {
        else_block = basic_block();
    } else {
        else_block = done_block;
    }

    // Recursively emit the boolean guard expression.  We need to pass the
    // true and the false block pointers so that the correct code is emitted
    // on each branch.
    Operand guard = emit(statement->guard(), then_block, else_block, false);
    if (!block_->is_terminated()) {
        bz(guard, else_block, then_block);
    }

    // Now emit the true branch of the conditional
    emit(then_block);
    emit(statement->true_branch());

    // Emit the false branch if it exists; make sure to insert a jump before
    // emitting the false branch
    if (statement->false_branch()) {
        if (!block_->is_terminated()) {
            jump(done_block);
        }
        emit(else_block);
        emit(statement->false_branch());
        // jump(done_block);
    }
    emit(done_block);
}

void BasicBlockGenerator::operator()(Assignment* statement) {
    // FixMe: This breaks SSA form, because variables are not renamed.  With
    // this code the way it is, the generator only generates SSA for temporary
    // expressions.  This limitation is here as a punt on introducing
    // phi-functions until optimizations are needed, since without
    // optimizations, SSA is not needed anyway.

    Expression::Ptr init = statement->initializer();
    Operand value;
    if (dynamic_cast<Empty*>(init.pointer())) {
        value = env_->integer("0");
    } else {
        value = emit(init);
    }

    String::Ptr id = statement->identifier();
    Type::Ptr type = statement->type(); 
    Variable::Ptr var = variable(id);
    Attribute::Ptr attr = class_ ? class_->attribute(id) : 0;

    if (var) {
        // Assignment to a local var that has already been initialized once in
        // the current scope.
        if (!type->is_value()) {
            emit_refcount_dec(var->operand());
        }
        block_->instr(MOV, var->operand(), value, 0);
        if (!type->is_value()) {
            emit_refcount_inc(var->operand());
        }
    } else if (attr) {
        // Assignment to an attribute within a class
        Variable::Ptr self = variable(env_->name("self"));
        Operand addr = Operand::addr(self->operand().temp(), attr->slot()+2);  
        Operand old = load(addr);
        if (!type->is_value()) {
            emit_refcount_dec(old);
        } 
        // +2 is for vtable and refcount
        store(addr, value);
        if (!type->is_value()) {
            emit_refcount_inc(value);
        }
    } else {
        // Assignment to a local var that has not yet been initialized in the
        // current scope.
        Variable::Ptr var = new Variable(id, mov(value), init->type());
        variable(var);
        if (!type->is_value()) {
            emit_refcount_inc(var->operand());
        }
    }
}

void BasicBlockGenerator::operator()(Return* statement) {<commit_msg>Added checks for weak instance variables<commit_after>/*
 * Copyright (c) 2011 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, APEXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */  

#include "BasicBlockGenerator.hpp"
#include <cassert>
#include <algorithm>

using namespace std;

BasicBlockGenerator::BasicBlockGenerator(Environment* env, Machine* mach) :
    env_(env),
    machine_(mach),
    label_(0) {

    if (env_->errors()) {
        return;
    }
    for (Feature::Ptr m = env_->modules(); m; m = m->next()) {
        m(this);
    }    
}

void BasicBlockGenerator::operator()(Class* feature) {
    // Output intermediate-level code for the class given by 'feature'.  
    // This function also sets up the vtable for the class.
    class_ = feature;
    calculate_size(feature);

    enter_scope();
    for (Feature::Ptr f = feature->features(); f; f = f->next()) {
        f(this);
    }
    exit_scope();

    if (!feature->is_object()) { return; }

    emit_vtable(feature);
    class_ = 0;
}

void BasicBlockGenerator::operator()(Module* feature) {
    module_ = feature;
    for (Feature::Ptr f = feature->features(); f; f = f->next()) {
        f(this);
    }
}

void BasicBlockGenerator::operator()(Formal* formal) {
    
}

void BasicBlockGenerator::operator()(StringLiteral* expr) {
    // Load a pointer to the string from the string table.  Strings must
    // always be loaded first, since they are specified by address.
    return_ = load(expr);
}

void BasicBlockGenerator::operator()(IntegerLiteral* expr) {
    // Load the literal value with load-immediate
    return_ = load(expr);
}

void BasicBlockGenerator::operator()(FloatLiteral* expr) {
    // Load the literal value with load-immediate
    return_ = load(expr);
}

void BasicBlockGenerator::operator()(BooleanLiteral* expr) {
    // Load the literal value with load-immediate
    return_ = load(expr);
}

void BasicBlockGenerator::operator()(Binary* expr) {
    // Emit the left and right exprs, then perform the operation on
    // the two operands, and return the result.

    if (env_->name("and") == expr->operation()) {
        BasicBlock::Ptr left_true = basic_block();
        
        // Don't use the 'real' true branch; on true we want to emit the    
        // test for the second side of the and
        Operand left = emit(expr->left(), left_true, false_, false);
        if (!block_->is_terminated()) {
            bz(left, false_, left_true);
        }
        emit(left_true); 

        return_ = emit(expr->right(), true_, false_, invert_branch_);
        
    } else if (env_->name("or") == expr->operation()) {
        BasicBlock::Ptr left_false = basic_block();
        
        // Don't use the 'real' false branch; on false we want to emit
        // the test for the second side of the or
        Operand left = emit(expr->left(), true_, left_false, true);
        if (!block_->is_terminated()) {
            bnz(left, true_, left_false);
        }
        emit(left_false);
    
        return_ = emit(expr->right(), true_, false_, invert_branch_);

    } else {
        assert(!"Unsupported binary operation");
    }
}

void BasicBlockGenerator::operator()(Unary* expr) {
    // Emit the code for the expression, then perform the operation on the
    // operand and return the result.

    if (env_->name("not")) {
        // Swap the false and true branches while calling the child, since 
        // the 'not' inverts the conditional 
        Operand op = emit(expr->child(), false_, true_, !invert_branch_);
    } else {
        assert(!"Unsupported unary operation");
    }
}

void BasicBlockGenerator::operator()(Call* expr) {
    // Push objects in anticipation of the call instruction.  Arguments must
    // be pushed in reverse order.
    vector<Operand> args;
    for (Expression::Ptr a = expr->arguments(); a; a = a->next()) {
        args.push_back(emit(a));
    }
    for (int i = args.size()-1; i >= 0; i--) {
        emit_push_arg(i, args[i]);
    }

    // Look up the function by name in the current context.
    String::Ptr id = expr->identifier();
    String::Ptr scope = expr->scope();
    Function::Ptr func = expr->file()->function(scope, id);

    // Insert a call expression, then pop the return value off the stack.
    call(func->label());
    if (!func->type()->is_void()) {
        return_ = emit_pop_ret();
    } else {
        return_ = 0;
    }
}

void BasicBlockGenerator::operator()(Dispatch* expr) {
    // The call expression may actually be an operator, if the type of the
    // expression is primitive.
    Type::Ptr type = expr->arguments()->type();
    String::Ptr id = expr->identifier();
    if (id->string()[0] == '@' && type->is_primitive()) {
        emit_operator(expr);
        return; 
    }

    // Push objects in anticipation of the call instruction.
    vector<Operand> args;
    for (Expression::Ptr a = expr->arguments(); a; a = a->next()) {
        args.push_back(emit(a));
    }

    // Look up the function by name in the current context.
    Expression::Ptr receiver = expr->arguments();
    Class::Ptr clazz = receiver->type()->clazz();
    Function::Ptr func = clazz->function(id);

    Operand fnptr;
    if (type->is_interface()) { 
        // Dynamic dispatch: call the object dispatch function with the
        // receiver and function name as arguments.
        
        String::Ptr name = env_->string(func->name()->string());
        emit_push_arg(1, load(new StringLiteral(Location(), name)));
        emit_push_arg(0, args[0]); // Receiver
        call(env_->name("_Object__dispatch"));
        fnptr = emit_pop_ret();
    }

    for (int i = args.size()-1; i >= 0; i--) {
        emit_push_arg(i, args[i]);
    }

    if (type->is_interface()) {
        // Dynamic dispatch: call the function pointer.
        call(fnptr);
    } else {
        // Static dispatch: insert a call expression, then pop the return value
        // off the stack.
        call(func->label());
    }

    if (!func->type()->is_void()) {
        return_ = emit_pop_ret();
    } else {
        return_ = 0;
    }
}

void BasicBlockGenerator::operator()(Construct* expr) {
    // Push objects in anticipation of the call instruction.  Arguments must
    // be pushed in reverse order.
    vector<Operand> args;
    for (Expression::Ptr a = expr->arguments(); a; a = a->next()) {
        args.push_back(emit(a));
    }
    for (int i = args.size()-1; i >= 0; i--) {
        emit_push_arg(i, args[i]);
    }

    // Look up the function by name in the current context.
    String::Ptr id = env_->name("@init");
    Class::Ptr clazz = expr->type()->clazz();
    Function::Ptr func = clazz->function(id);

    // Insert a call expression, then pop the return value off the stack.
    call(func->label());
    return_ = emit_pop_ret();
}

void BasicBlockGenerator::operator()(Identifier* expr) {
    // Simply look up the value of the variable as stored previously.
    String::Ptr id = expr->identifier();
    Variable::Ptr var = variable(id);
    Attribute::Ptr attr = class_ ? class_->attribute(id) : 0;
    if (var) {
        return_ = var->operand();
    } else if (attr) {
        Variable::Ptr self = variable(env_->name("self"));
        return_ = load(Operand::addr(self->operand().temp(), attr->slot()+2));
        // +2 is for refcount, vtable slots
    } else {
        // Variable can't be found in a temporary; it must be an argument 
        // passed on the stack.

        int offset = stack(id);
        assert(offset);
        return_ = load(Operand::addr(offset)); 
        // A load operand of zero means the variable must be loaded relative
        // to the base pointer.

        variable(new Variable(id, return_, 0));
    }
}

void BasicBlockGenerator::operator()(Empty* expr) {
    // Do nothing
    return_ = load(env_->integer("0"));
}

void BasicBlockGenerator::operator()(Block* statement) {
    enter_scope();
    for (Statement::Ptr s = statement->children(); s; s = s->next()) {
        s(this);
    }
    exit_scope();
}

void BasicBlockGenerator::operator()(Simple* statement) {
    Expression::Ptr expr = statement->expression();
    expr(this);
}

void BasicBlockGenerator::operator()(Let* statement) {
    // Enter a new scope, then emit code for initializing all the let
    // variables, and initialize code for the body.
    enter_scope();
    for (Statement::Ptr v = statement->variables(); v; v = v->next()) {
        emit(v);
    } 
    emit(statement->block());
    exit_scope();
}

void BasicBlockGenerator::operator()(While* statement) {
    // Emit the guard expression in a new basic block
    BasicBlock::Ptr guard_block = basic_block();
    BasicBlock::Ptr body_block = basic_block();
    BasicBlock::Ptr done_block = basic_block();

    emit(guard_block);

    // Recursively emit the boolean guard expression.  
    Operand guard = emit(statement->guard(), body_block, done_block, false);
    if (!block_->is_terminated()) {
        bz(guard, done_block, body_block);
    }

    // Now emit the body of the loop
    emit(body_block);
    emit(statement->block());

    // Jump back up to re-evaluate the guard expression
    jump(guard_block);
    emit(done_block);    
}

void BasicBlockGenerator::operator()(Conditional* statement) {
    // Emit a conditional if/then expression with boolean guard expr.
    BasicBlock::Ptr then_block = basic_block();
    BasicBlock::Ptr else_block;
    BasicBlock::Ptr done_block = basic_block();
    if (statement->false_branch()) {
        else_block = basic_block();
    } else {
        else_block = done_block;
    }

    // Recursively emit the boolean guard expression.  We need to pass the
    // true and the false block pointers so that the correct code is emitted
    // on each branch.
    Operand guard = emit(statement->guard(), then_block, else_block, false);
    if (!block_->is_terminated()) {
        bz(guard, else_block, then_block);
    }

    // Now emit the true branch of the conditional
    emit(then_block);
    emit(statement->true_branch());

    // Emit the false branch if it exists; make sure to insert a jump before
    // emitting the false branch
    if (statement->false_branch()) {
        if (!block_->is_terminated()) {
            jump(done_block);
        }
        emit(else_block);
        emit(statement->false_branch());
        // jump(done_block);
    }
    emit(done_block);
}

void BasicBlockGenerator::operator()(Assignment* statement) {
    // FixMe: This breaks SSA form, because variables are not renamed.  With
    // this code the way it is, the generator only generates SSA for temporary
    // expressions.  This limitation is here as a punt on introducing
    // phi-functions until optimizations are needed, since without
    // optimizations, SSA is not needed anyway.

    Expression::Ptr init = statement->initializer();
    Operand value;
    if (dynamic_cast<Empty*>(init.pointer())) {
        value = env_->integer("0");
    } else {
        value = emit(init);
    }

    String::Ptr id = statement->identifier();
    Type::Ptr type = statement->type(); 
    Variable::Ptr var = variable(id);
    Attribute::Ptr attr = class_ ? class_->attribute(id) : 0;

    if (var) {
        // Assignment to a local var that has already been initialized once in
        // the current scope.
        if (!type->is_value()) {
            emit_refcount_dec(var->operand());
        }
        block_->instr(MOV, var->operand(), value, 0);
        if (!type->is_value()) {
            emit_refcount_inc(var->operand());
        }
    } else if (attr) {
        // Assignment to an attribute within a class
        Variable::Ptr self = variable(env_->name("self"));
        Operand addr = Operand::addr(self->operand().temp(), attr->slot()+2);  
        Operand old = load(addr);
        if (!type->is_value() && !attr->is_weak()) {
            emit_refcount_dec(old);
        } 
        // +2 is for vtable and refcount
        store(addr, value);
        if (!type->is_value() && !attr->is_weak()) {
            emit_refcount_inc(value);
        }
    } else {
        // Assignment to a local var that has not yet been initialized in the
        // current scope.
        Variable::Ptr var = new Variable(id, mov(value), init->type());
        variable(var);
        if (!type->is_value()) {
            emit_refcount_inc(var->operand());
        }
    }
}

void BasicBlockGenerator::operator()(Return* statement) {
{'fraction_non_alphanumeric': 0.13050473304149363, 'fraction_numerical': 0.0020952594754368244, 'mean_word_length': 2.737136465324385, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 221, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3288213', 'n_tokens_mistral': 7716, 'n_tokens_neox': 7523, 'n_words': 2475}