Repository: JuliaLang/julia
File: src/llvm-alloc-opt.cpp (C++)

Code before:
                    break;
                }
            }
        }
        if (has_refaggr) {
            REMARK([&]() {
                return OptimizationRemarkMissed(DEBUG_TYPE, "Escaped", orig)
                    << "GC allocation has unusual object reference, unable to move to stack " << ore::NV("GC Allocation", orig);
            });
            if (use_info.hastypeof)
                optimizeTag(orig);
            continue;
        }
        if (!use_info.hasunknownmem && !use_info.addrescaped) {
            REMARK([&](){
                return OptimizationRemark(DEBUG_TYPE, "Stack Split Allocation", orig)
                    << "GC allocation split on stack " << ore::NV("GC Allocation", orig);
            });
            // No one actually care about the memory layout of this object, split it.
            splitOnStack(orig);
            continue;
        }
        // The move to stack code below, if has_ref is set, changes the allocation to an array of jlvalue_t's. This is fine
        // if all objects are jlvalue_t's. However, if part of the allocation is not a julia object (e.g. it is a { float, jlvaluet }),
        // then the moveToStackCAll will create a [2 x jlvaluet] bitcast to { float, jlvaluet }. The float clearly is not a GC
        // value and will result in segfaults and other problems.
        if (has_unboxed && has_ref) {
            REMARK([&]() {
                return OptimizationRemarkMissed(DEBUG_TYPE, "Escaped", orig)
                    << "GC allocation could not be split and contained both julia object and non-julia-object data, unable to move to stack " << ore::NV("GC Allocation", orig);
            });
            if (use_info.hastypeof)
                optimizeTag(orig);
            continue;
        }
        REMARK([&](){
            return OptimizationRemark(DEBUG_TYPE, "Stack Move Allocation", orig)
                << "GC allocation moved to stack " << ore::NV("GC Allocation", orig);
        });
        // The object has no fields with mix reference access
        moveToStack(orig, sz, has_ref, use_info.allockind);
    }
}

bool Optimizer::finalize()
{
    if (removed.empty())
        return false;
    for (auto inst: removed)
        inst->eraseFromParent();
    return true;

Review comment (suggestion):
```suggestion
        // The move to stack code below, if has_ref is set, changes the allocation to an array of jlvalue_t's. This is fine
        // if all objects are jlvalue_t's. However, if part of the allocation is an unboxed value (e.g. it is a { float, jlvaluet }),
        // then moveToStack will create a [2 x jlvaluet] bitcast to { float, jlvaluet }. 
        // This later causes the GC rooting pass, to miss-characterize the float as a pointer to a GC value
```

Code after:
                    break;
                }
            }
        }
        if (has_refaggr) {
            REMARK([&]() {
                return OptimizationRemarkMissed(DEBUG_TYPE, "Escaped", orig)
                    << "GC allocation has unusual object reference, unable to move to stack " << ore::NV("GC Allocation", orig);
            });
            if (use_info.hastypeof)
                optimizeTag(orig);
            continue;
        }
        if (!use_info.hasunknownmem && !use_info.addrescaped) {
            REMARK([&](){
                return OptimizationRemark(DEBUG_TYPE, "Stack Split Allocation", orig)
                    << "GC allocation split on stack " << ore::NV("GC Allocation", orig);
            });
            // No one actually care about the memory layout of this object, split it.
            splitOnStack(orig);
            continue;
        }
        // The move to stack code below, if has_ref is set, changes the allocation to an array of jlvalue_t's. This is fine
        // if all objects are jlvalue_t's. However, if part of the allocation is an unboxed value (e.g. it is a { float, jlvaluet }),
        // then moveToStack will create a [2 x jlvaluet] bitcast to { float, jlvaluet }.
        // This later causes the GC rooting pass, to miss-characterize the float as a pointer to a GC value
        if (has_unboxed && has_ref) {
            REMARK([&]() {
                return OptimizationRemarkMissed(DEBUG_TYPE, "Escaped", orig)
                    << "GC allocation could not be split since it contains both boxed and unboxed values, unable to move to stack " << ore::NV("GC Allocation", orig);
            });
            if (use_info.hastypeof)
                optimizeTag(orig);
            continue;
        }
        REMARK([&](){
            return OptimizationRemark(DEBUG_TYPE, "Stack Move Allocation", orig)
                << "GC allocation moved to stack " << ore::NV("GC Allocation", orig);
        });
        // The object has no fields with mix reference access
        moveToStack(orig, sz, has_ref, use_info.allockind);
    }
}

bool Optimizer::finalize()
{
    if (removed.empty())
        return false;
    for (auto inst: removed)
        inst->eraseFromParent();
    return true;