llvm / clangir

A new (MLIR based) high-level IR for clang.
https://clangir.org
Other
351 stars 95 forks source link

Through MLIR lowering (not LLVM): Missing CIR operations #561

Open gxsoar opened 5 months ago

gxsoar commented 5 months ago

There are two lowering paths from CIR:

  1. CIR to LLVM IR dialect
  2. CIR to MLIR in-tree dialects

Most effort has been into (1), which the list below doesn't really apply. Here's a the list of missing features in (2):

bcardosolopes commented 5 months ago

Btw, thanks for trying to categorize, this is going to be very useful for distributing work into multiple issues.

gxsoar commented 5 months ago

Hello, in the clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp :

void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns,
                                         mlir::TypeConverter &converter) {
  patterns.add<CIRReturnLowering, CIRBrOpLowering>(patterns.getContext());

  patterns.add<CIRCmpOpLowering, CIRCallOpLowering, CIRUnaryOpLowering,
               CIRBinOpLowering, CIRLoadOpLowering, CIRConstantOpLowering,
               CIRStoreOpLowering, CIRAllocaOpLowering, CIRFuncOpLowering,
               CIRScopeOpLowering, CIRBrCondOpLowering, CIRTernaryOpLowering,
               CIRYieldOpLowering>(converter, patterns.getContext());
}

I find these operations can be lowered to MLIR, cir.if and cir.global donot have releating passes, which can lower cir.if , cir.global to MLIR, why not lower cir.if to scf.if ? .But clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp , these passes can lower cir operations to llvm ir.

bcardosolopes commented 5 months ago

Oh, my apologies, this is talking about "Through MLIR" path, not our direct lowering, let me re-open! Sorry for the confusion

bcardosolopes commented 5 months ago

I just updated the issue description! Thanks for pushing this

Lancern commented 5 months ago

@bcardosolopes Currently the lowering prepare pass runs only on the LLVMIR lowering path. Should we introduce a similar pass for the MLIR lowering path? Some of the operations listed here can be transformed or canonicalized before lowering.

GaoXiangYa commented 5 months ago
Operation Category Difficulty Progress
cir.cos Math Easy  Done
cir.ceil Math Easy  Done
cir.exp2 Math Easy  Done
cir.exp Math Easy  Done
cir.fabs Math Easy  Done
cir.floor Math Easy  Done
cir.log10 Math Easy  Done
cir.rint Math Easy  
cir.round Math Easy  Done
cir.sin Math Easy  Done
cir.sqrt Math Easy  Done
cir.shift Math Easy  Done
cir.libc.memchr lib call Easy  
cir.libc.memcpy lib call Easy  
cir.nearbyint Lib Call Easy  
cir.get_bitfield Address Easy  
cir.get_global Address Easy  Done
cir.global Address Easy  Done
cir.set_bitfield Address Easy  
cir.std.find Lib Call Easy  
cir.break Control Flow Mid  
cir.asm Control Flow Mid  
cir.condition Control Flow Mid  Done
cir.continue Control Flow Mid  
cir.for Control Flow Mid  Done
cir.do Control Flow Mid  
cir.if Control Flow Mid  Done
cir.while Control Flow Mid  Done
cir.llvmir.zeroinit LLVM Mid  
cir.alloc_exception Exception Hard  
cir.catch Exception Hard  
cir.catch_param Exception Hard  
cir.throw Exception Hard  
cir.trunc Exception Hard  
cir.try_call Exception Hard  
cir.resume Exception Hard  
cir.try Exception Hard  
cir.va.arg Paramenter List Hard  
cir.va.copy Paramenter List Hard  
cir.va.end Paramenter List Hard  
cir.vec.cmp SIMD vector Hard  
cir.vec.create SIMD vector Hard  
cir.vec.extract SIMD vector Hard  
cir.vec.insert SIMD vector Hard  
cir.iterator_begin Iterator Hard  
cir.iterator_end Iterator Hard  
cir.ptr_diff Pointer Hard  
cir.ptr_stride Pointer Hard  Done
cir.stack_restore Stack Operation Hard  
cir.stack_save Stack Operation Hard  
cir.base_class_addr Class Hard  
cir.objsize Normal Hard  
cir.get_member Class Hard  
cir.vtable.address_point Vtable Hard  
cir.await Asynchronous programming Hard  

Hello, I have conducted research on these operations, classified them, and made a simple assessment of the difficulty of implementing these operations. I want to solve this issue. The current idea is to solve it one by one from easy to difficult, starting with math-related operations.

bcardosolopes commented 5 months ago

Sounds good

bcardosolopes commented 5 months ago

@bcardosolopes Currently the lowering prepare pass runs only on the LLVMIR lowering path. Should we introduce a similar pass for the MLIR lowering path? Some of the operations listed here can be transformed or canonicalized before lowering.

Sure, we should just add LoweringPrepare for that pipeline. There shouldn't be anything LLVM specific there, though somethings naturally go that direction (e.g. lowering globals). If we find that we need to different decisions, we can think about how to refactor that once we get into those.

bcardosolopes commented 5 months ago

@orbiri this table could be interesting for you too!

Lancern commented 5 months ago

Sure, we should just add LoweringPrepare for that pipeline. There shouldn't be anything LLVM specific there, though somethings naturally go that direction (e.g. lowering globals). If we find that we need to different decisions, we can think about how to refactor that once we get into those.

I checked this again. The current LoweringPrepare pass is included in the C++-to-MLIR pipeline (i.e. the pipeline built by clang frontend). But it is not included in the pipelines built by cir-opt or cir-translate. Is it intentional? Should we add the pass in those pipelines?

bcardosolopes commented 5 months ago

But it is not included in the pipelines built by cir-opt or cir-translate. Is it intentional?

LoweringPrepare needs the AST, and we don't have that (yet) by standalone invocations of cir-opt or cir-translate on top of CIR files. :(

Should we add the pass in those pipelines?

We should probably add it to clang driven "through MLIR" codegen, yes.

GaoXiangYa commented 4 months ago

Hello , I find that some libc functions lowering to mlir can use func.call methods, however, I think it is not necessary to do this. And like some vtable operations, it is difficult to lowering them to mlir. @bcardosolopes

bcardosolopes commented 4 months ago

Hello , I find that some libc functions lowering to mlir can use func.call methods, however, I think it is not necessary to do this. And like some vtable operations, it is difficult to lowering them to mlir.

Sorry, I'm not sure I understand the concern, can you elaborate?

GaoXiangYa commented 4 months ago

What I mean is how to translate libc function calls into MLIR , and whether operations related to some vtable can be translated into MLIR? @bcardosolopes

bcardosolopes commented 4 months ago

I understand your question, but I don't understand the specifics:

I find that some libc functions lowering to mlir can use func.call methods, however, I think it is not necessary to do this

If you don't want to use func.call methods, what do you want to use instead?

some vtable operations, it is difficult to lowering them to mlir

Why? What did you tried that didn't work?

Also, on a tangent, what is it your goal on working on MLIR support? Are you just trying to cover all CIR lowering possible for MLIR?

GaoXiangYa commented 4 months ago

We are currently attempting to lower C code to CIR and then further to MLIR for performance analysis. However, for library function calls like libc, we haven't found a good solution to lower them to MLIR yet, and MLIR currently does not support C struct type. @bcardosolopes

bcardosolopes commented 4 months ago

for library function calls like libc, we haven't found a good solution to lower them to MLIR yet

Can you elaborate on why func.call isn't good enough? Are you looking into more higher level representations for libc functions in MLIR? I'm not aware of any, indeed. Btw, I'm asking more questions case I'm curious to understand :)

We started mapping some libc functions in CIR, see memchr for instance, but approaches like that would only be useful if you were doing your perf analysis on top of CIR, not MLIR dialects.