Skip to content

LLVM optimization often (always?) results of loss of closure upvar debug info #141712

Open
@khuey

Description

@khuey

I'm filing this here for tracking even though this is largely/entirely an LLVM issue (llvm/llvm-project#141559, NB: the title of that issue is not accurate at the time of filing this one)

use std::{env, process};
use std::str::FromStr;

fn main() {
    let needle = env::var("NEEDLE").unwrap();
    let ret = i64::from_str(&env::var("RETURN").unwrap()).unwrap();
    let ret2 = i64::from_str(&env::var("RETURN2").unwrap()).unwrap();

    let check = |foobar| {
        if foobar == needle {
            process::exit(ret as i32 - ret2 as i32);
            return true;
        }
        false
    };

    for s in env::args() {
        if check(s) {
            unreachable!();
        }
    }
}

This program has been reduced from iterator heavy code but intentionally made weird in certain ways to defeat the optimizer (getting upvar values from env vars), highlight the issue with the closure (eschewing the use of the Iterator trait), and to force the rustc-generated type capturing the upvars to be of sufficient size.

rustc's MIR optimizations do not inline the closure check, leaving that for LLVM to do. Once LLVM inlines it, SROA then sets to work on the upvar-capturing-type and splits it into its components. LLVM does correctly move the debug value definitions for the upvars within the closure to the points at which the equivalent variables in the outer function are defined, and it does correctly rewrite the DWARF expressions to "$rsp plus offset plus deref".

Where LLVM falls down is that the LiveDebugValues pass does not propagate the value definition through basic blocks where the corresponding variable is not in scope (unless the entire block is "artificial"). This essentially guarantees that the value will not be propagated through to the closure and will be lost.

There is some discussion in the linked LLVM issue of how to fix this and what the performance costs might be.

@rustbot label +A-llvm +A-debuginfo +WG-llvm

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-debuginfoArea: Debugging information in compiled programs (DWARF, PDB, etc.)C-bugCategory: This is a bug.WG-llvmWorking group: LLVM backend code generation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions