@@ -148,6 +148,7 @@ fn convert_basic_block<'tcx>(
148
148
bb_data : & BasicBlockData < ' tcx > ,
149
149
tcx : TyCtxt < ' tcx > ,
150
150
return_oomir_type : & oomir:: Type , // Pass function return type
151
+ basic_blocks : & mut HashMap < String , oomir:: BasicBlock > ,
151
152
) -> oomir:: BasicBlock {
152
153
// Use the basic block index as its label.
153
154
let label = format ! ( "bb{}" , bb. index( ) ) ;
@@ -162,7 +163,6 @@ fn convert_basic_block<'tcx>(
162
163
let oomir_op1 = convert_operand ( op1, tcx) ;
163
164
let oomir_op2 = convert_operand ( op2, tcx) ;
164
165
165
- // --- MODIFICATION FOR CHECKED OPS ---
166
166
match bin_op {
167
167
// Non-checked ops remain the same
168
168
BinOp :: Add => instructions. push ( oomir:: Instruction :: Add { dest, op1 : oomir_op1, op2 : oomir_op2 } ) ,
@@ -173,19 +173,46 @@ fn convert_basic_block<'tcx>(
173
173
BinOp :: Rem => {
174
174
instructions. push ( oomir:: Instruction :: Rem { dest, op1 : oomir_op1, op2 : oomir_op2 } ) ;
175
175
}
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
178
177
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
+ } ) ;
189
216
}
190
217
// Default case for other binary ops
191
218
_ => {
@@ -198,31 +225,56 @@ fn convert_basic_block<'tcx>(
198
225
// Convert the MIR operand (_1, constant, _7.0, etc.)
199
226
let mut src_oomir_operand = convert_operand ( mir_operand, tcx) ;
200
227
201
- println ! ( "Info: Converting Rvalue::Use to OOMIR operand: {:?}" , src_oomir_operand) ;
202
-
203
228
// Check if the *source* operand is a variable that looks like a tuple field access
204
229
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
+ }
222
242
223
243
// Generate the OOMIR Move instruction with the (potentially adjusted) source
224
244
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
+ }
226
278
_ => {
227
279
println ! ( "Warning: Unhandled rvalue {:?}" , rvalue) ;
228
280
}
@@ -326,14 +378,44 @@ fn convert_basic_block<'tcx>(
326
378
println ! ( "Info: Call in bb{} has no return target (diverges)." , bb. index( ) ) ;
327
379
}
328
380
}
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
+ ) ;
337
419
}
338
420
// Other terminator kinds (like Resume, etc.) can be added as needed.
339
421
_ => {
@@ -392,7 +474,7 @@ pub fn mir_to_oomir<'tcx>(
392
474
let entry_label = "bb0" . to_string ( ) ;
393
475
394
476
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
396
478
basic_blocks. insert ( bb_ir. label . clone ( ) , bb_ir) ;
397
479
}
398
480
0 commit comments