Skip to content

Commit 19f27a2

Browse files
committed
add for overflow operations and exception handling, use LDC for large ints instead of clamping.
1 parent 899ad63 commit 19f27a2

File tree

3 files changed

+238
-100
lines changed

3 files changed

+238
-100
lines changed

src/lower1.rs

Lines changed: 124 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ fn convert_basic_block<'tcx>(
148148
bb_data: &BasicBlockData<'tcx>,
149149
tcx: TyCtxt<'tcx>,
150150
return_oomir_type: &oomir::Type, // Pass function return type
151+
basic_blocks: &mut HashMap<String, oomir::BasicBlock>,
151152
) -> oomir::BasicBlock {
152153
// Use the basic block index as its label.
153154
let label = format!("bb{}", bb.index());
@@ -162,7 +163,6 @@ fn convert_basic_block<'tcx>(
162163
let oomir_op1 = convert_operand(op1, tcx);
163164
let oomir_op2 = convert_operand(op2, tcx);
164165

165-
// --- MODIFICATION FOR CHECKED OPS ---
166166
match bin_op {
167167
// Non-checked ops remain the same
168168
BinOp::Add => instructions.push(oomir::Instruction::Add { dest, op1: oomir_op1, op2: oomir_op2 }),
@@ -173,19 +173,46 @@ fn convert_basic_block<'tcx>(
173173
BinOp::Rem => {
174174
instructions.push(oomir::Instruction::Rem { dest, op1: oomir_op1, op2: oomir_op2 });
175175
}
176-
// Checked ops: Generate the standard op, implicitly discarding overflow flag.
177-
// The `dest` variable will now only hold the integer result, not the tuple.
176+
// Checked ops: Generate a tuple with result and overflow flag
178177
BinOp::AddWithOverflow => {
179-
println!("Info: Mapping AddWithOverflow to simple Add, discarding overflow flag. Dest '{}' holds i32 result.", dest);
180-
instructions.push(oomir::Instruction::Add { dest, op1: oomir_op1, op2: oomir_op2 });
181-
}
182-
BinOp::SubWithOverflow => {
183-
println!("Info: Mapping SubWithOverflow to simple Sub, discarding overflow flag. Dest '{}' holds i32 result.", dest);
184-
instructions.push(oomir::Instruction::Sub { dest, op1: oomir_op1, op2: oomir_op2 });
185-
}
186-
BinOp::MulWithOverflow => {
187-
println!("Info: Mapping MulWithOverflow to simple Mul, discarding overflow flag. Dest '{}' holds i32 result.", dest);
188-
instructions.push(oomir::Instruction::Mul { dest, op1: oomir_op1, op2: oomir_op2 });
178+
let tuple_dest = format!("{}_tuple", dest);
179+
instructions.push(oomir::Instruction::AddWithOverflow {
180+
dest: tuple_dest.clone(),
181+
op1: oomir_op1,
182+
op2: oomir_op2,
183+
});
184+
185+
// Split the tuple into result and overflow flag
186+
let result_dest = format!("{}_result", tuple_dest);
187+
let overflow_dest = format!("{}_overflow", tuple_dest);
188+
instructions.push(oomir::Instruction::Move {
189+
src: oomir::Operand::Variable(result_dest.clone()),
190+
dest: format!("{}.0", dest),
191+
});
192+
instructions.push(oomir::Instruction::Move {
193+
src: oomir::Operand::Variable(overflow_dest.clone()),
194+
dest: format!("{}.1", dest),
195+
});
196+
},
197+
BinOp::SubWithOverflow => {
198+
let tuple_dest = format!("{}_tuple", dest);
199+
instructions.push(oomir::Instruction::SubWithOverflow {
200+
dest: tuple_dest.clone(),
201+
op1: oomir_op1,
202+
op2: oomir_op2,
203+
});
204+
205+
// Split the tuple into result and overflow flag
206+
let result_dest = format!("{}_result", tuple_dest);
207+
let overflow_dest = format!("{}_overflow", tuple_dest);
208+
instructions.push(oomir::Instruction::Move {
209+
src: oomir::Operand::Variable(result_dest.clone()),
210+
dest: format!("{}.0", dest),
211+
});
212+
instructions.push(oomir::Instruction::Move {
213+
src: oomir::Operand::Variable(overflow_dest.clone()),
214+
dest: format!("{}.1", dest),
215+
});
189216
}
190217
// Default case for other binary ops
191218
_ => {
@@ -198,31 +225,56 @@ fn convert_basic_block<'tcx>(
198225
// Convert the MIR operand (_1, constant, _7.0, etc.)
199226
let mut src_oomir_operand = convert_operand(mir_operand, tcx);
200227

201-
println!("Info: Converting Rvalue::Use to OOMIR operand: {:?}", src_oomir_operand);
202-
203228
// Check if the *source* operand is a variable that looks like a tuple field access
204229
if let oomir::Operand::Variable(ref src_name) = src_oomir_operand {
205-
println!("Info: Source operand is a variable: {}", src_name);
206-
// Check common tuple field projections explicitly
207-
if src_name.ends_with(".0") || src_name.ends_with(".1") {
208-
// Extract the base variable name (e.g., "_7" from "_7.0")
209-
if let Some((base_var, _)) = src_name.rsplit_once('.') {
210-
println!("Info: Adjusting Rvalue::Use source operand {} to base {} for Move instruction to dest '{}'.", src_name, base_var, dest);
211-
// Replace the operand with one using just the base name
212-
src_oomir_operand = oomir::Operand::Variable(base_var.to_string());
213-
} else {
214-
println!("Warning: Failed to extract base variable from tuple field access: {}", src_name);
215-
}
216-
} else {
217-
println!("Info: Source operand is a variable, but not a tuple field access: {}", src_name);
218-
}
219-
} else {
220-
println!("Warning: Unhandled source operand type {:?}", src_oomir_operand);
221-
}
230+
if src_name.contains('.') {
231+
// Handle tuple projections (e.g., _7.0, _7.1)
232+
if let Some((base_var, field)) = src_name.split_once('.') {
233+
let projection_var = format!("{}_proj_{}", base_var, field);
234+
instructions.push(oomir::Instruction::Move {
235+
dest: projection_var.clone(),
236+
src: oomir::Operand::Variable(src_name.clone()),
237+
});
238+
src_oomir_operand = oomir::Operand::Variable(projection_var);
239+
}
240+
}
241+
}
222242

223243
// Generate the OOMIR Move instruction with the (potentially adjusted) source
224244
instructions.push(oomir::Instruction::Move { dest: dest.clone(), src: src_oomir_operand });
225-
}
245+
}
246+
Rvalue::Aggregate(box kind, operands) => {
247+
match kind {
248+
rustc_middle::mir::AggregateKind::Tuple => {
249+
// 'dest' here is the name of the tuple itself (e.g., "_2")
250+
// We need to define its fields.
251+
if operands.len() > 2 {
252+
println!("Warning: Tuple aggregate with >2 fields not fully handled: {}", dest);
253+
}
254+
for (i, mir_op) in operands.iter().enumerate() {
255+
// Define the field variable name (e.g., "_2.0")
256+
let field_dest = format!("{}.{}", dest, i);
257+
let field_src = convert_operand(mir_op, tcx);
258+
// Generate a Move to define the field variable
259+
instructions.push(oomir::Instruction::Move {
260+
dest: field_dest,
261+
src: field_src,
262+
});
263+
}
264+
// We might not need an explicit instruction for the tuple 'dest' itself
265+
// if we only ever access its fields directly via the ".N" names.
266+
}
267+
_ => {
268+
println!("Warning: Unhandled aggregate kind {:?} for dest {}", kind, dest);
269+
// Assign a default/dummy value? Might cause issues later.
270+
// For now, maybe push a placeholder move:
271+
instructions.push(oomir::Instruction::Move {
272+
dest: dest.clone(),
273+
src: oomir::Operand::Constant(oomir::Constant::I32(0)), // Placeholder!
274+
});
275+
}
276+
}
277+
}
226278
_ => {
227279
println!("Warning: Unhandled rvalue {:?}", rvalue);
228280
}
@@ -326,14 +378,44 @@ fn convert_basic_block<'tcx>(
326378
println!("Info: Call in bb{} has no return target (diverges).", bb.index());
327379
}
328380
}
329-
TerminatorKind::Assert { target, cond: _, expected: _, msg: _, unwind: _ } => {
330-
// Instead of ignoring, treat it as an unconditional jump to the success path `target`.
331-
// This ignores the assertion check itself but preserves the essential control flow.
332-
let target_label = format!("bb{}", target.index());
333-
println!("Info: Treating Assert Terminator in bb{} as unconditional jump to {}", bb.index(), target_label);
334-
instructions.push(oomir::Instruction::Jump { target: target_label });
335-
// NOTE: The assertion condition (`cond`) might have been computed in a previous statement
336-
// (e.g., _3 = Eq(...)). That statement still exists, but the Branch/Assert based on it is replaced by Jump.
381+
TerminatorKind::Assert { target, cond, expected, msg, unwind: _ } => {
382+
// Convert the condition operand
383+
let condition = convert_operand(cond, tcx);
384+
385+
// Generate a comparison instruction to check if the condition matches the expected value
386+
let comparison_dest = format!("assert_cmp_{}", bb.index());
387+
instructions.push(oomir::Instruction::Eq {
388+
dest: comparison_dest.clone(),
389+
op1: condition,
390+
op2: oomir::Operand::Constant(oomir::Constant::Boolean(*expected)),
391+
});
392+
393+
// Generate a branch based on the comparison result
394+
let true_block = format!("bb{}", target.index()); // Success path
395+
let false_block = format!("assert_fail_{}", bb.index()); // Failure path label
396+
instructions.push(oomir::Instruction::Branch {
397+
condition: oomir::Operand::Variable(comparison_dest),
398+
true_block, // Jump here if assertion holds (cond == expected)
399+
false_block: false_block.clone(), // Jump here if assertion fails
400+
});
401+
402+
// Add a new basic block for the assertion failure (panic)
403+
let fail_instructions = vec![
404+
oomir::Instruction::ThrowNewWithMessage {
405+
// For now, hardcode RuntimeException. Could be configurable later.
406+
exception_class: "java/lang/RuntimeException".to_string(),
407+
// Extract the format string as the message.
408+
// TODO: Handle msg.args() for formatted messages later.
409+
message: format!("{:?}", msg),
410+
},
411+
];
412+
basic_blocks.insert( // Ensure 'basic_blocks' map is mutable and passed in
413+
false_block.clone(),
414+
oomir::BasicBlock {
415+
label: false_block,
416+
instructions: fail_instructions,
417+
},
418+
);
337419
}
338420
// Other terminator kinds (like Resume, etc.) can be added as needed.
339421
_ => {
@@ -392,7 +474,7 @@ pub fn mir_to_oomir<'tcx>(
392474
let entry_label = "bb0".to_string();
393475

394476
for (bb, bb_data) in mir.basic_blocks_mut().iter_enumerated() {
395-
let bb_ir = convert_basic_block(bb, bb_data, tcx, &return_oomir_ty); // Pass return type here
477+
let bb_ir = convert_basic_block(bb, bb_data, tcx, &return_oomir_ty, &mut basic_blocks); // Pass return type here
396478
basic_blocks.insert(bb_ir.label.clone(), bb_ir);
397479
}
398480

0 commit comments

Comments
 (0)