Skip to content

Commit 01e5ec6

Browse files
committed
Breaking modules out into several files - improved structure/maintainability.
1 parent 93df647 commit 01e5ec6

File tree

14 files changed

+4261
-3855
lines changed

14 files changed

+4261
-3855
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ sha2 = "0.10.8"
1212

1313
[lib]
1414
crate-type = ["dylib"]
15+
16+
[package.metadata.rust-analyzer]
17+
rustc_private=true

src/lib.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,9 @@ impl CodegenBackend for MyBackend {
133133
CrateInfo,
134134
)>()
135135
.expect("in join_codegen: ongoing_codegen is not a bytecode map");
136-
136+
137137
let mut compiled_modules = Vec::new();
138-
138+
139139
// Iterate over each (file_name, bytecode) pair in the map.
140140
for (name, bytecode) in bytecode_map.into_iter() {
141141
let file_path = outputs.temp_path_ext_for_cgu(&name, ".class", None);
@@ -145,13 +145,19 @@ impl CodegenBackend for MyBackend {
145145

146146
// make the actual file path by adding {name}.class to the directory
147147
let file_path = dir.join(format!("{}.class", name));
148-
148+
149149
// Write the bytecode to the file
150-
let mut file = std::fs::File::create(&file_path)
151-
.unwrap_or_else(|e| panic!("Could not create file {}: {}", file_path.display(), e));
152-
file.write_all(&bytecode)
153-
.unwrap_or_else(|e| panic!("Could not write bytecode to file {}: {}", file_path.display(), e));
154-
150+
let mut file = std::fs::File::create(&file_path).unwrap_or_else(|e| {
151+
panic!("Could not create file {}: {}", file_path.display(), e)
152+
});
153+
file.write_all(&bytecode).unwrap_or_else(|e| {
154+
panic!(
155+
"Could not write bytecode to file {}: {}",
156+
file_path.display(),
157+
e
158+
)
159+
});
160+
155161
// Create a CompiledModule for this file
156162
compiled_modules.push(CompiledModule {
157163
name: name.clone(),
@@ -164,7 +170,7 @@ impl CodegenBackend for MyBackend {
164170
assembly: None,
165171
});
166172
}
167-
173+
168174
let codegen_results = CodegenResults {
169175
modules: compiled_modules,
170176
allocator_module: None,
@@ -176,7 +182,7 @@ impl CodegenBackend for MyBackend {
176182
}))
177183
.expect("Could not join_codegen")
178184
}
179-
185+
180186
fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) {
181187
println!("linking!");
182188
use rustc_codegen_ssa::back::link::link_binary;

src/lower1.rs

Lines changed: 10 additions & 2086 deletions
Large diffs are not rendered by default.

src/lower1/checked_ops.rs

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
use crate::oomir;
2+
3+
pub fn emit_checked_arithmetic_oomir_instructions(
4+
dest_base_name: &str,
5+
op1: &oomir::Operand,
6+
op2: &oomir::Operand,
7+
op_ty: &oomir::Type,
8+
operation: &str,
9+
unique_id_offset: usize, // Used to ensure unique labels/temps
10+
) -> (Vec<oomir::Instruction>, String, String) {
11+
let mut generated_instructions = Vec::new();
12+
13+
// --- Generate unique temporary variable names and labels ---
14+
let unique_id = unique_id_offset; // Use offset for uniqueness
15+
let tmp_a = format!("{}_{}_chk_a_{}", dest_base_name, operation, unique_id);
16+
let tmp_b = format!("{}_{}_chk_b_{}", dest_base_name, operation, unique_id);
17+
let tmp_result = format!("{}_{}_chk_res_{}", dest_base_name, operation, unique_id);
18+
let tmp_overflow = format!("{}_{}_chk_ovf_{}", dest_base_name, operation, unique_id);
19+
20+
// Labels for control flow *within* this sequence
21+
let label_check_neg = format!(
22+
"label_{}_{}_chk_neg_{}",
23+
dest_base_name, operation, unique_id
24+
);
25+
let label_overflow = format!(
26+
"label_{}_{}_chk_ovf_{}",
27+
dest_base_name, operation, unique_id
28+
);
29+
let label_no_overflow = format!(
30+
"label_{}_{}_chk_no_ovf_{}",
31+
dest_base_name, operation, unique_id
32+
);
33+
let label_end = format!(
34+
"label_{}_{}_chk_end_{}",
35+
dest_base_name, operation, unique_id
36+
);
37+
38+
// Labels for intermediate targets within the checks to avoid unstructured jumps
39+
let lbl_pos_check_b_non_neg = format!(
40+
"lbl_{}_{}_pos_chk_b_non_neg_{}",
41+
dest_base_name, operation, unique_id
42+
);
43+
let lbl_pos_check_final_cmp = format!(
44+
"lbl_{}_{}_pos_check_final_cmp_{}",
45+
dest_base_name, operation, unique_id
46+
);
47+
let lbl_neg_check_b_non_pos = format!(
48+
"lbl_{}_{}_neg_chk_b_non_pos_{}",
49+
dest_base_name, operation, unique_id
50+
);
51+
let lbl_neg_check_final_cmp = format!(
52+
"lbl_{}_{}_neg_chk_final_cmp_{}",
53+
dest_base_name, operation, unique_id
54+
);
55+
56+
// --- Load operands into temporary variables ---
57+
generated_instructions.push(oomir::Instruction::Move {
58+
dest: tmp_a.clone(),
59+
src: op1.clone(),
60+
});
61+
generated_instructions.push(oomir::Instruction::Move {
62+
dest: tmp_b.clone(),
63+
src: op2.clone(),
64+
});
65+
66+
let op1_var = oomir::Operand::Variable {
67+
name: tmp_a.clone(),
68+
ty: op_ty.clone(),
69+
};
70+
let op2_var = oomir::Operand::Variable {
71+
name: tmp_b.clone(),
72+
ty: op_ty.clone(),
73+
};
74+
75+
// --- Get MIN/MAX constants ---
76+
let (const_max, const_min) = match op_ty {
77+
oomir::Type::I32 => (
78+
oomir::Constant::I32(i32::MAX),
79+
oomir::Constant::I32(i32::MIN),
80+
),
81+
// TODO: Add other types like I64
82+
_ => panic!(
83+
"Checked arithmetic not implemented for OOMIR type {:?}",
84+
op_ty
85+
),
86+
};
87+
88+
// --- Start Positive Overflow Check ---
89+
let tmp_cmp1 = format!("{}_{}_chk_cmp1_{}", dest_base_name, operation, unique_id);
90+
generated_instructions.push(oomir::Instruction::Gt {
91+
dest: tmp_cmp1.clone(),
92+
op1: op1_var.clone(),
93+
op2: oomir::Operand::Constant(oomir::Constant::I32(0)),
94+
});
95+
generated_instructions.push(oomir::Instruction::Branch {
96+
condition: oomir::Operand::Variable {
97+
name: tmp_cmp1.clone(),
98+
ty: oomir::Type::Boolean,
99+
},
100+
true_block: lbl_pos_check_b_non_neg.clone(),
101+
false_block: label_check_neg.clone(),
102+
}); // If a > 0 goto check b, else goto neg check
103+
104+
// --- Positive Check: Check B --- (Label: lbl_pos_check_b_non_neg)
105+
generated_instructions.push(oomir::Instruction::Label {
106+
name: lbl_pos_check_b_non_neg.clone(),
107+
});
108+
let tmp_cmp2 = format!("{}_{}_chk_cmp2_{}", dest_base_name, operation, unique_id);
109+
generated_instructions.push(oomir::Instruction::Gt {
110+
dest: tmp_cmp2.clone(),
111+
op1: op2_var.clone(),
112+
op2: oomir::Operand::Constant(oomir::Constant::I32(0)),
113+
});
114+
generated_instructions.push(oomir::Instruction::Branch {
115+
condition: oomir::Operand::Variable {
116+
name: tmp_cmp2.clone(),
117+
ty: oomir::Type::Boolean,
118+
},
119+
true_block: lbl_pos_check_final_cmp.clone(),
120+
false_block: label_check_neg.clone(),
121+
}); // If b > 0 goto final check, else goto neg check
122+
123+
// --- Positive Check: Final Comparison --- (Label: lbl_pos_check_final_cmp)
124+
generated_instructions.push(oomir::Instruction::Label {
125+
name: lbl_pos_check_final_cmp.clone(),
126+
});
127+
let tmp_max_minus_a = format!(
128+
"{}_{}_chk_max_minus_a_{}",
129+
dest_base_name, operation, unique_id
130+
);
131+
let tmp_cmp3 = format!("{}_{}_chk_cmp3_{}", dest_base_name, operation, unique_id);
132+
generated_instructions.push(oomir::Instruction::Sub {
133+
dest: tmp_max_minus_a.clone(),
134+
op1: oomir::Operand::Constant(const_max),
135+
op2: op1_var.clone(),
136+
});
137+
generated_instructions.push(oomir::Instruction::Gt {
138+
dest: tmp_cmp3.clone(),
139+
op1: op2_var.clone(),
140+
op2: oomir::Operand::Variable {
141+
name: tmp_max_minus_a.clone(),
142+
ty: op_ty.clone(),
143+
},
144+
});
145+
generated_instructions.push(oomir::Instruction::Branch {
146+
condition: oomir::Operand::Variable {
147+
name: tmp_cmp3.clone(),
148+
ty: oomir::Type::Boolean,
149+
},
150+
true_block: label_overflow.clone(),
151+
false_block: label_check_neg.clone(),
152+
}); // If b > MAX-a goto overflow, else goto neg check
153+
154+
// --- Start Negative Overflow Check --- (Label: label_check_neg)
155+
generated_instructions.push(oomir::Instruction::Label {
156+
name: label_check_neg.clone(),
157+
});
158+
let tmp_cmp4 = format!("{}_{}_chk_cmp4_{}", dest_base_name, operation, unique_id);
159+
generated_instructions.push(oomir::Instruction::Lt {
160+
dest: tmp_cmp4.clone(),
161+
op1: op1_var.clone(),
162+
op2: oomir::Operand::Constant(oomir::Constant::I32(0)),
163+
});
164+
generated_instructions.push(oomir::Instruction::Branch {
165+
condition: oomir::Operand::Variable {
166+
name: tmp_cmp4.clone(),
167+
ty: oomir::Type::Boolean,
168+
},
169+
true_block: lbl_neg_check_b_non_pos.clone(),
170+
false_block: label_no_overflow.clone(),
171+
}); // If a < 0 goto check b, else goto no_overflow
172+
173+
// --- Negative Check: Check B --- (Label: lbl_neg_check_b_non_pos)
174+
generated_instructions.push(oomir::Instruction::Label {
175+
name: lbl_neg_check_b_non_pos.clone(),
176+
});
177+
let tmp_cmp5 = format!("{}_{}_chk_cmp5_{}", dest_base_name, operation, unique_id);
178+
generated_instructions.push(oomir::Instruction::Lt {
179+
dest: tmp_cmp5.clone(),
180+
op1: op2_var.clone(),
181+
op2: oomir::Operand::Constant(oomir::Constant::I32(0)),
182+
});
183+
generated_instructions.push(oomir::Instruction::Branch {
184+
condition: oomir::Operand::Variable {
185+
name: tmp_cmp5.clone(),
186+
ty: oomir::Type::Boolean,
187+
},
188+
true_block: lbl_neg_check_final_cmp.clone(),
189+
false_block: label_no_overflow.clone(),
190+
}); // If b < 0 goto final check, else goto no_overflow
191+
192+
// --- Negative Check: Final Comparison --- (Label: lbl_neg_check_final_cmp)
193+
generated_instructions.push(oomir::Instruction::Label {
194+
name: lbl_neg_check_final_cmp.clone(),
195+
});
196+
let tmp_min_minus_a = format!(
197+
"{}_{}_chk_min_minus_a_{}",
198+
dest_base_name, operation, unique_id
199+
);
200+
let tmp_cmp6 = format!("{}_{}_chk_cmp6_{}", dest_base_name, operation, unique_id);
201+
generated_instructions.push(oomir::Instruction::Sub {
202+
dest: tmp_min_minus_a.clone(),
203+
op1: oomir::Operand::Constant(const_min),
204+
op2: op1_var.clone(),
205+
});
206+
generated_instructions.push(oomir::Instruction::Lt {
207+
dest: tmp_cmp6.clone(),
208+
op1: op2_var.clone(),
209+
op2: oomir::Operand::Variable {
210+
name: tmp_min_minus_a.clone(),
211+
ty: op_ty.clone(),
212+
},
213+
});
214+
generated_instructions.push(oomir::Instruction::Branch {
215+
condition: oomir::Operand::Variable {
216+
name: tmp_cmp6.clone(),
217+
ty: oomir::Type::Boolean,
218+
},
219+
true_block: label_overflow.clone(),
220+
false_block: label_no_overflow.clone(),
221+
}); // If b < MIN-a goto overflow, else goto no_overflow
222+
223+
// --- Overflow Path --- (Label: label_overflow)
224+
generated_instructions.push(oomir::Instruction::Label {
225+
name: label_overflow.clone(),
226+
});
227+
generated_instructions.push(oomir::Instruction::Move {
228+
dest: tmp_overflow.clone(),
229+
src: oomir::Operand::Constant(oomir::Constant::Boolean(true)),
230+
});
231+
// Determine zero value for the type
232+
let zero_val = match op_ty {
233+
oomir::Type::I8 => oomir::Constant::I8(0),
234+
oomir::Type::I16 => oomir::Constant::I16(0),
235+
oomir::Type::I32 => oomir::Constant::I32(0),
236+
oomir::Type::I64 => oomir::Constant::I64(0),
237+
_ => oomir::Constant::I32(0), // Fallback or panic?
238+
};
239+
generated_instructions.push(oomir::Instruction::Move {
240+
dest: tmp_result.clone(),
241+
src: oomir::Operand::Constant(zero_val),
242+
});
243+
generated_instructions.push(oomir::Instruction::Jump {
244+
target: label_end.clone(),
245+
});
246+
247+
// --- No Overflow Path --- (Label: label_no_overflow)
248+
generated_instructions.push(oomir::Instruction::Label {
249+
name: label_no_overflow.clone(),
250+
});
251+
generated_instructions.push(oomir::Instruction::Move {
252+
dest: tmp_overflow.clone(),
253+
src: oomir::Operand::Constant(oomir::Constant::Boolean(false)),
254+
});
255+
// Perform actual operation
256+
match operation {
257+
"add" => generated_instructions.push(oomir::Instruction::Add {
258+
dest: tmp_result.clone(),
259+
op1: op1_var.clone(),
260+
op2: op2_var.clone(),
261+
}),
262+
"sub" => generated_instructions.push(oomir::Instruction::Sub {
263+
dest: tmp_result.clone(),
264+
op1: op1_var.clone(),
265+
op2: op2_var.clone(),
266+
}),
267+
"mul" => generated_instructions.push(oomir::Instruction::Mul {
268+
dest: tmp_result.clone(),
269+
op1: op1_var.clone(),
270+
op2: op2_var.clone(),
271+
}),
272+
_ => panic!("Unsupported checked operation: {}", operation),
273+
}
274+
generated_instructions.push(oomir::Instruction::Jump {
275+
target: label_end.clone(),
276+
}); // Or just fall through to end label? Jump is safer.
277+
278+
// --- End Path --- (Label: label_end)
279+
generated_instructions.push(oomir::Instruction::Label {
280+
name: label_end.clone(),
281+
});
282+
// Result is in tmp_result, overflow flag in tmp_overflow. No instruction needed here.
283+
284+
// Return the generated instructions and the names of the temporary variables
285+
(generated_instructions, tmp_result, tmp_overflow)
286+
}

0 commit comments

Comments
 (0)