Slide 1

Slide 1 text

John Lin 2024/08/03 Coscup 2024 ༻ MLIR መ࡞ Ұݸ Ruby IR (intermediate representation) Implement a Ruby IR with MLIR

Slide 2

Slide 2 text

COSCUP 2024 • Twitter: @johnlinvc • website: https://johnlin.vc • SRE @ West Pharmaceutical services
 ੢ࣜဌऱ • Do Ruby as a hobby.
 ڵझ࢖વత Rubyistɻ John Lin

Slide 3

Slide 3 text

COSCUP 2024 coscup = 40 + 2 What if ? ೗Ռʁ

Slide 4

Slide 4 text

COSCUP 2024 coscup = 40 + 2 Automatically optimized into ࣗಈ࠷ՂԽ੒ coscup = 42 What if ? ೗Ռʁ

Slide 5

Slide 5 text

COSCUP 2024 $ cat << EOF > coscup.rb coscup = 40 + 2 EOF $ bundle exec mlir_rb_optimizer coscup.rb coscup = 42 ՄҎʂ We can!

Slide 6

Slide 6 text

COSCUP 2024 • Optimizer parse the Ruby code, emit the IR(intermediate representation), optimize the IR, translate the IR back to Ruby Code.
 Optimizer parse Ruby ఔࣜᛰɼ༌ग़ IR (தհᛰʣɼ࠷ՂԽ IRɼ೺ IR ຋ᩄճ Ruby ఔࣜ ᛰɻ • Use a Ruby IR based on MLIR. 
 ࢖༻جԙ MLIR త Ruby IR ɻ • https://github.com/johnlinvc/mlir-dialect-ruby ዎኄ၏౸తʁ How ?

Slide 7

Slide 7 text

COSCUP 2024 • What is IR?
 ॄኄੋ IR ? • What is MLIR?
 ॄኄੋ MLIR ? • Intro to MLIR Ruby dialect
 հ঺ MLIR Ruby ํݴ • Future plan & Q&A
 ະိܭᙘᢛ Q&A େߝ Agenda

Slide 8

Slide 8 text

COSCUP 2024 • IR stands for intermediate representation.
 IR ੋ தհᛰతॖሜɻ • IR is the a program representation between AST(abstract syntax tree) and Machine Code.
 IR ੋհԙ AST(ޠ๏थʣ࿨ػցᛰ ೭ؒతҰछఔࣜදࣔ๏ɻ ॄኄੋ IR ? What is IR?

Slide 9

Slide 9 text

COSCUP 2024 define i32 @add(i32 %a) #0 { %1 = alloca i32, align 4 store i32 %a, i32* %1, align 4 %2 = load i32, i32* @globvar, align 4 %3 = load i32, i32* %1, align 4 %4 = add nsw i32 %2, %3 ret i32 %4 } Clang (LLVM IR) C/C++ LLVM IR Machine

Slide 10

Slide 10 text

COSCUP 2024 sil @_T5norms11taxicabNormfT1aV5norms5Point_Sd : $(Point) -> Double { bb0(%0 : $Point): // func Swift.+(Double, Double) -> Double %1 = function_ref @_Tsoi1pfTSdSd_Sd %2 = struct_extract %0 : $Point, #Point.x %3 = struct_extract %0 : $Point, #Point.y %4 = apply %1(%2, %3) : $(Double, Double) -> Double return %4 : Double } Swift IR (SIL) Swift SIL LLVM IR Machine

Slide 11

Slide 11 text

COSCUP 2024 HIR: Tree based थ㐫 THIR: HIR with inferred Type ༗ਪᏗܕผత HIR MIR: SSA Form IR ᄸҰොᆴ IR Rust IR (HIR,THIR,MIR) Rust HIR THIR Machine LLVM IR LIR

Slide 12

Slide 12 text

COSCUP 2024 • Makes Optimizing & Type Checking easier
 ߋ༰қ࠷ՂԽ࿨ܕผᒾҰ • As an abstraction layer between the Programming Language and It's running environment.
 ࡞ҝఔࣜޠݴ࿨ࣥߦ؀ڥؒతந৅૚
 IR త༻్ The Purpose of IR

Slide 13

Slide 13 text

COSCUP 2024 • The CRuby virtual machine(YARV, Yet another Ruby VM) 
 has a instruction set (ISeq).
 CRuby 㐘ٖػ YARV ༗ఆٛҰݸࢦྩू ISEQɻ • YARV is a stack machine.
 YARV ࢖༻ Stack ိ၏ܭࢉɻ • Dynamic typed, with some optimization like tagged pointer. 
 ಈଶܕผɼෆա༗Ұࠣ࠷ՂԽ૾ੋ tagged pointerɻ Ruby ݱࡏత IR Ruby's current IR Ruby ISEQ YARV VM

Slide 14

Slide 14 text

COSCUP 2024 3.3.0 :008 > puts RubyVM::InstructionSequence.compile('coscup = 40 + 2').disasm ... 0000 putobject 40 ( 1)[Li] 0002 putobject 2 0004 opt_plus [CcCr] 0006 dup 0007 setlocal_WC_0 coscup@0 0009 leave Ruby ݱࡏత IR Ruby's current IR

Slide 15

Slide 15 text

COSCUP 2024 • YARV is stack machine. Which is easier to implement and port across di ff erent CPU Arch. But harder to optimize and runs slower. [1]
 YARV ੋ stack machineɻ༰қመ࡞࿨Ҡ২ɼୠੋൺֱຫ࿨ֱ೉࠷ՂԽɻ • YARV is dynamic typed, making Monomorphization harder.
 ಈଶܕผൺֱ೉ Monomorphization • YARV is made for CPU, we don't want to miss the AI train on GPU.
 YARV ੋҝ CPU ઃܭతɼᔒ㭎๏䋯ࡏ GPU ্ɻ Why do we need a new IR for Ruby?

Slide 16

Slide 16 text

COSCUP 2024 Stack machine 40 2

Slide 17

Slide 17 text

COSCUP 2024 Stack machine 40 2 40 2 opt_plus

Slide 18

Slide 18 text

COSCUP 2024 Stack machine 40 2 40 2 opt_plus 42

Slide 19

Slide 19 text

COSCUP 2024 • A optimization on generating specialized code for a speci fi c type.
 ҝಛఆܕผ㗞ੜಛผతػցᛰత࠷ՂԽɻ • e.g. 40+2 can be compiled into a single ADD instruction.
 40 + 2 ՄҎඃฤᩄ੒ᄸҰ ADD ࢦྩɻ Monomorphization

Slide 20

Slide 20 text

COSCUP 2024 • Ability to run the same program on CPU, GPU, FPGA etc.
 ՄҎࡏ CPU/GPU/FPGA ࣥߦಉҰࢧఔࣜɻ • Very useful for AI/ML workload
 ሣ AI/ML ိ㘸኷ॏཁ • YARV only support CPUɻ
 YARV ୞ࢧԉ CPUɻ • ҟߏܭࢉ Heterogeneous computing

Slide 21

Slide 21 text

COSCUP 2024 • Register machine for better performance & easier to optimize
 ࢖༻࢑ଘثိᩋᏈೳߋ޷ɼߋ༰қ࠷ՂԽ • Static typed to have Monomorphization optimization
 ᯩଶܕผɼߋ༰қ၏Monomorphization • Support Heterogeneous computing
 ࢧԉҟߏܭࢉ զ၇ՄҎ༗Ұݸߋ޷త Ruby IR 䆩ʁ Can we have a better IR for Ruby?

Slide 22

Slide 22 text

COSCUP 2024 • Multi-Level Intermediate Representation 
 ଟ૚࣍தհᛰ • Part of LLVM project.
 LLVM తҰ෦෼ • A extensible common IR syntax for di ff erent compiler backend & frontend.
 ՄᎷॆత௨༻ IR ޠ๏ɼՄ༻ԙଟछฤᩄثલޙ୺ɻ • Provide tool & framework for developing your own IR.
 ఏڙ޻۩࿨ᐽՍိᩋ㟬։ᚙࣗݾత IR MLIR

Slide 23

Slide 23 text

COSCUP 2024 • Enable compilers to have more language speci fi c IR for optimization & diagnostic
 ᩋฤᩄثՄҎೳⴺ༗ߋషۙޠݴత IR ိ၏࠷ՂԽ࿨෼ੳɻ • Support compile to non-CPU based targets like GPU, FPGA.
 ՄҎฤᩄ౸ CPU Ҏ֎తฏ୆૾ੋ GPU, FPGAɻ • Act as a cross language compatibility platform.
 ၏ҝލޠݴత૬༰ੑฏ୆ɻ MLIR త໨ඪ Goals of MLIR

Slide 24

Slide 24 text

COSCUP 2024 • Compilers: • Clang (ClangIR) • Mojo, a super set of Python. • Nx, an Elixir ML tool. • Onnx, an ML tool. MLIR ࢖༻ऀ User of MLIR

Slide 25

Slide 25 text

COSCUP 2024 • Extensible IR syntax ՄᎷॆత IR ޠ๏ • Parser for custom IR ٬੍ IR త Parser • Framework to translate between source language & MLIR
 ࡏိݯޠݴ࿨ MLIR ೭ؒ຋ᩄతᐽՍɻ • Framework to optimize IR ࠷ՂԽ IR తᐽՍɻ • Framework to convert between IRs. ࡏ IR ؒ᫚׵తᐽՍɻ MLIR ޭೳ MLIR features

Slide 26

Slide 26 text

COSCUP 2024 • Instructions are called Operations, user can de fi ne their own operations.
 ࢦྩڣ၏ Operationɼ࢖༻ऀՄҎఆٛࣗݾత Operation • Static single assignment form(SSA) , make optimization easier.
 ᄸҰොᆴɼߋ༰қ࠷ՂԽɻ • Strong static typed. ᯩଶڧܕผ • Block based syntax instead of Φ(PHI) node. 
 ࢖༻ block ိऔ୅ Φ(PHI) nodeɻ MLIR IR ޠ๏ಛ৭ MLIR IR syntax features

Slide 27

Slide 27 text

COSCUP 2024 module { %0 = ruby.constant_int "40" : !ruby.int %1 = ruby.constant_int "2" : !ruby.int %2 = ruby.call %0 : !ruby.int -> "+"(%1) : (!ruby.int) -> ! ruby.opaque_object %3 = ruby.local_variable_write "coscup" = %2 {rb_stmt = true} : ! ruby.opaque_object } foo=40+2 MLIR IR

Slide 28

Slide 28 text

COSCUP 2024 module { %0 = ruby.def "hello" (required_args : ["name"]) : (required_args : [! ruby.opaque_object]) -> !ruby.opaque_object { %1 = ruby.local_variable_read "name" : !ruby.opaque_object ruby.return %1 : !ruby.opaque_object } : !ruby.sym } MLIR block

Slide 29

Slide 29 text

COSCUP 2024 • A set of IR de fi nition with it's own tools is called a dialect in MLIR.
 Ұ૊ IR ఆٛɼ౥഑ଞࣗݾత޻۩बڣ၏Ұݸ MLIR ํݴɻ • Operation(IR) de fi nitions. Operation ఆٛ • A translator that convert to/from MLIR to target language.
 ࡏ໨ඪޠݴ࿨ MLIR ೭ؒ᫚׵త຋ᩄ޻۩ɻ • Optimization passes to optimize the IR. IR త࠷ՂԽྲྀఔɻ • Converter to convert from/to other MLIR dialects. 
 ࡏ MLIR ํݴؒ᫚׵త᫚׵޻۩ɻ ॄኄੋ MLIR ํݴ? What is a MLIR dialect?

Slide 30

Slide 30 text

COSCUP 2024 • https://github.com/johnlinvc/mlir-dialect-ruby • Current Features: • Ruby Operations de fi nition in MLIR
 MLIR Ruby Operation ఆٛ • Ruby Optimization Passes.
 Ruby ࠷ՂԽྲྀఔ • Translate from Ruby code to IR. ኺ Ruby ຋ᩄ੒ IRɻ • Translate from IR back to Ruby code. ኺ IR ຋ᩄճ Ruby MLIR Ruby dialect

Slide 31

Slide 31 text

COSCUP 2024 MLIR Ruby dialect Ruby MLIR Ruby Optimization passes Ruby MLIR Ruby ISEQ YARV MLIR LLVM IR Machine Code

Slide 32

Slide 32 text

COSCUP 2024 MLIR Ruby dialect Ruby MLIR Ruby Optimization passes Ruby MLIR Ruby ISEQ YARV MLIR LLVM IR Machine Code

Slide 33

Slide 33 text

COSCUP 2024 • Use tablegen, a tool from LLVM ༻ MLIR ఆٛ Ruby IR Define a Ruby IR with MLIR def Ruby_LocalVariableWriteOp : Ruby_Op<"local_variable_write", [SameOperandsAndResultType]> { let arguments = (ins StrAttr:$var_name, Ruby_AnyType: $input); let results = (outs Ruby_AnyType:$res); let assemblyFormat = [{ $var_name `=` $input attr-dict `:` type($res) }]; }

Slide 34

Slide 34 text

COSCUP 2024 MLIR Ruby dialect Ruby MLIR Ruby Optimization passes Ruby MLIR Ruby ISEQ YARV MLIR LLVM IR Machine Code

Slide 35

Slide 35 text

COSCUP 2024 • Prism is the new cross implementation parser for Ruby.
 Prism ੋ৽తލመ࡞ Ruby Parserɻ • Has richer info than the 'Parser' gem.
 ൺى 'Parser' gem ༗ߋଟతࢿ㘤ɻ • Provides Ruby,C & JS API.
 ఏڙ Ruby, C & JS API ༻ Prism ိ Parse Ruby Parse Ruby with Prism

Slide 36

Slide 36 text

COSCUP 2024 class PrismLoader def initialize(program) @prog = program @ast = Prism.parse(@prog) @visitor = PrismVisitor.new @module = nil end end ༻ Prism ိ Parse Ruby Parse Ruby with Prism

Slide 37

Slide 37 text

COSCUP 2024 ༻ Prism ိ Parse Ruby Parse Ruby with Prism @ ProgramNode (location: (1,0)-(1,11)) ├── locals: [:coscup] └── statements: @ StatementsNode (location: (1,0)-(1,11)) └── body: (length: 1) └── @ LocalVariableWriteNode (location: (1,0)-(1,11)) ├── name: :coscup ├── depth: 0 ├── name_loc: (1,0)-(1,6) = "coscup" ├── value: │ @ CallNode (location: (1,7)-(1,11)) │ ├── flags: ∅ │ ├── receiver: │ │ @ IntegerNode (location: (1,7)-(1,9)) │ │ └── flags: decimal │ ├── call_operator_loc: ∅ │ ├── name: :+ │ ├── message_loc: (1,9)-(1,10) = "+" │ ├── opening_loc: ∅ │ ├── arguments: │ │ @ ArgumentsNode (location: (1,10)-(1,11)) │ │ ├── flags: ∅ │ │ └── arguments: (length: 1) │ │ └── @ IntegerNode (location: (1,10)-(1,11)) │ │ └── flags: decimal coscup = 40 + 2

Slide 38

Slide 38 text

COSCUP 2024 ༻ Prism ိ Parse Ruby Parse Ruby with Prism └── @ LocalVariableWriteNode (location: (1,0)-(1,11)) ├── name: :coscup ├── value: │ @ CallNode (location: (1,7)-(1,11)) │ ├── receiver: │ │ @ IntegerNode (location: (1,7)-(1,9)) │ │ └── flags: decimal │ ├── name: :+ │ ├── arguments: │ │ @ ArgumentsNode (location: (1,10)-(1,11)) │ │ └── arguments: (length: 1) │ │ └── @ IntegerNode (location: (1,10)-(1,11)) │ │ └── flags: decimal coscup = 40 + 2

Slide 39

Slide 39 text

COSCUP 2024 • Use the Prism Visitor to Emit IR.
 ࢖༻ Prism Visitor ိ༌ग़ IR • Create SSA vars on the fl y.
 ಈଶ㗞ੜ SSA ᏓᏐ໊ ኺ AST ༌ग़ IR Emit IR from AST

Slide 40

Slide 40 text

COSCUP 2024 class PrismVisitor def visit(node) type = node.type.to_s method_name = "visit_#{type.split("_")[..-2].join("_")}" raise "not implemented: #{method_name}" unless respond_to? (method_name) send(method_name, node) end end ኺ AST ༌ग़ IR Emit IR from AST

Slide 41

Slide 41 text

COSCUP 2024 class PrismVisitor def visit_integer(node) build_int_stmt(node.value) end def build_int_stmt(value) with_new_ssa_var do |ssa_var, attr_dict| ret_type = "!ruby.int" @stmts << " #{ssa_var} = ruby.constant_int \"#{value}\" #{attr_dict} : #{ret_type}" ret_type end end end ኺ AST ༌ग़ IR Emit IR from AST

Slide 42

Slide 42 text

COSCUP 2024 %0 = ruby.constant_int "40" : !ruby.int %1 = ruby.constant_int "2" : !ruby.int %2 = ruby.call %0 : !ruby.int -> "+"(%1) : (!ruby.int) -> ! ruby.opaque_object %3 = ruby.local_variable_write "coscup" = %2 {rb_stmt = true} : ! ruby.opaque_object Emit IR from AST ኺ AST ༌ग़ IR coscup = 40 + 2

Slide 43

Slide 43 text

COSCUP 2024 MLIR Ruby dialect Ruby MLIR Ruby Optimization passes Ruby MLIR Ruby ISEQ YARV MLIR LLVM IR Machine Code

Slide 44

Slide 44 text

COSCUP 2024 • Use the MLIR Pass infrastructure to optimize the IR.
 ࢖༻ MLIR Pass Սߏိ࠷ՂԽ IR • Rewrite Patterns: Pattern match an Operation DAG, then perform edit/replace/delete on the DAG.
 ሣ Operation DAG ࡞ pattern matchɼ࠶ሣDAG ၏मվ/औ୅/႟আ • Fold: Replace an Operation with another Operation or a Value.
 औ୅ಛఆత Operation ҃ੋ᫚׵੒ Valueɻ ࠷ՂԽԋࢉ๏ Optimization passes

Slide 45

Slide 45 text

COSCUP 2024 • Use the Pattern Rewrite
 ࢖༻ Pattern Rewrite • Convert the `call` op with an `add` op when method name is "+". and has 2 arguments.
 ೗Ռ `call` op త method ੋ "+" ࣕ׌༗ၷݸჩᏐత࿩ɼ᫚׵੒ `add` opɻ Specialization pass

Slide 46

Slide 46 text

COSCUP 2024 %0 = ruby.constant_int "40" : !ruby.int %1 = ruby.constant_int "2" : !ruby.int %2 = ruby.call %0 : !ruby.int -> "+"(%1) : (!ruby.int) -> ! ruby.opaque_object %3 = ruby.local_variable_write "coscup" = %2 {rb_stmt = true} : ! ruby.opaque_object Specialization pass coscup = 40 + 2

Slide 47

Slide 47 text

COSCUP 2024 LogicalResult matchAndRewrite(CallOp op, PatternRewriter &rewriter) const final { if (op.getMethodName() != "+") { return failure(); } if (op.getArgs().size() != 1) { return failure(); } auto lhs = op.getCallee(); if (lhs == ::mlir::Value()) { return failure(); } auto rhs = op.getArgs()[0]; auto resultType = lhs.getType(); rewriter.replaceOpWithNewOp(op, resultType, lhs, rhs); return success(); } Specialization pass

Slide 48

Slide 48 text

COSCUP 2024 %0 = ruby.constant_int "40" {} : !ruby.int %1 = ruby.constant_int "2" {} : !ruby.int %2 = ruby.add %0, %1 : (!ruby.int, !ruby.int) -> !ruby.int %3 = ruby.local_variable_write "coscup"= %2 {rb_stmt = true} : ! ruby.opaque_object Specialization pass coscup = 40 + 2

Slide 49

Slide 49 text

COSCUP 2024 • Rewrite does not edit the subsequent calls, so the return type must keep the same. ܕผࡨޡ Type error after specialization %0 = ruby.constant_int "40" {} : !ruby.int %1 = ruby.constant_int "2" {} : !ruby.int %2 = ruby.add %0, %1 : (!ruby.int, !ruby.int) -> !ruby.int %3 = ruby.local_variable_write "coscup"= %2 {rb_stmt = true} : !ruby.opaque_object error: use of value '%2' expects different type than prior uses: '!ruby.opaque_object' vs '!ruby.int' coscup = 40 + 2

Slide 50

Slide 50 text

COSCUP 2024 • Use the Pattern Rewrite • Convert the `call` op with an `add` op when method name is "+". and has 2 arguments. • Add a `cast` op at the end to maintain the result type. Specialization pass

Slide 51

Slide 51 text

COSCUP 2024 LogicalResult matchAndRewrite(CallOp op, PatternRewriter &rewriter) const final { ... auto newAdd = rewriter.create(op.getLoc(), resultType, lhs, rhs); rewriter.replaceOpWithNewOp(op, op.getRes().getType(), newAdd); return success(); } Specialization pass

Slide 52

Slide 52 text

COSCUP 2024 %0 = ruby.constant_int "40" : !ruby.int %1 = ruby.constant_int "2" : !ruby.int %2 = ruby.add %0, %1 : (!ruby.int, !ruby.int) -> !ruby.int %3 = ruby.cast %2 : !ruby.int -> !ruby.opaque_object %4 = ruby.local_variable_write "coscup" = %3 {rb_stmt = true} : ! ruby.opaque_object Specialization pass coscup = 40 + 2

Slide 53

Slide 53 text

COSCUP 2024 • Use Pattern rewrite
 ࢖༻ Pattern rewrite • Change the input type & value.
 վᏓ input Type & input Value • The unused cast will be removed automatically.
 ᔒ༗༻౸త cast ။ࣗಈඃҠআ ܕผਪᏗ Type Inference Pass

Slide 54

Slide 54 text

COSCUP 2024 %0 = ruby.constant_int "40" : !ruby.int %1 = ruby.constant_int "2" : !ruby.int %2 = ruby.add %0, %1 : (!ruby.int, !ruby.int) -> !ruby.int %3 = ruby.cast %2 : !ruby.int -> !ruby.opaque_object %4 = ruby.local_variable_write "coscup" = %3 {rb_stmt = true} : ! ruby.opaque_object ܕผਪᏗ Type Inference Pass coscup = 40 + 2

Slide 55

Slide 55 text

COSCUP 2024 LogicalResult matchAndRewrite(LocalVariableWriteOp op, PatternRewriter &rewriter) const final { auto inputOp = op.getInput().getDefiningOp(); if (!inputOp) { return failure(); } auto newOp = rewriter.create( op.getLoc(), inputOp.getInput().getType(), op.getVarName(), inputOp.getInput()); newOp->setAttrs(op->getAttrs()); rewriter.replaceOp(op, newOp.getOperation()); return success(); } ܕผਪᏗ Type Inference Pass

Slide 56

Slide 56 text

COSCUP 2024 %0 = ruby.constant_int "40" : !ruby.int %1 = ruby.constant_int "2" : !ruby.int %2 = ruby.add %0, %1 : (!ruby.int, !ruby.int) -> !ruby.int %3 = ruby.local_variable_write "coscup" = %2 {rb_stmt = true} : !ruby.int ܕผਪᏗ Type Inference Pass coscup = 40 + 2

Slide 57

Slide 57 text

COSCUP 2024 • Make the IR easier to optimize in following passes.
 ᩋ IR ࡏޙ᠃త Pass தߋ޷࠷ՂԽɻ • Run the fold method automatically.
 ။ࣗಈ䋯 foldɻ • Can add additional pass as part of canonicalize.
 ՄҎ⃧Ճֹ֎త pass ਐنൣԽ pass نൣԽ pass Canonicalization pass

Slide 58

Slide 58 text

COSCUP 2024 • Part of the canonicalization pass
 نൣԽతҰ෦෼ • Use the fold system to remove constant values.
 ࢖༻ fold ိҠআᯩଶᆴɻ
 ৗᏐંᙟ Constant folding

Slide 59

Slide 59 text

COSCUP 2024 ৗᏐંᙟ Constant folding %0 = ruby.constant_int "40" : !ruby.int %1 = ruby.constant_int "2" : !ruby.int %2 = ruby.add %0, %1 : (!ruby.int, !ruby.int) -> !ruby.int %3 = ruby.local_variable_write "coscup" = %2 {rb_stmt = true} : !ruby.int coscup = 40 + 2

Slide 60

Slide 60 text

COSCUP 2024 ৗᏐંᙟ Constant folding def Ruby_AddOp : Ruby_BinaryOp<"add"> { let summary = "Add two objects"; let description = [{ This operation adds two objects. }]; let hasFolder = 1; } coscup = 40 + 2

Slide 61

Slide 61 text

COSCUP 2024 ৗᏐંᙟ Constant folding OpFoldResult AddOp::fold(AddOp::FoldAdaptor adaptor){ auto operands = adaptor.getOperands(); auto strLhs = operands[0].dyn_cast(); auto strRhs = operands[1].dyn_cast(); if (!strLhs || !strRhs) return nullptr; auto lhsInt = ::std::stoi(strLhs.getValue().str()); auto rhsInt = ::std::stoi(strRhs.getValue().str()); auto sum = lhsInt + rhsInt; auto sumStr = ::std::to_string(sum); auto str = StringAttr::get(getContext(), sumStr); return str; } coscup = 40 + 2

Slide 62

Slide 62 text

COSCUP 2024 ৗᏐંᙟ Constant folding Operation *RubyDialect::materializeConstant(OpBuilder &builder, Attribute value, Type type, Location loc) { return llvm::TypeSwitch(type) .Case([&](auto type) { auto strAttr = value.dyn_cast(); return strAttr ? builder.create(loc, type, strAttr) : nullptr; }) .Default([&](auto type) { return nullptr; }); } coscup = 40 + 2

Slide 63

Slide 63 text

COSCUP 2024 ৗᏐંᙟ Constant folding %0 = ruby.constant_int "42" : !ruby.int %1 = ruby.local_variable_write "coscup" = %0 {rb_stmt = true} : !ruby.int coscup = 40 + 2

Slide 64

Slide 64 text

COSCUP 2024 • Use the MLIR translate tools.
 ࢖༻ MLIR ຋ᩄ޻۩ɻ • Translate an op when visited by the visitor.
 ຋ᩄඃ visitor ๚໰౸త op. • Use a rb_stmt attribute to identify the top level statements.
 ࢖༻ rb_stmt attribute ိ൑ผ࠷্૚త statementsɻ ༌ग़ Ruby ఔࣜᛰ Emit Ruby code

Slide 65

Slide 65 text

COSCUP 2024 MLIR Ruby dialect Ruby MLIR Ruby Optimization passes Ruby MLIR Ruby ISEQ YARV MLIR LLVM IR Machine Code

Slide 66

Slide 66 text

COSCUP 2024 ༌ग़ Ruby ఔࣜᛰ Emit Ruby code %0 = ruby.constant_int "42" : !ruby.int %1 = ruby.local_variable_write "coscup" = %0 {rb_stmt = true} : !ruby.int coscup = 40 + 2

Slide 67

Slide 67 text

COSCUP 2024 ༌ग़ Ruby ఔࣜᛰ Emit Ruby code static LogicalResult printOperation(RubyEmitter &emitter, ruby::LocalVariableWriteOp op, bool skipStmtCheck = false) { if (!op->getAttrDictionary().get("rb_stmt") && !skipStmtCheck) return success(); Attribute value = op.getVarNameAttr(); raw_ostream &os = emitter.ostream(); if(!isa(value)) return failure(); if (auto sAttr = dyn_cast(value)) os << sAttr.getValue().str(); os << " = "; if( failed(emitter.emitOperand(op.getInput())) ) return failure(); if (op->getAttrDictionary().get("rb_stmt")) os << "\n"; return success(); }

Slide 68

Slide 68 text

COSCUP 2024 ༌ग़ Ruby ఔࣜᛰ Emit Ruby code coscup = 42 coscup = 40 + 2

Slide 69

Slide 69 text

COSCUP 2024 MLIR Ruby dialect Ruby MLIR Ruby Optimization passes Ruby MLIR Ruby ISEQ YARV MLIR LLVM IR Machine Code

Slide 70

Slide 70 text

COSCUP 2024 • Complete translator between MLIR & Ruby. 
 ׬੔ಘࡏ Ruby & MLIR ؒ᫚׵ɻ • More Optimization Passes ߋଟత࠷ՂԽԋࢉ๏ɻ • Another dialect for YARV ISEQ? 㠥Ұݸ YARV ISEQ dialect ? • Act as a Rubocop backend? ᙛ࡞ Rubocop తޙ୺ʁ • AOT compiling for Ruby? ሣ Ruby ၏ఏલฤᩄʁ • Heterogeneous computing for Ruby? Ruby ҟߏܭࢉʁ Future plans ະိܭᙘ

Slide 71

Slide 71 text

COSCUP 2024 • IR is a tool for compiler to optimize & validate programs.
 தհᛰ(IR) ੋฤᩄث༻ိ࠷ՂԽ࿨ᱛᨽఔࣜత޻۩ • It's time to have a new IR for Ruby.
 Ruby ࠩෆଟՄҎ༗Ұݸ৽ IR ྃ • MLIR is a state of art IR tool.
 MLIR ੋҰݸઌਐత IR ޻۩ • MLIR Ruby can optimize Ruby.
 MLIR Ruby ՄҎ࠷ՂԽ Ruby ݁࿦ Takeaways

Slide 72

Slide 72 text

COSCUP 2024 • • Twitter: @johnlinvc • ᓣܴަྲྀ • https://github.com/johnlinvc/mlir-dialect-ruby • West 㐸࠽தɻ Q&A ౤Өย -->