Cranelift DFG: make inst clone deep-clone varargs lists. (#5727)
When investigating #5716, I found that rematerialization of a `call`, in addition to blowing up for other reasons, caused aliasing of the varargs list (the `EntityList` in the `ListPool`), such that editing the args of the second copy of the call instruction inadvertently updated the first as well. This PR modifies `DataFlowGraph::clone_inst` so that it always clones the varargs list if present. This shouldn't have any functional impact on Cranelift today, because we don't rematerialize any instructions with varargs; but it's important to get it right to avoid a bug later!
This commit is contained in:
@@ -383,6 +383,83 @@ fn gen_instruction_data_impl(formats: &[&InstructionFormat], fmt: &mut Formatter
|
||||
});
|
||||
fmt.line("}");
|
||||
});
|
||||
fmt.line("}");
|
||||
|
||||
fmt.empty_line();
|
||||
|
||||
fmt.doc_comment(r#"
|
||||
Deep-clone an `InstructionData`, including any referenced lists.
|
||||
|
||||
This operation requires a reference to a `ValueListPool` to
|
||||
clone the `ValueLists`.
|
||||
"#);
|
||||
fmt.line("pub fn deep_clone(&self, pool: &mut ir::ValueListPool) -> Self {");
|
||||
fmt.indent(|fmt| {
|
||||
fmt.line("match *self {");
|
||||
fmt.indent(|fmt| {
|
||||
for format in formats {
|
||||
let name = format!("Self::{}", format.name);
|
||||
let mut members = vec!["opcode"];
|
||||
|
||||
if format.has_value_list {
|
||||
members.push("ref args");
|
||||
} else if format.num_value_operands == 1 {
|
||||
members.push("arg");
|
||||
} else if format.num_value_operands > 0 {
|
||||
members.push("args");
|
||||
}
|
||||
|
||||
match format.num_block_operands {
|
||||
0 => {}
|
||||
1 => {
|
||||
members.push("destination");
|
||||
}
|
||||
_ => {
|
||||
members.push("blocks");
|
||||
}
|
||||
};
|
||||
|
||||
for field in &format.imm_fields {
|
||||
members.push(field.member);
|
||||
}
|
||||
let members = members.join(", ");
|
||||
|
||||
fmtln!(fmt, "{}{{{}}} => {{", name, members ); // beware the moustaches
|
||||
fmt.indent(|fmt| {
|
||||
fmtln!(fmt, "Self::{} {{", format.name);
|
||||
fmt.indent(|fmt| {
|
||||
fmtln!(fmt, "opcode,");
|
||||
|
||||
if format.has_value_list {
|
||||
fmtln!(fmt, "args: args.deep_clone(pool),");
|
||||
} else if format.num_value_operands == 1 {
|
||||
fmtln!(fmt, "arg,");
|
||||
} else if format.num_value_operands > 0 {
|
||||
fmtln!(fmt, "args,");
|
||||
}
|
||||
|
||||
match format.num_block_operands {
|
||||
0 => {}
|
||||
1 => {
|
||||
fmtln!(fmt, "destination: destination.deep_clone(pool),");
|
||||
}
|
||||
2 => {
|
||||
fmtln!(fmt, "blocks: [blocks[0].deep_clone(pool), blocks[1].deep_clone(pool)],");
|
||||
}
|
||||
_ => panic!("Too many block targets in instruction"),
|
||||
}
|
||||
|
||||
for field in &format.imm_fields {
|
||||
fmtln!(fmt, "{},", field.member);
|
||||
}
|
||||
});
|
||||
fmtln!(fmt, "}");
|
||||
});
|
||||
fmtln!(fmt, "}");
|
||||
}
|
||||
});
|
||||
fmt.line("}");
|
||||
});
|
||||
fmt.line("}");
|
||||
});
|
||||
fmt.line("}");
|
||||
|
||||
Reference in New Issue
Block a user