fortrangoingonforty/armfortas / 204993d

Browse files

Tighten alias and SROA legality

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
204993d89e4be4e34de759dbbfbbaff386cd71f3
Parents
eb693b5
Tree
99eb0b1

2 changed files

StatusFile+-
M src/opt/alias.rs 50 1
M src/opt/sroa.rs 99 0
src/opt/alias.rsmodified
@@ -145,7 +145,11 @@ fn trace_offset(func: &Function, ptr: ValueId) -> Option<i64> {
145145
             let base_offset = trace_offset(func, *base)?;
146146
             if indices.len() != 1 { return None; }
147147
             let idx = resolve_const_int(func, indices[0])?;
148
-            Some(base_offset + idx)
148
+            let step = match &inst.ty {
149
+                IrType::Ptr(inner) => inner.size_bytes() as i64,
150
+                _ => return None,
151
+            };
152
+            Some(base_offset + idx * step)
149153
         }
150154
         _ => None,
151155
     }
@@ -259,6 +263,51 @@ mod tests {
259263
         assert_eq!(query(&f, a, a), AliasResult::MustAlias);
260264
     }
261265
 
266
+    #[test]
267
+    fn mixed_width_geps_same_index_do_not_must_alias() {
268
+        let mut f = Function::new("test".into(), vec![], IrType::Void);
269
+        let base_ty = IrType::Array(Box::new(IrType::Int(IntWidth::I8)), 384);
270
+        let base = f.next_value_id();
271
+        f.register_type(base, IrType::Ptr(Box::new(base_ty.clone())));
272
+        f.block_mut(f.entry).insts.push(Inst {
273
+            id: base,
274
+            ty: IrType::Ptr(Box::new(base_ty)),
275
+            span: span(),
276
+            kind: InstKind::Alloca(IrType::Array(Box::new(IrType::Int(IntWidth::I8)), 384)),
277
+        });
278
+
279
+        let four = f.next_value_id();
280
+        f.register_type(four, IrType::Int(IntWidth::I64));
281
+        f.block_mut(f.entry).insts.push(Inst {
282
+            id: four,
283
+            ty: IrType::Int(IntWidth::I64),
284
+            span: span(),
285
+            kind: InstKind::ConstInt(4, IntWidth::I64),
286
+        });
287
+
288
+        let gep_i32 = f.next_value_id();
289
+        f.register_type(gep_i32, IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))));
290
+        f.block_mut(f.entry).insts.push(Inst {
291
+            id: gep_i32,
292
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I32))),
293
+            span: span(),
294
+            kind: InstKind::GetElementPtr(base, vec![four]),
295
+        });
296
+
297
+        let gep_i64 = f.next_value_id();
298
+        f.register_type(gep_i64, IrType::Ptr(Box::new(IrType::Int(IntWidth::I64))));
299
+        f.block_mut(f.entry).insts.push(Inst {
300
+            id: gep_i64,
301
+            ty: IrType::Ptr(Box::new(IrType::Int(IntWidth::I64))),
302
+            span: span(),
303
+            kind: InstKind::GetElementPtr(base, vec![four]),
304
+        });
305
+
306
+        f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
307
+
308
+        assert_eq!(query(&f, gep_i32, gep_i64), AliasResult::NoAlias);
309
+    }
310
+
262311
     #[test]
263312
     fn gep_different_offsets_no_alias() {
264313
         let mut f = Function::new("test".into(), vec![], IrType::Void);
src/opt/sroa.rsmodified
@@ -106,6 +106,9 @@ fn is_eligible(func: &Function, alloca_id: ValueId) -> bool {
106106
                             return false;
107107
                         }
108108
                     }
109
+                    if gep_result_escapes(func, inst.id) {
110
+                        return false;
111
+                    }
109112
                     // This use is fine — constant-index element access.
110113
                 }
111114
                 // Store where the alloca is the VALUE being stored = pointer escape.
@@ -130,6 +133,40 @@ fn is_eligible(func: &Function, alloca_id: ValueId) -> bool {
130133
     true
131134
 }
132135
 
136
+fn gep_result_escapes(func: &Function, gep_id: ValueId) -> bool {
137
+    for block in &func.blocks {
138
+        for inst in &block.insts {
139
+            let uses = inst_uses(&inst.kind);
140
+            if !uses.contains(&gep_id) {
141
+                continue;
142
+            }
143
+            match &inst.kind {
144
+                InstKind::Load(ptr) if *ptr == gep_id => {}
145
+                InstKind::Store(_, ptr) if *ptr == gep_id => {}
146
+                _ => return true,
147
+            }
148
+        }
149
+        if let Some(term) = &block.terminator {
150
+            match term {
151
+                Terminator::Return(Some(v)) if *v == gep_id => return true,
152
+                Terminator::Branch(_, args) if args.contains(&gep_id) => return true,
153
+                Terminator::CondBranch { cond, true_args, false_args, .. } => {
154
+                    if *cond == gep_id || true_args.contains(&gep_id) || false_args.contains(&gep_id) {
155
+                        return true;
156
+                    }
157
+                }
158
+                Terminator::Switch { selector, .. } => {
159
+                    if *selector == gep_id {
160
+                        return true;
161
+                    }
162
+                }
163
+                _ => {}
164
+            }
165
+        }
166
+    }
167
+    false
168
+}
169
+
133170
 /// Decompose one alloca into individual scalar allocas.
134171
 fn decompose_alloca(func: &mut Function, cand: &SroaCandidate) -> bool {
135172
     // Create N individual allocas, one per field.
@@ -229,4 +266,66 @@ mod tests {
229266
         let pass = Sroa;
230267
         assert!(!pass.run(&mut m), "scalar alloca should not be decomposed");
231268
     }
269
+
270
+    #[test]
271
+    fn sroa_rejects_gep_address_escape() {
272
+        let mut m = Module::new("test".into());
273
+        let mut f = Function::new("test".into(), vec![], IrType::Void);
274
+        let arr_ty = IrType::Array(
275
+            Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8)))),
276
+            2,
277
+        );
278
+        let arr = f.next_value_id();
279
+        f.register_type(arr, IrType::Ptr(Box::new(arr_ty.clone())));
280
+        f.block_mut(f.entry).insts.push(Inst {
281
+            id: arr,
282
+            ty: IrType::Ptr(Box::new(arr_ty)),
283
+            span: span(),
284
+            kind: InstKind::Alloca(IrType::Array(
285
+                Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8)))),
286
+                2,
287
+            )),
288
+        });
289
+
290
+        let zero = f.next_value_id();
291
+        f.register_type(zero, IrType::Int(IntWidth::I64));
292
+        f.block_mut(f.entry).insts.push(Inst {
293
+            id: zero,
294
+            ty: IrType::Int(IntWidth::I64),
295
+            span: span(),
296
+            kind: InstKind::ConstInt(0, IntWidth::I64),
297
+        });
298
+
299
+        let gep = f.next_value_id();
300
+        f.register_type(gep, IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))))));
301
+        f.block_mut(f.entry).insts.push(Inst {
302
+            id: gep,
303
+            ty: IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))))),
304
+            span: span(),
305
+            kind: InstKind::GetElementPtr(arr, vec![zero]),
306
+        });
307
+
308
+        let sink = f.next_value_id();
309
+        f.register_type(sink, IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))))))));
310
+        f.block_mut(f.entry).insts.push(Inst {
311
+            id: sink,
312
+            ty: IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8))))))),
313
+            span: span(),
314
+            kind: InstKind::Alloca(IrType::Ptr(Box::new(IrType::Ptr(Box::new(IrType::Int(IntWidth::I8)))))),
315
+        });
316
+
317
+        let escape_store = f.next_value_id();
318
+        f.register_type(escape_store, IrType::Void);
319
+        f.block_mut(f.entry).insts.push(Inst {
320
+            id: escape_store,
321
+            ty: IrType::Void,
322
+            span: span(),
323
+            kind: InstKind::Store(gep, sink),
324
+        });
325
+
326
+        f.block_mut(f.entry).terminator = Some(Terminator::Return(None));
327
+        m.add_function(f);
328
+
329
+        assert!(!Sroa.run(&mut m), "GEP addresses that escape should block SROA");
330
+    }
232331
 }