souper-harvest: Do not generate assignments of constants
It turns out that Souper does not allow a constant to be assigned to a variable, they may only be used as operands. The 2.0.0 version of the `souper-ir` crate correctly reflects this. In the `cranelift_codegen::souper_harvest` module, we need to modify our Souper IR harvester so that it delays converting `iconst` and `bconst` into Souper IR until their values are used as operands. Finally, some unit tests in the `peepmatic-souper` crate need some small updates as well.
This commit is contained in:
@@ -142,7 +142,49 @@ fn harvest_candidate_lhs(
|
||||
let souper_assignment_rhs = match func.dfg.value_def(val) {
|
||||
ir::ValueDef::Result(inst, 0) => {
|
||||
let args = func.dfg.inst_args(inst);
|
||||
let arg = |allocs: &mut Allocs, n| allocs.ir_to_souper_val[&args[n]].into();
|
||||
|
||||
// Get the n^th argument as a souper operand.
|
||||
let arg = |allocs: &mut Allocs, n| {
|
||||
let arg = args[n];
|
||||
if let Some(a) = allocs.ir_to_souper_val.get(&arg).copied() {
|
||||
a.into()
|
||||
} else {
|
||||
// The only arguments we get that we haven't already
|
||||
// converted into a souper instruction are `iconst`s and
|
||||
// `bconst`s. This is because souper only allows
|
||||
// constants as operands, and it doesn't allow assigning
|
||||
// constants to a variable name. So we lazily convert
|
||||
// `iconst`s and `bconst`s into souper operands here,
|
||||
// when they are actually used.
|
||||
match func.dfg.value_def(arg) {
|
||||
ir::ValueDef::Result(inst, 0) => match func.dfg[inst] {
|
||||
ir::InstructionData::UnaryImm { opcode, imm } => {
|
||||
debug_assert_eq!(opcode, ir::Opcode::Iconst);
|
||||
let imm: i64 = imm.into();
|
||||
ast::Operand::Constant(ast::Constant {
|
||||
value: imm.into(),
|
||||
r#type: souper_type_of(&func.dfg, arg),
|
||||
})
|
||||
}
|
||||
ir::InstructionData::UnaryBool { opcode, imm } => {
|
||||
debug_assert_eq!(opcode, ir::Opcode::Iconst);
|
||||
ast::Operand::Constant(ast::Constant {
|
||||
value: imm.into(),
|
||||
r#type: souper_type_of(&func.dfg, arg),
|
||||
})
|
||||
}
|
||||
_ => unreachable!(
|
||||
"only iconst and bconst instructions \
|
||||
aren't in `ir_to_souper_val`"
|
||||
),
|
||||
},
|
||||
_ => unreachable!(
|
||||
"only iconst and bconst instructions \
|
||||
aren't in `ir_to_souper_val`"
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match (func.dfg[inst].opcode(), &func.dfg[inst]) {
|
||||
(ir::Opcode::Iadd, _) => {
|
||||
@@ -421,23 +463,13 @@ fn harvest_candidate_lhs(
|
||||
let b = arg(allocs, 1);
|
||||
ast::Instruction::UsubSat { a, b }.into()
|
||||
}
|
||||
(ir::Opcode::Iconst, ir::InstructionData::UnaryImm { imm, .. }) => {
|
||||
let value: i64 = (*imm).into();
|
||||
let value: i128 = value.into();
|
||||
ast::Constant {
|
||||
value,
|
||||
r#type: souper_type_of(&func.dfg, val),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
(ir::Opcode::Bconst, ir::InstructionData::UnaryBool { imm, .. }) => {
|
||||
let value = *imm as i128;
|
||||
ast::Constant {
|
||||
value,
|
||||
r#type: souper_type_of(&func.dfg, val),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
// Because Souper doesn't allow constants to be on the right
|
||||
// hand side of an assignment (i.e. `%0:i32 = 1234` is
|
||||
// disallowed) we have to ignore `iconst` and `bconst`
|
||||
// instructions until we process them as operands for some
|
||||
// other instruction. See the `arg` closure above for
|
||||
// details.
|
||||
(ir::Opcode::Iconst, _) | (ir::Opcode::Bconst, _) => return,
|
||||
_ => ast::AssignmentRhs::Var,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user