Skip to content

Commit 2afbab5

Browse files
authored
[CIR][ThroughMLIR] Improving eraseIfSafe and canonical ForOp lowering (#1660)
Fixes #1405 ## Improving eraseIfSafe: as far as I understand it eraseIfSafe should intuativly check if all memref load/store ops are created, which obtain offsets from the memref.reinterpret_cast in the eraseList. If so the operations in the eraseList are erased, otherwise they are kept until all cir.load/store ops relying on them are lowered. One challenge here is that we can't actually do this by checking the uses of memref.reinterpret_cast operations, as their results aren't actually used in the created memref load/store ops (the base alloca result found via findBaseAndIndices is used). Because of this, this base alloca result is passed as the newAddr Value to eraseIfSafe in the [cir.load](https://github.com/llvm/clangir/blob/6e5fa09550c98f84d017873ed3e5667fd5fd909c/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp#L236C5-L242C6)/[cir.store](https://github.com/llvm/clangir/blob/6e5fa09550c98f84d017873ed3e5667fd5fd909c/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp#L266C1-L271C6) lowerings. Currently the eraseIfSafe function counts all memref.load/store values that use this base address: https://github.com/llvm/clangir/blob/6e5fa09550c98f84d017873ed3e5667fd5fd909c/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp#L215-L218 The problem here is that this also counts all the other memref.load/store ops, which store/load to/from the base address, but don't use the memref.reinterpret_cast ops to obtain the offsets. Because of this the lowering fails if multiple store/loads to/from the same array are performed in the original C code as in the example of issue #1405. Because we are erroneously counting all the other memref.load/store ops, the newUsedNum is (for the later stores) larger than oldUsedNum (only the uses of the cir.ptr_stride op) and the memref.reinterpret_cast ops are not removed. This PR contains a first attempt to fix this (i.e only count the memref.load/store ops, which obtain offsets from the memref.reinterpret_cast in the eraseList). I only count memref.load/store ops, if the first offset value, corresponds to the offset value in the last memref.reinterpret_cast. Limitations of this PR: This fixes the indirect lowering of the example in issue #1405 and also works for other test I made where multiple store/loads to/from the same array, but assumes two thing to be the case: 1. The cir.const used as the stride in the cir.ptr_str is not reused in other cir.ptr_stride ops 2. Only the last cir.ptr_stride can have multiple uses (for multidim arrays) Both of these assumptions seem to be true for the C-Code I testet (for the translation of accesses to C/C++ Arrays to cir ops). But the eraseIfSafe function might need to be changed/further improved in the future to support cases, where those assumptions fail. For example if an optimization is run on cir where the cir.const ops with the same value are reused for the different cir.ptr_stride ops, the indirect lowering would still fail. Or if in a multidimensional array a subarray is accessed, e.g. ```c int arr[3][4]; int *row = arr[1]; ``` (Note: I pretty sure for this it isn't suffiicient to just extend the function to check if all offset value, corresponds to the offset value in the all memref.reinterpret_cast, but we would probably need to seperatly check for each memref.reinterpret_cast if it can be removed (instead of removing all or non in the eraseList)) ## Improving the lowering of canonical ForOps: While debugging issue #1405 I noticed a few thing that I think could be improved in the canonical ForOp lowering: 1. There is one edge case, where the forOp should not be marked as canonical in my opinion: ```c int i; for (i = 0; i < 100; i++); i += 10; ``` (with the current lowering this for is marked canonical but since i is replaced by the induction var of the scf.for op and the actual memory representing i is not updated i has a wrong value after the for. This is avoided when we lower this for as a non canonical for.) 2. I think we can directly replace the loads to the CIR.IV with the scf.IV and not create the dummy arith.add IV, 0 op (I think this might be a relic from previous MLIR version where the replaceOp only worked with operations (not values). This make the IR more readable and easier to understand. If I'm missing somethink here and the arith.add IV, 0 has a purpose I'm not seeing let me know. 3. When implementing the change in 1, we know that in a canonical for the induction variable is definied inside the for and is only valid here. Because of this and since we replace the loads of the cir IV with the scf.IV we can remove the unneccessary alloca and store op created for the cir.IV (These changes only show up in an non-optimized binary, but aren't relevant when running clang with optimations, I still think they improve the readability + understandability of the core ir) ## Running SCFPreparePass cir pass always when lowering throughMLIR: I also noticed, that we are currently only running the SCFPreparePass when we are printing the result of the cir to core dialect translation. https://github.com/llvm/clangir/blob/6e5fa09550c98f84d017873ed3e5667fd5fd909c/clang/lib/CIR/CodeGen/CIRPasses.cpp#L84-L85 Because of this compiling to an object file (or llvm IR) with the indirect lowering path fails, if the code contains a canonical for. I suggest always running this pass, when were going throughMLIR. ## Passing through is_nontemporal in loads/store lowerings: Since the corresponding memref ops also have this attribute it's basically just passing through a boolean (and doesn't need any special handling, I think). Even tho there is probably no practical application now I think this might avoid bugs/confusion in the future. If there is any reason not to do this let me know. I also added a new test case for arrays, adjusted the canonical forOp test to reflect the made changes and combined the non canonical forOp tests into one file and added a test case for the edge case describe before. (Note: if I find the time I will try to run the SingleSource test suite with the throughMLIR lowering in the next week to get a better idea, where we are with this pipeline. In general I agree with everything discussed in issue #1219, but I think we probably can already add more support in regard to arrays (and maybe pointers) with the existing mlir core constructs)
1 parent fb381bb commit 2afbab5

File tree

10 files changed

+203
-98
lines changed

10 files changed

+203
-98
lines changed

clang/include/clang/CIR/CIRToCIRPasses.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ mlir::LogicalResult runCIRToCIRPasses(
3434
llvm::StringRef lifetimeOpts, bool enableIdiomRecognizer,
3535
llvm::StringRef idiomRecognizerOpts, bool enableLibOpt,
3636
llvm::StringRef libOptOpts, std::string &passOptParsingFailure,
37-
bool enableCIRSimplify, bool flattenCIR, bool emitMLIR,
37+
bool enableCIRSimplify, bool flattenCIR, bool throughMLIR,
3838
bool enableCallConvLowering, bool enableMem2reg);
3939

4040
} // namespace cir

clang/lib/CIR/CodeGen/CIRPasses.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ mlir::LogicalResult runCIRToCIRPasses(
2828
llvm::StringRef lifetimeOpts, bool enableIdiomRecognizer,
2929
llvm::StringRef idiomRecognizerOpts, bool enableLibOpt,
3030
llvm::StringRef libOptOpts, std::string &passOptParsingFailure,
31-
bool enableCIRSimplify, bool flattenCIR, bool emitCore,
31+
bool enableCIRSimplify, bool flattenCIR, bool throughMLIR,
3232
bool enableCallConvLowering, bool enableMem2Reg) {
3333

3434
llvm::TimeTraceScope scope("CIR To CIR Passes");
@@ -81,7 +81,7 @@ mlir::LogicalResult runCIRToCIRPasses(
8181
if (enableMem2Reg)
8282
pm.addPass(mlir::createMem2Reg());
8383

84-
if (emitCore)
84+
if (throughMLIR)
8585
pm.addPass(mlir::createSCFPreparePass());
8686

8787
// FIXME: once CIRCodenAction fixes emission other than CIR we

clang/lib/CIR/FrontendAction/CIRGenAction.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,18 +210,16 @@ class CIRGenConsumer : public clang::ASTConsumer {
210210
action == CIRGenAction::OutputType::EmitMLIR &&
211211
feOptions.MLIRTargetDialect == clang::frontend::MLIR_CIR_FLAT;
212212

213-
bool emitCore = action == CIRGenAction::OutputType::EmitMLIR &&
214-
feOptions.MLIRTargetDialect == clang::frontend::MLIR_CORE;
215-
216213
// Setup and run CIR pipeline.
217214
std::string passOptParsingFailure;
218215
if (runCIRToCIRPasses(
219216
mlirMod, mlirCtx.get(), C, !feOptions.ClangIRDisableCIRVerifier,
220217
feOptions.ClangIRLifetimeCheck, lifetimeOpts,
221218
feOptions.ClangIRIdiomRecognizer, idiomRecognizerOpts,
222219
feOptions.ClangIRLibOpt, libOptOpts, passOptParsingFailure,
223-
codeGenOptions.OptimizationLevel > 0, flattenCIR, emitCore,
224-
enableCCLowering, feOptions.ClangIREnableMem2Reg)
220+
codeGenOptions.OptimizationLevel > 0, flattenCIR,
221+
!feOptions.ClangIRDirectLowering, enableCCLowering,
222+
feOptions.ClangIREnableMem2Reg)
225223
.failed()) {
226224
if (!passOptParsingFailure.empty())
227225
diagnosticsEngine.Report(diag::err_drv_cir_pass_opt_parsing)

clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,18 @@
1414
#include "mlir/Dialect/MemRef/IR/MemRef.h"
1515
#include "mlir/Dialect/SCF/IR/SCF.h"
1616
#include "mlir/IR/Builders.h"
17+
#include "mlir/IR/BuiltinOps.h"
1718
#include "mlir/IR/Location.h"
1819
#include "mlir/IR/ValueRange.h"
1920
#include "mlir/Pass/PassManager.h"
21+
#include "mlir/Support/LLVM.h"
2022
#include "mlir/Support/LogicalResult.h"
2123
#include "mlir/Transforms/DialectConversion.h"
2224
#include "clang/CIR/Dialect/IR/CIRDialect.h"
2325
#include "clang/CIR/Dialect/IR/CIRTypes.h"
2426
#include "clang/CIR/LowerToMLIR.h"
2527
#include "llvm/ADT/TypeSwitch.h"
28+
#include "llvm/IR/Module.h"
2629

2730
using namespace cir;
2831
using namespace llvm;
@@ -252,6 +255,14 @@ void SCFLoop::analysis() {
252255
if (!canonical)
253256
return;
254257

258+
// If the IV is defined before the forOp (i.e. outside the surrounding
259+
// cir.scope) this is not a canonical loop as the IV would not have the
260+
// correct value after the forOp
261+
if (ivAddr.getDefiningOp()->getBlock() != forOp->getBlock()) {
262+
canonical = false;
263+
return;
264+
}
265+
255266
cmpOp = findCmpOp();
256267
if (!cmpOp) {
257268
canonical = false;
@@ -303,16 +314,24 @@ void SCFLoop::transferToSCFForOp() {
303314
"Not support lowering loop with break, continue or if yet");
304315
// Replace the IV usage to scf loop induction variable.
305316
if (isIVLoad(op, ivAddr)) {
306-
// Replace CIR IV load with arith.addi scf.IV, 0.
307-
// The replacement makes the SCF IV can be automatically propogated
308-
// by OpAdaptor for individual IV user lowering.
309-
// The redundant arith.addi can be removed by later MLIR passes.
310-
rewriter->setInsertionPoint(op);
311-
auto newIV = plusConstant(scfForOp.getInductionVar(), loc, 0);
312-
rewriter->replaceOp(op, newIV.getDefiningOp());
317+
// Replace CIR IV load with scf.IV
318+
// (i.e. remove the load op and replace the uses of the result of the CIR
319+
// IV load with the scf.IV)
320+
rewriter->replaceOp(op, scfForOp.getInductionVar());
313321
}
314322
return mlir::WalkResult::advance();
315323
});
324+
325+
// All uses have been replaced by the scf.IV and we can remove the alloca +
326+
// initial store operations
327+
328+
// The operations before the loop have been transferred to MLIR.
329+
// So we need to go through getRemappedValue to find the operations.
330+
auto remapAddr = rewriter->getRemappedValue(ivAddr);
331+
332+
// Since this is a canonical loop we can remove the alloca + initial store op
333+
rewriter->eraseOp(remapAddr.getDefiningOp());
334+
rewriter->eraseOp(*remapAddr.user_begin());
316335
}
317336

318337
void SCFLoop::transformToSCFWhileOp() {

clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "mlir/Dialect/SCF/IR/SCF.h"
2929
#include "mlir/Dialect/Vector/IR/VectorOps.h"
3030
#include "mlir/IR/BuiltinDialect.h"
31+
#include "mlir/IR/BuiltinOps.h"
3132
#include "mlir/IR/BuiltinTypes.h"
3233
#include "mlir/IR/Operation.h"
3334
#include "mlir/IR/Region.h"
@@ -36,6 +37,7 @@
3637
#include "mlir/IR/ValueRange.h"
3738
#include "mlir/Pass/Pass.h"
3839
#include "mlir/Pass/PassManager.h"
40+
#include "mlir/Support/LLVM.h"
3941
#include "mlir/Support/LogicalResult.h"
4042
#include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h"
4143
#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
@@ -51,6 +53,7 @@
5153
#include "llvm/ADT/STLExtras.h"
5254
#include "llvm/ADT/SmallVector.h"
5355
#include "llvm/ADT/TypeSwitch.h"
56+
#include "llvm/IR/Value.h"
5457
#include "llvm/Support/TimeProfiler.h"
5558

5659
using namespace cir;
@@ -204,18 +207,41 @@ static bool findBaseAndIndices(mlir::Value addr, mlir::Value &base,
204207
return true;
205208
}
206209

207-
// For memref.reinterpret_cast has multiple users, erasing the operation
208-
// after the last load or store been generated.
210+
// If the memref.reinterpret_cast has multiple users (i.e the original
211+
// cir.ptr_stride op has multiple users), only erase the operation after the
212+
// last load or store has been generated.
209213
static void eraseIfSafe(mlir::Value oldAddr, mlir::Value newAddr,
210214
SmallVector<mlir::Operation *> &eraseList,
211215
mlir::ConversionPatternRewriter &rewriter) {
216+
212217
unsigned oldUsedNum =
213218
std::distance(oldAddr.getUses().begin(), oldAddr.getUses().end());
214219
unsigned newUsedNum = 0;
220+
// Count the uses of the newAddr (the result of the original base alloca) in
221+
// load/store ops using an forwarded offset from the current
222+
// memref.reinterpret_cast op
215223
for (auto *user : newAddr.getUsers()) {
216-
if (isa<mlir::memref::LoadOp>(*user) || isa<mlir::memref::StoreOp>(*user))
217-
++newUsedNum;
224+
if (auto loadOpUser = mlir::dyn_cast_or_null<mlir::memref::LoadOp>(*user)) {
225+
if (!loadOpUser.getIndices().empty()) {
226+
auto strideVal = loadOpUser.getIndices()[0];
227+
if (strideVal ==
228+
mlir::dyn_cast<mlir::memref::ReinterpretCastOp>(eraseList.back())
229+
.getOffsets()[0])
230+
++newUsedNum;
231+
}
232+
} else if (auto storeOpUser =
233+
mlir::dyn_cast_or_null<mlir::memref::StoreOp>(*user)) {
234+
if (!storeOpUser.getIndices().empty()) {
235+
auto strideVal = storeOpUser.getIndices()[0];
236+
if (strideVal ==
237+
mlir::dyn_cast<mlir::memref::ReinterpretCastOp>(eraseList.back())
238+
.getOffsets()[0])
239+
++newUsedNum;
240+
}
241+
}
218242
}
243+
// If all load/store ops using forwarded offsets from the current
244+
// memref.reinterpret_cast ops erase the memref.reinterpret_cast ops
219245
if (oldUsedNum == newUsedNum) {
220246
for (auto op : eraseList)
221247
rewriter.eraseOp(op);
@@ -235,13 +261,13 @@ class CIRLoadOpLowering : public mlir::OpConversionPattern<cir::LoadOp> {
235261
mlir::memref::LoadOp newLoad;
236262
if (findBaseAndIndices(adaptor.getAddr(), base, indices, eraseList,
237263
rewriter)) {
238-
newLoad =
239-
rewriter.create<mlir::memref::LoadOp>(op.getLoc(), base, indices);
240-
// rewriter.replaceOpWithNewOp<mlir::memref::LoadOp>(op, base, indices);
264+
newLoad = rewriter.create<mlir::memref::LoadOp>(
265+
op.getLoc(), base, indices, op.getIsNontemporal());
241266
eraseIfSafe(op.getAddr(), base, eraseList, rewriter);
242267
} else
243-
newLoad =
244-
rewriter.create<mlir::memref::LoadOp>(op.getLoc(), adaptor.getAddr());
268+
newLoad = rewriter.create<mlir::memref::LoadOp>(
269+
op.getLoc(), adaptor.getAddr(), mlir::ValueRange{},
270+
op.getIsNontemporal());
245271

246272
// Convert adapted result to its original type if needed.
247273
mlir::Value result = emitFromMemory(rewriter, op, newLoad.getResult());
@@ -265,12 +291,13 @@ class CIRStoreOpLowering : public mlir::OpConversionPattern<cir::StoreOp> {
265291
mlir::Value value = emitToMemory(rewriter, op, adaptor.getValue());
266292
if (findBaseAndIndices(adaptor.getAddr(), base, indices, eraseList,
267293
rewriter)) {
268-
rewriter.replaceOpWithNewOp<mlir::memref::StoreOp>(op, value, base,
269-
indices);
294+
rewriter.replaceOpWithNewOp<mlir::memref::StoreOp>(
295+
op, value, base, indices, op.getIsNontemporal());
270296
eraseIfSafe(op.getAddr(), base, eraseList, rewriter);
271297
} else
272-
rewriter.replaceOpWithNewOp<mlir::memref::StoreOp>(op, value,
273-
adaptor.getAddr());
298+
rewriter.replaceOpWithNewOp<mlir::memref::StoreOp>(
299+
op, value, adaptor.getAddr(), mlir::ValueRange{},
300+
op.getIsNontemporal());
274301
return mlir::LogicalResult::success();
275302
}
276303
};
@@ -1451,7 +1478,6 @@ mlir::ModuleOp lowerFromCIRToMLIR(mlir::ModuleOp theModule,
14511478
if (!result)
14521479
report_fatal_error(
14531480
"The pass manager failed to lower CIR to MLIR standard dialects!");
1454-
14551481
// Now that we ran all the lowering passes, verify the final output.
14561482
if (theModule.verify().failed())
14571483
report_fatal_error(

clang/test/CIR/Lowering/ThroughMLIR/array.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,32 @@ int test_array2() {
2929
int a[3][4];
3030
return a[1][2];
3131
}
32+
33+
int test_array3() {
34+
// CIR-LABEL: cir.func {{.*}} @test_array3()
35+
// CIR: %[[ARRAY:.*]] = cir.alloca !cir.array<!s32i x 3>, !cir.ptr<!cir.array<!s32i x 3>>, ["a"] {alignment = 4 : i64}
36+
// CIR: %[[PTRDECAY1:.*]] = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr<!cir.array<!s32i x 3>>), !cir.ptr<!s32i>
37+
// CIR: %[[PTRSTRIDE1:.*]] = cir.ptr_stride(%[[PTRDECAY1]] : !cir.ptr<!s32i>, {{.*}} : !s32i), !cir.ptr<!s32i>
38+
// CIR: {{.*}} = cir.load align(4) %[[PTRSTRIDE1]] : !cir.ptr<!s32i>, !s32i
39+
// CIR: %[[PTRDECAY2:.*]] = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr<!cir.array<!s32i x 3>>), !cir.ptr<!s32i>
40+
// CIR: %[[PTRSTRIDE2:.*]] = cir.ptr_stride(%[[PTRDECAY2]] : !cir.ptr<!s32i>, {{.*}} : !s32i), !cir.ptr<!s32i>
41+
// CIR: %{{.*}} = cir.load align(4) %[[PTRSTRIDE2]] : !cir.ptr<!s32i>, !s32i
42+
// CIR: cir.store align(4) {{.*}}, %[[PTRSTRIDE2]] : !s32i, !cir.ptr<!s32i>
43+
// CIR: %[[PTRDECAY3:.*]] = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr<!cir.array<!s32i x 3>>), !cir.ptr<!s32i>
44+
// CIR: %[[PTRSTRIDE3:.*]] = cir.ptr_stride(%[[PTRDECAY3]] : !cir.ptr<!s32i>, {{.*}} : !s32i), !cir.ptr<!s32i>
45+
// CIR: %{{.*}} = cir.load align(4) %[[PTRSTRIDE3]] : !cir.ptr<!s32i>, !s32i
46+
47+
// MLIR-LABEL: func @test_array3
48+
// MLIR: %{{.*}} = memref.alloca() {alignment = 4 : i64} : memref<i32>
49+
// MLIR: %[[ARRAY:.*]] = memref.alloca() {alignment = 4 : i64} : memref<3xi32>
50+
// MLIR: %[[IDX1:.*]] = arith.index_cast %{{.*}} : i32 to index
51+
// MLIR: %{{.*}} = memref.load %[[ARRAY]][%[[IDX1]]] : memref<3xi32>
52+
// MLIR: %[[IDX2:.*]] = arith.index_cast %{{.*}} : i32 to index
53+
// MLIR: %{{.*}} = memref.load %[[ARRAY]][%[[IDX2]]] : memref<3xi32>
54+
// MLIR: memref.store %{{.*}}, %[[ARRAY]][%[[IDX2]]] : memref<3xi32>
55+
// MLIR: %[[IDX3:.*]] = arith.index_cast %{{.*}} : i32 to index
56+
// MLIR: %{{.*}} = memref.load %[[ARRAY]][%[[IDX3]]] : memref<3xi32>
57+
int a[3];
58+
a[0] += a[2];
59+
return a[1];
60+
}

clang/test/CIR/Lowering/ThroughMLIR/for-reject-1.cpp

Lines changed: 0 additions & 24 deletions
This file was deleted.

clang/test/CIR/Lowering/ThroughMLIR/for-reject-2.cpp

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-direct-lowering -emit-mlir=core %s -o %t.mlir
2+
// RUN: FileCheck --input-file=%t.mlir %s
3+
4+
void f() {}
5+
6+
void reject_test1() {
7+
for (int i = 0; i < 100; i++, f());
8+
// CHECK: %[[ALLOCA:.+]] = memref.alloca
9+
// CHECK: %[[ZERO:.+]] = arith.constant 0
10+
// CHECK: memref.store %[[ZERO]], %[[ALLOCA]]
11+
// CHECK: %[[HUNDRED:.+]] = arith.constant 100
12+
// CHECK: scf.while : () -> () {
13+
// CHECK: %[[TMP:.+]] = memref.load %[[ALLOCA]]
14+
// CHECK: %[[TMP1:.+]] = arith.cmpi slt, %0, %[[HUNDRED]]
15+
// CHECK: scf.condition(%[[TMP1]])
16+
// CHECK: } do {
17+
// CHECK: %[[TMP2:.+]] = memref.load %[[ALLOCA]]
18+
// CHECK: %[[ONE:.+]] = arith.constant 1
19+
// CHECK: %[[TMP3:.+]] = arith.addi %[[TMP2]], %[[ONE]]
20+
// CHECK: memref.store %[[TMP3]], %[[ALLOCA]]
21+
// CHECK: func.call @_Z1fv()
22+
// CHECK: scf.yield
23+
// CHECK: }
24+
}
25+
26+
void reject_test2() {
27+
for (int i = 0; i < 100; i++, i++);
28+
// CHECK: %[[ALLOCA:.+]] = memref.alloca
29+
// CHECK: %[[ZERO:.+]] = arith.constant 0
30+
// CHECK: memref.store %[[ZERO]], %[[ALLOCA]]
31+
// CHECK: %[[HUNDRED:.+]] = arith.constant 100
32+
// CHECK: scf.while : () -> () {
33+
// CHECK: %[[TMP:.+]] = memref.load %[[ALLOCA]]
34+
// CHECK: %[[TMP2:.+]] = arith.cmpi slt, %[[TMP]], %[[HUNDRED]]
35+
// CHECK: scf.condition(%[[TMP2]])
36+
// CHECK: } do {
37+
// CHECK: %[[TMP3:.+]] = memref.load %[[ALLOCA]]
38+
// CHECK: %[[ONE:.+]] = arith.constant 1
39+
// CHECK: %[[ADD:.+]] = arith.addi %[[TMP3]], %[[ONE]]
40+
// CHECK: memref.store %[[ADD]], %[[ALLOCA]]
41+
// CHECK: %[[LOAD:.+]] = memref.load %[[ALLOCA]]
42+
// CHECK: %[[ONE2:.+]] = arith.constant 1
43+
// CHECK: %[[ADD2:.+]] = arith.addi %[[LOAD]], %[[ONE2]]
44+
// CHECK: memref.store %[[ADD2]], %[[ALLOCA]]
45+
// CHECK: scf.yield
46+
// CHECK: }
47+
}
48+
49+
void reject_test3() {
50+
int i;
51+
for (i = 0; i < 100; i++);
52+
i += 10;
53+
// CHECK: %[[ALLOCA:.+]] = memref.alloca()
54+
// CHECK: memref.alloca_scope {
55+
// CHECK: %[[ZERO:.+]] = arith.constant 0
56+
// CHECK: memref.store %[[ZERO]], %[[ALLOCA]]
57+
// CHECK: %[[HUNDRED:.+]] = arith.constant 100
58+
// CHECK: scf.while : () -> () {
59+
// CHECK: %[[TMP:.+]] = memref.load %[[ALLOCA]]
60+
// CHECK: %[[TMP2:.+]] = arith.cmpi slt, %[[TMP]], %[[HUNDRED]]
61+
// CHECK: scf.condition(%[[TMP2]])
62+
// CHECK: } do {
63+
// CHECK: %[[TMP3:.+]] = memref.load %[[ALLOCA]]
64+
// CHECK: %[[ONE:.+]] = arith.constant 1
65+
// CHECK: %[[ADD:.+]] = arith.addi %[[TMP3]], %[[ONE]]
66+
// CHECK: memref.store %[[ADD]], %[[ALLOCA]]
67+
// CHECK: scf.yield
68+
// CHECK: }
69+
// CHECK: }
70+
// CHECK: %[[TEN:.+]] = arith.constant 10
71+
// CHECK: %[[TMP4:.+]] = memref.load %[[ALLOCA]]
72+
// CHECK: %[[TMP5:.+]] = arith.addi %[[TMP4]], %[[TEN]]
73+
// CHECK: memref.store %[[TMP5]], %[[ALLOCA]]
74+
}

0 commit comments

Comments
 (0)