| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
[mlir][bufferize] Make buffer-results-to-out-params support only functions that are neither public nor extern (#162441) The callers of public or extern functions are unknown, so their function signatures cannot be changed. | 9 个月前 | |
[mlir][bufferize] Add hoist-dynamic-allocs-option to buffer-results-to-out-params (#160985) Add hoist-dynamic-allocs-option to buffer-results-to-out-params. This PR supported that obtain the size of the dynamic shape memref through the caller-callee relationship. | 10 个月前 | |
[mlir][bufferize] Make buffer-results-to-out-params support only functions that are neither public nor extern (#162441) The callers of public or extern functions are unknown, so their function signatures cannot be changed. | 9 个月前 | |
[MLIR][BufferResultsToOutParamsPass] Add Option to Modify Public Function's Signature (#167248) Since https://github.com/llvm/llvm-project/pull/162441, buffer-results-to-out-params transforms private functions only. But, as mentioned in https://github.com/llvm/llvm-project/pull/162441#issuecomment-3404195242, this is a breaking change for pipelines handling C code. Our pipeline @EfficientComputer is also affected by this breaking change. Therefore, this PR adds an opt-in flag to allow public functions to be transformed by BufferResultsToOutParamsPass. | 8 个月前 | |
[mlir][bufferize] Make buffer-results-to-out-params support only functions that are neither public nor extern (#162441) The callers of public or extern functions are unknown, so their function signatures cannot be changed. | 9 个月前 | |
[mlir] Fix region simplification bug when later blocks use prior block argument values (#97960) This fixes #94520 by ensuring that any if any block arguments are being used outside of the original block that the block is not considered a candidate for merging. More details: the root cause of the issue described in #94520 was that ^bb2 and ^bb5 were being merged despite %4 (an argument to ^bb2) was being used later in ^bb7. When the block merge occurred, that unintentionally changed the value of %4 for all downstream code. This change prevents that from happening. | 1 年前 | |
[mlir] Fix block merging (#102038) With this PR I am trying to address: https://github.com/llvm/llvm-project/issues/63230. What changed: - While merging identical blocks, don't add a block argument if it is "identical" to another block argument. I.e., if the two block arguments refer to the same Value. The operations operands in the block will point to the argument we already inserted. This needs to happen to all the arguments we pass to the different successors of the parent block - After merged the blocks, get rid of "unnecessary" arguments. I.e., if all the predecessors pass the same block argument, there is no need to pass it as an argument. - This last simplification clashed with BufferDeallocationSimplification. The reason, I think, is that the two simplifications are clashing. I.e., BufferDeallocationSimplification contains an analysis based on the block structure. If we simplify the block structure (by merging and/or dropping block arguments) the analysis is invalid . The solution I found is to do a more prudent simplification when running that pass. **Note-1**: I ran all the integration tests (-DMLIR_INCLUDE_INTEGRATION_TESTS=ON) and they passed. **Note-2**: I fixed a bug found by @Dinistro in #97697 . The issue was that, when looking for redundant arguments, I was not considering that the block might have already some arguments. So the index (in the block args list) of the i-th newArgument is i+numOfOldArguments. | 1 年前 | |
Avoid unnecessary erasing of constant Locs (#151573) Do not erase location info when moving an op within the same block. Since #75415 , the FoldUtils.cpp erases the location information when moving an operation. This was being done even when an operation was moved to the front of a block it was already in. In TFLite, this location information is used to provide meaningful names for tensors, which aids in debugging and mapping compiled tensors back to their original layers. The aggressive erasure of location info caused many tensors in TFLite models to receive generic names (e.g., tfl.pseudo_qconst), making the models harder to inspect. This change modifies the logic to preserve the location of an operation when it is moved within the same block. The location is now only erased when the operation is moved from a different block entirely. This ensures that most tensor names are preserved, improving the debugging experience for TFLite models. | 1 年前 | |
[mlir][Pass] Include anchor op in -pass-pipeline In D134622 the printed form of a pass manager is changed to include the name of the op that the pass manager is anchored on. This updates the -pass-pipeline argument format to include the anchor op as well, so that the printed form of a pipeline can be directly passed to -pass-pipeline. In most cases this requires updating -pass-pipeline='pipeline' to -pass-pipeline='builtin.module(pipeline)'. This also fixes an outdated assert that prevented running a PassManager anchored on 'any'. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D134900 | 3 年前 | |
[mlir][memref] Verify out-of-bounds access for memref.subview (#133086) * Improve the verifier of memref.subview to detect out-of-bounds extractions. * Improve the documentation of memref.subview to make clear that out-of-bounds extractions are not allowed. Rewrite examples to use the new strided<> notation instead of affine_map layout maps. Also remove all unrelated operations (memref.alloc) from the examples. * Fix various test cases where memref.subview ops ran out-of-bounds. * Update canonicalizations patterns to ensure that they do not fold IR if it would generate IR that no longer verifies. Related discussion on Discourse: https://discourse.llvm.org/t/out-of-bounds-semantics-of-memref-subview/85293 This is a re-upload of #131876, which was reverted due to failing GPU tests. These tests were faulty and fixed in #133051. | 1 年前 | |
[mlir][memref] Support test-compose-subview dynamic size (#146881) Supports the case where the sizes of the subview op is dynamic.When there are more for loops in the tile algorithm, multiple subviews are performed and test-compose-subview does not work when the size operand of the subview ops is dynamic value. | 1 年前 | |
Pretty print on -dump-pass-pipeline (#143223) This PR makes dump-pass-pipeline pretty-print the dumped pipeline. For large pipelines the current behavior produces a wall of text that is hard to visually navigate. For the command bash mlir-opt --pass-pipeline="builtin.module(flatten-memref, expand-strided-metadata,func.func(arith-expand,func.func(affine-scalrep)))" --dump-pass-pipeline Before: bash Pass Manager with 3 passes: builtin.module(flatten-memref,expand-strided-metadata,func.func(arith-expand{include-bf16=false include-f8e8m0=false},func.func(affine-scalrep))) After: bash Pass Manager with 3 passes: builtin.module( flatten-memref, expand-strided-metadata, func.func( arith-expand{include-bf16=false include-f8e8m0=false}, func.func( affine-scalrep ) ) ) Another nice feature of this is that the pretty-printed string can still be copy/pasted into -pass-pipeline using a quote: bash $ bin/mlir-opt --dump-pass-pipeline test.mlir --pass-pipeline=' builtin.module( flatten-memref, expand-strided-metadata, func.func( arith-expand{include-bf16=false include-f8e8m0=false}, func.func( affine-scalrep ) ) )' --------- Co-authored-by: Jeremy Kun <j2kun@users.noreply.github.com> | 1 年前 | |
[mlir][vector] Support complete folding in single pass for vector.insert/vector.extract (#142124) ### Description This patch improves the folding efficiency of vector.insert and vector.extract operations by not returning early after successfully converting dynamic indices to static indices. This PR also renames the test pass TestConstantFold to TestSingleFold and adds comprehensive documentation explaining the single-pass folding behavior. ### Motivation Since the OpBuilder::createOrFold function only calls fold **once**, the current fold methods of vector.insert and vector.extract may leave the op in a state that can be folded further. For example, consider the following un-folded IR: %v1 = vector.insert %e1, %v0 [0] : f32 into vector<128xf32> %c0 = arith.constant 0 : index %e2 = vector.extract %v1[%c0] : f32 from vector<128xf32> If we use createOrFold to create the vector.extract op, then the result will be: %v1 = vector.insert %e1, %v0 [127] : f32 into vector<128xf32> %e2 = vector.extract %v1[0] : f32 from vector<128xf32> But this is not the optimal result. createOrFold should have returned %e1. The reason is that the execution of fold returns immediately after extractInsertFoldConstantOp, causing subsequent folding logics to be skipped. --------- Co-authored-by: Yang Bai <yangb@nvidia.com> | 1 年前 | |
[mlir][vector] Support complete folding in single pass for vector.insert/vector.extract (#142124) ### Description This patch improves the folding efficiency of vector.insert and vector.extract operations by not returning early after successfully converting dynamic indices to static indices. This PR also renames the test pass TestConstantFold to TestSingleFold and adds comprehensive documentation explaining the single-pass folding behavior. ### Motivation Since the OpBuilder::createOrFold function only calls fold **once**, the current fold methods of vector.insert and vector.extract may leave the op in a state that can be folded further. For example, consider the following un-folded IR: %v1 = vector.insert %e1, %v0 [0] : f32 into vector<128xf32> %c0 = arith.constant 0 : index %e2 = vector.extract %v1[%c0] : f32 from vector<128xf32> If we use createOrFold to create the vector.extract op, then the result will be: %v1 = vector.insert %e1, %v0 [127] : f32 into vector<128xf32> %e2 = vector.extract %v1[0] : f32 from vector<128xf32> But this is not the optimal result. createOrFold should have returned %e1. The reason is that the execution of fold returns immediately after extractInsertFoldConstantOp, causing subsequent folding logics to be skipped. --------- Co-authored-by: Yang Bai <yangb@nvidia.com> | 1 年前 | |
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
[mlir][Transforms][NFC] CSE: Split tests and fix typo (#115680) Add -split-input-file to CSE tests and fix a typo in Passes.h. (The typo is harmless as long as the pass has no options.) | 1 年前 | |
[mlir][Transforms] Delete 1:N dialect conversion driver (#121389) The 1:N dialect conversion driver has been deprecated. Use the regular dialect conversion driver instead. This commit deletes the 1:N dialect conversion driver. Note for LLVM integration: If you are already using the regular dialect conversion, but still have argument materializations in your code base, simply delete all addArgumentMaterialization calls. For details, see https://discourse.llvm.org/t/rfc-merging-1-1-and-1-n-dialect-conversions/82513. | 1 年前 | |
| 2 年前 | ||
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
Pretty print on -dump-pass-pipeline (#143223) This PR makes dump-pass-pipeline pretty-print the dumped pipeline. For large pipelines the current behavior produces a wall of text that is hard to visually navigate. For the command bash mlir-opt --pass-pipeline="builtin.module(flatten-memref, expand-strided-metadata,func.func(arith-expand,func.func(affine-scalrep)))" --dump-pass-pipeline Before: bash Pass Manager with 3 passes: builtin.module(flatten-memref,expand-strided-metadata,func.func(arith-expand{include-bf16=false include-f8e8m0=false},func.func(affine-scalrep))) After: bash Pass Manager with 3 passes: builtin.module( flatten-memref, expand-strided-metadata, func.func( arith-expand{include-bf16=false include-f8e8m0=false}, func.func( affine-scalrep ) ) ) Another nice feature of this is that the pretty-printed string can still be copy/pasted into -pass-pipeline using a quote: bash $ bin/mlir-opt --dump-pass-pipeline test.mlir --pass-pipeline=' builtin.module( flatten-memref, expand-strided-metadata, func.func( arith-expand{include-bf16=false include-f8e8m0=false}, func.func( affine-scalrep ) ) )' --------- Co-authored-by: Jeremy Kun <j2kun@users.noreply.github.com> | 1 年前 | |
| 1 年前 | ||
[test] Remove misleading '' | 1 年前 | |
| 1 年前 | ||
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
[mlir] Fix inlining-threshold.mlir test for NDEBUG builds. | 2 年前 | |
[mlir][builtin] Make unrealized_conversion_cast inlineable (#139722) Until now, builtin.unrealized_conversion_cast ops could not be inlined by the Inliner pass. | 11 个月前 | |
[mlir][transform] Guard parametric loop tiling pass from no option (#118254) test-extract-fixed-outer-loops pass always crash without any test-outer-loop-sizes option. We need to keep the pass from crash by checking the option existence. Fix https://github.com/llvm/llvm-project/issues/61716, https://github.com/llvm/llvm-project/issues/116360 --------- Co-authored-by: Mehdi Amini <joker.eph@gmail.com> | 1 年前 | |
[mlir][SCF] scf.parallel: Make reductions part of the terminator (#75314) This commit makes reductions part of the terminator. Instead of scf.yield, scf.reduce now terminates the body of scf.parallel ops. scf.reduce may contain an arbitrary number of reductions, with one region per reduction. Example: mlir %init = arith.constant 0.0 : f32 %r:2 = scf.parallel (%iv) = (%lb) to (%ub) step (%step) init (%init, %init) -> f32, f32 { %elem_to_reduce1 = load %buffer1[%iv] : memref<100xf32> %elem_to_reduce2 = load %buffer2[%iv] : memref<100xf32> scf.reduce(%elem_to_reduce1, %elem_to_reduce2 : f32, f32) { ^bb0(%lhs : f32, %rhs: f32): %res = arith.addf %lhs, %rhs : f32 scf.reduce.return %res : f32 }, { ^bb0(%lhs : f32, %rhs: f32): %res = arith.mulf %lhs, %rhs : f32 scf.reduce.return %res : f32 } } scf.reduce operations can no longer be interleaved with other ops in the body of scf.parallel. This simplifies the op and makes it possible to assign the RecursiveMemoryEffects trait to scf.reduce. (This was not possible before because the op was not a terminator, causing the op to be DCE'd.) | 2 年前 | |
[mlir][Transforms] Make LocationSnapshotPass respect OpPrintingFlags (#119373) The current implementation of LocationSnapshotPass takes an OpPrintingFlags argument and stores it as member, but does not use it for printing. Properly implement the printing flags, also supporting command line args. --------- Co-authored-by: Mehdi Amini <joker.eph@gmail.com> | 1 年前 | |
Fix side effects for LLVM integer operations (udiv, sdiv) incorrectly marked as Pure (#166648) This MR modifies side effect traits of some integer arithmetic operations in the LLVM dialect. Prior to this MR, the LLVM dialect sdiv and udiv operations were marked as Pure through tblgen inheritance of the LLVM_ArithmeticOpBase class. The Pure trait allowed incorrect hoisting of sdiv/udiv operations by the loop-independent-code-motion pass. This MR modifies the sdiv and udiv LLVM operations to have traits and code motion behavior identical to their counterparts in the arith dialect, which were established by the commit/review below. https://github.com/llvm/llvm-project/commit/ed39825be48805b174d3177f1d8d41ed84784d18 https://reviews.llvm.org/D137814 | 8 个月前 | |
| 1 年前 | ||
[mlir][affine] Fix min simplification in makeComposedAffineApply (#145376) This patch fixes a bug discovered in the affine::makeComposedFoldedAffineApply function when composeAffineMin == true. The bug happened because the simplification assumed the symbols appearing in the affine.apply op corresponded to symbols in the affine.min op, and that's not always the case. For example: mlir #map = affine_map<()[s0, s1] -> (s1)> #map1 = affine_map<()[s0, s1] -> (s0 ceildiv s1)> module { func.func @min_max_full_simplify() -> index { %0 = test.value_with_bounds {max = 64 : index, min = 32 : index} %1 = test.value_with_bounds {max = 64 : index, min = 32 : index} %2 = affine.min #map()[%0, %1] %3 = affine.apply #map1()[%2, %0] return %3 : index } } This patch also introduces the test make_composed_folded_affine_apply transform operation to test this simplification. It also adds tests ensuring we get correct behavior. --------- Co-authored-by: Nicolas Vasilache <nico.vasilache@amd.com> | 1 年前 | |
[mlir] Fix block merging (#102038) With this PR I am trying to address: https://github.com/llvm/llvm-project/issues/63230. What changed: - While merging identical blocks, don't add a block argument if it is "identical" to another block argument. I.e., if the two block arguments refer to the same Value. The operations operands in the block will point to the argument we already inserted. This needs to happen to all the arguments we pass to the different successors of the parent block - After merged the blocks, get rid of "unnecessary" arguments. I.e., if all the predecessors pass the same block argument, there is no need to pass it as an argument. - This last simplification clashed with BufferDeallocationSimplification. The reason, I think, is that the two simplifications are clashing. I.e., BufferDeallocationSimplification contains an analysis based on the block structure. If we simplify the block structure (by merging and/or dropping block arguments) the analysis is invalid . The solution I found is to do a more prudent simplification when running that pass. **Note-1**: I ran all the integration tests (-DMLIR_INCLUDE_INTEGRATION_TESTS=ON) and they passed. **Note-2**: I fixed a bug found by @Dinistro in #97697 . The issue was that, when looking for redundant arguments, I was not considering that the block might have already some arguments. So the index (in the block args list) of the i-th newArgument is i+numOfOldArguments. | 1 年前 | |
[llvm-project] Fix typos mutli and mutliple. NFC. (#122880) | 1 年前 | |
[MLIR] getBackwardSlice: don't bail on ops that are IsolatedFromAbove (#158135) Ops with the IsIsolatedFromAbove trait should be captured by the backward slice. --------- Signed-off-by: Ian Wood <ianwood@u.northwestern.edu> | 10 个月前 | |
[mlir][SCF] Use Affine ops for indexing math. (#108450) For index type of induction variable, the indexing math is better represented using affine ops such as affine.delinearize_index. This also further demonstrates that some of these affine ops might need to move to a different dialect. For one these ops only support IndexType when they should be able to work with any integer type. This change also includes some canonicalization patterns for affine.delinearize_index operation to 1) Drop unit basis values 2) Remove the delinearize_index op when the linear_index is a loop induction variable of a normalized loop and the basis is of size 1 and is also the upper bound of the normalized loop. --------- Signed-off-by: MaheshRavishankar <mahesh.ravishankar@gmail.com> | 1 年前 | |
[mlir][Pass] Include anchor op in -pass-pipeline In D134622 the printed form of a pass manager is changed to include the name of the op that the pass manager is anchored on. This updates the -pass-pipeline argument format to include the anchor op as well, so that the printed form of a pipeline can be directly passed to -pass-pipeline. In most cases this requires updating -pass-pipeline='pipeline' to -pass-pipeline='builtin.module(pipeline)'. This also fixes an outdated assert that prevented running a PassManager anchored on 'any'. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D134900 | 3 年前 | |
[mlir] Use arith max or min ops instead of cmp + select (#82178) I believe the semantics should be the same, but this saves 1 op and simplifies the code. For example, the following two instructions: %2 = cmp sgt %0, %1 %3 = select %2, %0, %1 Are equivalent to: %2 = maxsi %0 %1 | 2 年前 | |
[ViewOpGraph] Improve GraphViz output (#125509) This patch improves the GraphViz output of ViewOpGraph (--view-op-graph). - Switch to rectangular record-based nodes, inspired by a similar visualization in [Glow](https://github.com/pytorch/glow). Rectangles make more efficient use of space when printing text. - Add input and output ports for each operand and result, and remove edge labels. - Switch to a muted color palette to reduce eye strain. | 1 年前 | |
[ViewOpGraph] Improve GraphViz output (#125509) This patch improves the GraphViz output of ViewOpGraph (--view-op-graph). - Switch to rectangular record-based nodes, inspired by a similar visualization in [Glow](https://github.com/pytorch/glow). Rectangles make more efficient use of space when printing text. - Add input and output ports for each operand and result, and remove edge labels. - Switch to a muted color palette to reduce eye strain. | 1 年前 | |
[ViewOpGraph] Improve GraphViz output (#125509) This patch improves the GraphViz output of ViewOpGraph (--view-op-graph). - Switch to rectangular record-based nodes, inspired by a similar visualization in [Glow](https://github.com/pytorch/glow). Rectangles make more efficient use of space when printing text. - Add input and output ports for each operand and result, and remove edge labels. - Switch to a muted color palette to reduce eye strain. | 1 年前 | |
[mlir] PromoteBuffersToStackPass - Copy attributes of original AllocOp Reviewed By: nicolasvasilache Differential Revision: https://reviews.llvm.org/D143185 | 3 年前 | |
Allowing RDV to call getArgOperandsMutable() (#160415) ## Problem RemoveDeadValues can legally drop dead function arguments on private func.func callees. But call-sites to such functions aren't fixed if the call operation keeps its call arguments in a **segmented operand group** (i.ie, uses AttrSizedOperandSegments), unless the call op implements getArgOperandsMutable and the RDV pass actually uses it. ## Fix When RDV decides to drop callee function args, it should, for each call-site that implements CallOpInterface, **shrink the call's argument segment** via getArgOperandsMutable() using the same dead-arg indices. This keeps both the flat operand list and the operand_segment_sizes attribute in sync (that's what MutableOperandRange does when bound to the segment). ## Note This change is a no-op for: * call ops without segment operands (they still get their flat operands erased via the generic path) * call ops whose calle args weren't dropped (public, external, non-func-func, unresolved symbol, etc) * llvm.call/llvm.invoke (RDV doesn't drop llvm.func args --------- Co-authored-by: Mehdi Amini <joker.eph@gmail.com> | 10 个月前 | |
[mlir] Make remove-dead-values remove block and successorOperands before delete ops (#166766) Reland https://github.com/llvm/llvm-project/pull/165725, fix the Failed test by removing successor operands before delete operations. Following the deletion of cond.branch, its successor operands will subsequently be removed. | 8 个月前 | |
[mlir][Pass] Include anchor op in -pass-pipeline In D134622 the printed form of a pass manager is changed to include the name of the op that the pass manager is anchored on. This updates the -pass-pipeline argument format to include the anchor op as well, so that the printed form of a pipeline can be directly passed to -pass-pipeline. In most cases this requires updating -pass-pipeline='pipeline' to -pass-pipeline='builtin.module(pipeline)'. This also fixes an outdated assert that prevented running a PassManager anchored on 'any'. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D134900 | 3 年前 | |
[mlir][Pass] Include anchor op in -pass-pipeline In D134622 the printed form of a pass manager is changed to include the name of the op that the pass manager is anchored on. This updates the -pass-pipeline argument format to include the anchor op as well, so that the printed form of a pipeline can be directly passed to -pass-pipeline. In most cases this requires updating -pass-pipeline='pipeline' to -pass-pipeline='builtin.module(pipeline)'. This also fixes an outdated assert that prevented running a PassManager anchored on 'any'. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D134900 | 3 年前 | |
[mlir] Guard sccp pass from crashing with different source type (#120656) Vector::BroadCastOp expects the identical element type in folding. It causes the crash if the different source type is given to the SCCP pass. We need to guard the pass from crashing if the nonidentical element type is given, but still compatible. (e.g. index vs integer type) https://github.com/llvm/llvm-project/issues/120193 | 1 年前 | |
[mlir] fix crash when scf utils work on llvm.func (#120688) fixed https://github.com/llvm/llvm-project/issues/119378 | 1 年前 | |
[mlir] Delete unroll-full option for Affine/SCF unroll pass (#164658) Make the unroll-factor take -1 as "full" and avoid potential conflict when passing both an explicit factor and unroll-full=true. | 9 个月前 | |
[mlir][Interfaces] LoopLikeOpInterface: Add replaceWithAdditionalYields (#67121) affine::replaceForOpWithNewYields and replaceLoopWithNewYields (for "scf.for") are now interface methods and additional loop-carried variables can now be added to "scf.for"/"affine.for" uniformly. (No more TypeSwitch needed.) Note: scf.while and other loops with loop-carried variables can implement replaceWithAdditionalYields, but to keep this commit small, that is not done in this commit. | 2 年前 | |
[mlir][SCF] Use Affine ops for indexing math. (#108450) For index type of induction variable, the indexing math is better represented using affine ops such as affine.delinearize_index. This also further demonstrates that some of these affine ops might need to move to a different dialect. For one these ops only support IndexType when they should be able to work with any integer type. This change also includes some canonicalization patterns for affine.delinearize_index operation to 1) Drop unit basis values 2) Remove the delinearize_index op when the linear_index is a loop induction variable of a normalized loop and the basis is of size 1 and is also the upper bound of the normalized loop. --------- Signed-off-by: MaheshRavishankar <mahesh.ravishankar@gmail.com> | 1 年前 | |
[llvm-project] Fix typos mutli and mutliple. NFC. (#122880) | 1 年前 | |
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
[mlir][Transforms] Dialect conversion: Fix missing source materialization (#97903) This commit fixes a bug in the dialect conversion. During a 1:N signature conversion, the dialect conversion did not insert a cast back to the original block argument type, producing invalid IR. See test-block-legalization.mlir: Without this commit, the operand type of the op changes because an unrealized_conversion_cast is missing: "test.consumer_of_complex"(%v) : (!llvm.struct<(f64, f64)>) -> () To implement this fix, it was necessary to change the meaning of argument materializations. An argument materialization now maps from the new block argument types to the original block argument type. (It now behaves almost like a source materialization.) This also addresses a FIXME in the code base: // FIXME: The current argument materialization hook expects the original // output type, even though it doesn't use that as the actual output type // of the generated IR. The output type is just used as an indicator of // the type of materialization to do. This behavior is really awkward in // that it diverges from the behavior of the other hooks, and can be // easily misunderstood. We should clean up the argument hooks to better // represent the desired invariants we actually care about. It is no longer necessary to distinguish between the "output type" and the "original output type". Most type converter are already written according to the new API. (Most implementations use the same conversion functions as for source materializations.) One exception is the MemRef-to-LLVM type converter, which materialized an !llvm.struct based on the elements of a memref descriptor. It still does that, but casts the !llvm.struct back to the original memref type. The dialect conversion inserts a target materialization (to !llvm.struct) which cancels out with the other cast. This commit also fixes a bug in computeNecessaryMaterializations. The implementation did not account for the possibility that a value was replaced multiple times. E.g., replace a by b, then b by c. This commit also adds a transform dialect op to populate SCF-to-CF patterns. This transform op was needed to write a test case. The bug described here appears only during a complex interplay of 1:N signature conversions and op replacements. (I was not able to trigger it with ops and patterns from the test dialect without duplicating the scf.if pattern.) Note for LLVM integration: Make sure that all addArgument/Source/TargetMaterialization functions produce an SSA of the specified type. Depends on #98743. | 2 年前 | |
[mlir] Implement a memory-space cast bubbling-down transform (#159454) This commit adds functionality to bubble down memory-space casts operations, allowing consumer operations to use the original memory-space rather than first casting to a different memory space. Changes: - Introduce MemorySpaceCastOpInterface to handle memory-space cast operations - Create a MemorySpaceCastConsumerOpInterface pass that identifies and bubbles down eligible casts - Add implementation for memref and vector operations to handle memory-space cast propagation - Add bubbleDownCasts method to relevant operations to support the fusion In particular, in the current implementation only memory-space casts into the default memory-space can be bubbled-down. Example: mlir func.func @op_with_cast_sequence(%arg0: memref<4x4xf32, 1>, %arg1: index, %arg2: f32) -> memref<16xf32> { %memspacecast = memref.memory_space_cast %arg0 : memref<4x4xf32, 1> to memref<4x4xf32> %c0 = arith.constant 0 : index %c4 = arith.constant 4 : index %expanded = memref.expand_shape %memspacecast [[0], [1, 2]] output_shape [4, 2, 2] : memref<4x4xf32> into memref<4x2x2xf32> %collapsed = memref.collapse_shape %expanded [[0, 1, 2]] : memref<4x2x2xf32> into memref<16xf32> %loaded = memref.load %collapsed[%c0] : memref<16xf32> %added = arith.addf %loaded, %arg2 : f32 memref.store %added, %collapsed[%c0] : memref<16xf32> %atomic_result = memref.atomic_rmw addf %arg2, %collapsed[%c4] : (f32, memref<16xf32>) -> f32 return %collapsed : memref<16xf32> } // mlir-opt --bubble-down-memory-space-casts func.func @op_with_cast_sequence(%arg0: memref<4x4xf32, 1>, %arg1: index, %arg2: f32) -> memref<16xf32> { %c4 = arith.constant 4 : index %c0 = arith.constant 0 : index %expand_shape = memref.expand_shape %arg0 [[0], [1, 2]] output_shape [4, 2, 2] : memref<4x4xf32, 1> into memref<4x2x2xf32, 1> %collapse_shape = memref.collapse_shape %expand_shape [[0, 1, 2]] : memref<4x2x2xf32, 1> into memref<16xf32, 1> %memspacecast = memref.memory_space_cast %collapse_shape : memref<16xf32, 1> to memref<16xf32> %0 = memref.load %collapse_shape[%c0] : memref<16xf32, 1> %1 = arith.addf %0, %arg2 : f32 memref.store %1, %collapse_shape[%c0] : memref<16xf32, 1> %2 = memref.atomic_rmw addf %arg2, %collapse_shape[%c4] : (f32, memref<16xf32, 1>) -> f32 return %memspacecast : memref<16xf32> } --------- Signed-off-by: Fabian Mora <fabian.mora-cordero@amd.com> Co-authored-by: Mehdi Amini <joker.eph@gmail.com> | 10 个月前 | |
[mlir][Pass] Include anchor op in -pass-pipeline In D134622 the printed form of a pass manager is changed to include the name of the op that the pass manager is anchored on. This updates the -pass-pipeline argument format to include the anchor op as well, so that the printed form of a pipeline can be directly passed to -pass-pipeline. In most cases this requires updating -pass-pipeline='pipeline' to -pass-pipeline='builtin.module(pipeline)'. This also fixes an outdated assert that prevented running a PassManager anchored on 'any'. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D134900 | 3 年前 | |
[mlir] Fix block merging (#102038) With this PR I am trying to address: https://github.com/llvm/llvm-project/issues/63230. What changed: - While merging identical blocks, don't add a block argument if it is "identical" to another block argument. I.e., if the two block arguments refer to the same Value. The operations operands in the block will point to the argument we already inserted. This needs to happen to all the arguments we pass to the different successors of the parent block - After merged the blocks, get rid of "unnecessary" arguments. I.e., if all the predecessors pass the same block argument, there is no need to pass it as an argument. - This last simplification clashed with BufferDeallocationSimplification. The reason, I think, is that the two simplifications are clashing. I.e., BufferDeallocationSimplification contains an analysis based on the block structure. If we simplify the block structure (by merging and/or dropping block arguments) the analysis is invalid . The solution I found is to do a more prudent simplification when running that pass. **Note-1**: I ran all the integration tests (-DMLIR_INCLUDE_INTEGRATION_TESTS=ON) and they passed. **Note-2**: I fixed a bug found by @Dinistro in #97697 . The issue was that, when looking for redundant arguments, I was not considering that the block might have already some arguments. So the index (in the block args list) of the i-th newArgument is i+numOfOldArguments. | 1 年前 | |
[MLIR] Erase unreachable blocks before applying patterns in the greedy rewriter (#153957) Operations like: %add = arith.addi %add, %add : i64 are legal in unreachable code. Unfortunately many patterns would be unsafe to apply on such IR and can lead to crashes or infinite loops. To avoid this we can remove unreachable blocks before attempting to apply patterns. We may have to do this also whenever the CFG is changed by a pattern, it is left up for future work right now. Fixes #153732 | 11 个月前 | |
[MLIR] Add a utility to sort the operands of commutative ops Added a commutativity utility pattern and a function to populate it. The pattern sorts the operands of an op in ascending order of the "key" associated with each operand iff the op is commutative. This sorting is stable. The function is intended to be used inside passes to simplify the matching of commutative operations. After the application of the above-mentioned pattern, since the commutative operands now have a deterministic order in which they occur in an op, the matching of large DAGs becomes much simpler, i.e., requires much less number of checks to be written by a user in her/his pattern matching function. The "key" associated with an operand is the list of the "AncestorKeys" associated with the ancestors of this operand, in a breadth-first order. The operand of any op is produced by a set of ops and block arguments. Each of these ops and block arguments is called an "ancestor" of this operand. Now, the "AncestorKey" associated with: 1. A block argument is {type: BLOCK_ARGUMENT, opName: ""}. 2. A non-constant-like op, for example, arith.addi, is {type: NON_CONSTANT_OP, opName: "arith.addi"}. 3. A constant-like op, for example, arith.constant, is {type: CONSTANT_OP, opName: "arith.constant"}. So, if an operand, say A, was produced as follows: `` <block argument> <block argument> \ / \ / arith.subi arith.constant \ / arith.addi | returns A ` Then, the block arguments and operations present in the backward slice of A, in the breadth-first order are: arith.addi, arith.subi, arith.constant, <block argument>, and <block argument>. Thus, the "key" associated with operand A is: { {type: NON_CONSTANT_OP, opName: "arith.addi"}, {type: NON_CONSTANT_OP, opName: "arith.subi"}, {type: CONSTANT_OP, opName: "arith.constant"}, {type: BLOCK_ARGUMENT, opName: ""}, {type: BLOCK_ARGUMENT, opName: ""} } Now, if "keyA" is the key associated with operand A and "keyB" is the key associated with operand B, then: "keyA" < "keyB" iff: 1. In the first unequal pair of corresponding AncestorKeys, the AncestorKey in operand A is smaller, or, 2. Both the AncestorKeys in every pair are the same and the size of operand A's "key" is smaller. AncestorKeys of type BLOCK_ARGUMENT are considered the smallest, those of type CONSTANT_OP, the largest, and NON_CONSTANT_OP types come in between. Within the types NON_CONSTANT_OP and CONSTANT_OP, the smaller ones are the ones with smaller op names (lexicographically). --- Some examples of such a sorting: Assume that the sorting is being applied to foo.commutative, which is a commutative op. Example 1: > %1 = foo.const 0 > %2 = foo.mul <block argument>, <block argument> > %3 = foo.commutative %1, %2 Here, 1. The key associated with %1 is: { {CONSTANT_OP, "foo.const"} } 2. The key associated with %2 is: { {NON_CONSTANT_OP, "foo.mul"}, {BLOCK_ARGUMENT, ""}, {BLOCK_ARGUMENT, ""} } The key of %2 < the key of %1 Thus, the sorted foo.commutative is: > %3 = foo.commutative %2, %1 Example 2: > %1 = foo.const 0 > %2 = foo.mul <block argument>, <block argument> > %3 = foo.mul %2, %1 > %4 = foo.add %2, %1 > %5 = foo.commutative %1, %2, %3, %4 Here, 1. The key associated with %1 is: { {CONSTANT_OP, "foo.const"} } 2. The key associated with %2 is: { {NON_CONSTANT_OP, "foo.mul"}, {BLOCK_ARGUMENT, ""} } 3. The key associated with %3 is: { {NON_CONSTANT_OP, "foo.mul"}, {NON_CONSTANT_OP, "foo.mul"}, {CONSTANT_OP, "foo.const"}, {BLOCK_ARGUMENT, ""}, {BLOCK_ARGUMENT, ""} } 4. The key associated with %4 is: { {NON_CONSTANT_OP, "foo.add"}, {NON_CONSTANT_OP, "foo.mul"}, {CONSTANT_OP, "foo.const"}, {BLOCK_ARGUMENT, ""}, {BLOCK_ARGUMENT, ""} } Thus, the sorted foo.commutative` is: > %5 = foo.commutative %4, %3, %2, %1 Signed-off-by: Srishti Srivastava <srishti.srivastava@polymagelabs.com> Reviewed By: Mogball Differential Revision: https://reviews.llvm.org/D124750 | 3 年前 | |
[mlir][Transforms] Dialect conversion: Context-aware type conversions (#140434) This commit adds support for context-aware type conversions: type conversion rules that can return different types depending on the IR. There is no change for existing (context-unaware) type conversion rules: c++ // Example: Conversion any integer type to f32. converter.addConversion([](IntegerType t) { return Float32Type::get(t.getContext()); } There is now an additional overload to register context-aware type conversion rules: ``c++ // Example: Type conversion rule for integers, depending on the context: // Get the defining op of v, read its "increment" attribute and return an // integer with a bitwidth that is increased by "increment". converter.addConversion([](Value v) -> std::optional<Type> { auto intType = dyn_cast<IntegerType>(v.getType()); if (!intType) return std::nullopt; Operation *op = v.getDefiningOp(); if (!op) return std::nullopt; auto incrementAttr = op->getAttrOfType<IntegerAttr>("increment"); if (!incrementAttr) return std::nullopt; return IntegerType::get(v.getContext(), intType.getWidth() + incrementAttr.getInt()); }); ` For performance reasons, the type converter caches the result of type conversions. This is no longer possible when there context-aware type conversions because each conversion could compute a different type depending on the context. There is no performance degradation when there are only context-unaware type conversions. Note: This commit just adds context-aware type conversions to the dialect conversion framework. There are many existing patterns that still call converter.convertType(someValue.getType()). These should be gradually updated in subsequent commits to call converter.convertType(someValue)`. Co-authored-by: Markus Böck <markus.boeck02@gmail.com> | 11 个月前 | |
[MLIR][FuncToLLVM] Remove typed pointers from call conversion test pass (#71107) This commit removes typed pointers from the Func to LLVM test pass. Typed pointers have been deprecated for a while now and it's planned to soon remove them from the LLVM dialect. Related PSA: https://discourse.llvm.org/t/psa-removal-of-typed-pointers-from-the-llvm-dialect/74502 | 2 年前 | |
[mlir][LLVM] Improve lowering of llvm.byval function arguments (#100028) When a function argument is annotated with the llvm.byval attribute, [LLVM expects](https://llvm.org/docs/LangRef.html#parameter-attributes) the function argument type to be an llvm.ptr. For example: func.func (%args0 : llvm.ptr {llvm.byval = !llvm.struct<(i32)>} { ... } Unfortunately, this makes the type conversion context-dependent, which is something that the type conversion infrastructure (i.e., LLVMTypeConverter in this particular case) doesn't support. For example, we may want to convert MyType to llvm.struct<(i32)> in general, but to an llvm.ptr type only when it's a function argument passed by value. To fix this problem, this PR changes the FuncToLLVM conversion logic to generate an llvm.ptr when the function argument has a llvm.byval attribute. An llvm.load is inserted into the function to retrieve the value expected by the argument users. | 1 年前 | |
[mlir:PDL] Add support for DialectConversion with pattern configurations Up until now PDL(L) has not supported dialect conversion because we had no way of remapping values or integrating with type conversions. This commit rectifies that by adding a new "pattern configuration" concept to PDL. This essentially allows for attaching external configurations to patterns, which can hook into pattern events (for now just the scope of a rewrite, but we could also pass configs to native rewrites as well). This allows for injecting the type converter into the conversion pattern rewriter. Differential Revision: https://reviews.llvm.org/D133142 | 3 年前 | |
[mlir][inliner] Add doClone and canHandleMultipleBlocks callbacks to Inliner Config (#131226) Current inliner disables inlining when the caller is in a region with single block trait, while the callee function contains multiple blocks. the SingleBlock trait is used in operations such as do/while loop, for example fir.do_loop, fir.iterate_while and fir.if. Typically, calls within loops are good candidates for inlining. However, functions with multiple blocks are also common. for example, any function with "if () then return" will result in multiple blocks in MLIR. This change gives the flexibility of a customized inliner to handle such cases. doClone: clones instructions and other information from the callee function into the caller function. . canHandleMultipleBlocks: checks if functions with multiple blocks can be inlined into a region with the SingleBlock trait. The default behavior of the inliner remains unchanged. --------- Co-authored-by: jeanPerier <jean.perier.polytechnique@gmail.com> Co-authored-by: Mehdi Amini <joker.eph@gmail.com> | 1 年前 | |
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
[mlir][Transforms][NFC] Dialect conversion: Reformat materialization error message (#114176) This commit changes the format of the materialization error message. Previously: failed to legalize unresolved materialization from ('f64') to 'f32' that remained live after conversion Now: failed to legalize unresolved materialization from ('f64') to ('f32') that remained live after conversion This commit is in preparation of merging the 1:1 and 1:N dialect conversions. At that point, target materializations may create more than one SSA value. I am sending this change as a separate PR to keep the main PR smaller. | 1 年前 | |
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
[MLIR][Transforms] Fix dialect conversion inverse mapping (#104648) Inverse mapping needs to be updated for the result that was remapped (it was previously only updated halfway). | 1 年前 | |
[mlir][CF] Add structural type conversion patterns (#165629) Add structural type conversion patterns for CF dialect ops. These patterns are similar to the SCF structural type conversion patterns. This commit adds missing functionality and is in preparation of #165180, which changes the way blocks are converted. (Only entry blocks are converted.) | 9 个月前 | |
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
[mlir][test] Turn test-legalize-mode into a pass option (#150767) The test-legalize-mode option is used only by the test-legalize-patterns pass. | 1 年前 | |
[mlir] Enable disabling folding in dialect conversion (#152890) Previously this only happened post checking if the op is legal, but was done unconditionally post (and before other legalization patterns). Add option to not attempt folding and one to do so as last resort. Did consider but did not add a always attempt to fold option (which would have folded whether or not legal), but removed TODO about it. | 11 个月前 | |
[mlir] Enable disabling folding in dialect conversion (#152890) Previously this only happened post checking if the op is legal, but was done unconditionally post (and before other legalization patterns). Add option to not attempt folding and one to do so as last resort. Did consider but did not add a always attempt to fold option (which would have folded whether or not legal), but removed TODO about it. | 11 个月前 | |
| 1 年前 | ||
[mlir] Dialect Conversion: Add support for post-order legalization order (#166292) By default, the dialect conversion driver processes operations in pre-order: the initial worklist is populated pre-order. (New/modified operations are immediately legalized recursively.) This commit adds a new API for selective post-order legalization. Patterns can request an operation / region legalization via ConversionPatternRewriter::legalize. They can call these helper functions on nested regions before rewriting the operation itself. Note: In rollback mode, a failed recursive legalization typically leads to a conversion failure. Since recursive legalization is performed by separate pattern applications, there is no way for the original pattern to recover from such a failure. | 9 个月前 | |
[mlir] Enable disabling folding in dialect conversion (#152890) Previously this only happened post checking if the op is legal, but was done unconditionally post (and before other legalization patterns). Add option to not attempt folding and one to do so as last resort. Did consider but did not add a always attempt to fold option (which would have folded whether or not legal), but removed TODO about it. | 11 个月前 | |
[mlir][Transforms] Dialect Conversion: Convert entry block only (#165180) When converting a function, convert only the entry block signature. The remaining block signatures should be converted by the respective branching ops. The FuncToLLVM / ControlFlowToLLVM patterns already use that design. c++ struct BranchOpLowering : public ConvertOpToLLVMPattern<cf::BranchOp> { LogicalResult matchAndRewrite(cf::BranchOp op, OneToNOpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { // Convert successor block. SmallVector<Value> flattenedAdaptor = flattenValues(adaptor.getOperands()); FailureOr<Block *> convertedBlock = getConvertedBlock(rewriter, getTypeConverter(), op, op.getSuccessor(), TypeRange(ValueRange(flattenedAdaptor))); // ... } }; This is consistent with the fact that operations from unreachable blocks are not put on the initial worklist. With this change, parent ops are no longer recursively legalized when inserting a block, simplifying the conversion driver a bit. Note for LLVM integration: If you are seeing failures, make sure to: - Drop converter.isLegal(&op.getBody()) when checking the legality of a function op. Only the entry block signature / function type should be taken into account. - If you need to convert all reachable blocks and are using cf branching ops, add populateCFStructuralTypeConversionsAndLegality. - If you need to convert all reachable blocks and are using custom branching ops, implement and populate custom structural type conversion patterns, similar to populateCFStructuralTypeConversionsAndLegality. | 9 个月前 | |
[mlir] Dialect Conversion: Add support for post-order legalization order (#166292) By default, the dialect conversion driver processes operations in pre-order: the initial worklist is populated pre-order. (New/modified operations are immediately legalized recursively.) This commit adds a new API for selective post-order legalization. Patterns can request an operation / region legalization via ConversionPatternRewriter::legalize. They can call these helper functions on nested regions before rewriting the operation itself. Note: In rollback mode, a failed recursive legalization typically leads to a conversion failure. Since recursive legalization is performed by separate pattern applications, there is no way for the original pattern to recover from such a failure. | 9 个月前 | |
[mlir] Dialect Conversion: Add support for post-order legalization order (#166292) By default, the dialect conversion driver processes operations in pre-order: the initial worklist is populated pre-order. (New/modified operations are immediately legalized recursively.) This commit adds a new API for selective post-order legalization. Patterns can request an operation / region legalization via ConversionPatternRewriter::legalize. They can call these helper functions on nested regions before rewriting the operation itself. Note: In rollback mode, a failed recursive legalization typically leads to a conversion failure. Since recursive legalization is performed by separate pattern applications, there is no way for the original pattern to recover from such a failure. | 9 个月前 | |
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
[mlir] Add fast walk-based pattern rewrite driver (#113825) This is intended as a fast pattern rewrite driver for the cases when a simple walk gets the job done but we would still want to implement it in terms of rewrite patterns (that can be used with the greedy pattern rewrite driver downstream). The new driver is inspired by the discussion in https://github.com/llvm/llvm-project/pull/112454 and the LLVM Dev presentation from @matthias-springer earlier this week. This limitation comes with some limitations: * It does not repeat until a fixpoint or revisit ops modified in place or newly created ops. In general, it only walks forward (in the post-order). * matchAndRewrite can only erase the matched op or its descendants. This is verified under expensive checks. * It does not perform folding / DCE. We could probably relax some of these in the future without sacrificing too much performance. | 1 年前 | |
[mlir] Enable decoupling two kinds of greedy behavior. (#104649) The greedy rewriter is used in many different flows and it has a lot of convenience (work list management, debugging actions, tracing, etc). But it combines two kinds of greedy behavior 1) how ops are matched, 2) folding wherever it can. These are independent forms of greedy and leads to inefficiency. E.g., cases where one need to create different phases in lowering and is required to applying patterns in specific order split across different passes. Using the driver one ends up needlessly retrying folding/having multiple rounds of folding attempts, where one final run would have sufficed. Of course folks can locally avoid this behavior by just building their own, but this is also a common requested feature that folks keep on working around locally in suboptimal ways. For downstream users, there should be no behavioral change. Updating from the deprecated should just be a find and replace (e.g., find ./ -type f -exec sed -i 's|applyPatternsAndFoldGreedily|applyPatternsGreedily|g' {} \; variety) as the API arguments hasn't changed between the two. | 1 年前 | |
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 | |
[mlir] Remove special case parsing/printing of func operations This was leftover from when the standard dialect was destroyed, and when FuncOp moved to the func dialect. Now that these transitions have settled a bit we can drop these. Most updates were handled using a simple regex: replace ^( *)func with $1func.func Differential Revision: https://reviews.llvm.org/D124146 | 4 年前 | |
[mlir][IR][NFC] Rename notify*Removed to notify*Erased (#82253) Rename listener callback names: * notifyOperationRemoved -> notifyOperationErased * notifyBlockRemoved -> notifyBlockErased The current callback names are misnomers. The callbacks are triggered when an operation/block is erased, not when it is removed (unlinked). E.g.: c++ /// Notify the listener that the specified operation is about to be erased. /// At this point, the operation has zero uses. /// /// Note: This notification is not triggered when unlinking an operation. virtual void notifyOperationErased(Operation *op) {} This change is in preparation of adding listener support to the dialect conversion. The dialect conversion internally unlinks IR before erasing it at a later point of time. There is an important difference between "remove" and "erase". Lister callback names should be accurate to avoid confusion. | 2 年前 | |
[mlir] Walk nested non-symbol table ops in symbol dce (#143353) The previous code was effectively that a symbol is dead if was not nested in sequence of SymbolTables. But one can have operations that one cannot delete/DCE that refers to symbols which one could delete which resulted in symbol-dce deleting symbols that are still referenced and the resulting IR being invalid. This changes it so that all operations inside non SymbolTable op are considered to find nested SymbolTable ops. --------- Co-authored-by: Mehdi Amini <joker.eph@gmail.com> | 1 年前 | |
[mlir][NFC] Update textual references of func to func.func in Transform tests The special case parsing of func operations is being removed. | 4 年前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 9 个月前 | ||
| 10 个月前 | ||
| 9 个月前 | ||
| 8 个月前 | ||
| 9 个月前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 3 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 4 年前 | ||
| 4 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 2 年前 | ||
| 4 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 4 年前 | ||
| 2 年前 | ||
| 11 个月前 | ||
| 1 年前 | ||
| 2 年前 | ||
| 1 年前 | ||
| 8 个月前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 10 个月前 | ||
| 1 年前 | ||
| 3 年前 | ||
| 2 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 3 年前 | ||
| 10 个月前 | ||
| 8 个月前 | ||
| 3 年前 | ||
| 3 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 9 个月前 | ||
| 2 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 4 年前 | ||
| 2 年前 | ||
| 10 个月前 | ||
| 3 年前 | ||
| 1 年前 | ||
| 11 个月前 | ||
| 3 年前 | ||
| 11 个月前 | ||
| 2 年前 | ||
| 1 年前 | ||
| 3 年前 | ||
| 1 年前 | ||
| 4 年前 | ||
| 1 年前 | ||
| 4 年前 | ||
| 1 年前 | ||
| 9 个月前 | ||
| 4 年前 | ||
| 1 年前 | ||
| 11 个月前 | ||
| 11 个月前 | ||
| 1 年前 | ||
| 9 个月前 | ||
| 11 个月前 | ||
| 9 个月前 | ||
| 9 个月前 | ||
| 9 个月前 | ||
| 4 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 4 年前 | ||
| 4 年前 | ||
| 2 年前 | ||
| 1 年前 | ||
| 4 年前 |