{"id":5355,"date":"2025-02-08T12:13:13","date_gmt":"2025-02-08T11:13:13","guid":{"rendered":"https:\/\/www.islandwalking.com\/wordpress\/?p=5355"},"modified":"2025-02-08T16:40:06","modified_gmt":"2025-02-08T15:40:06","slug":"llvm-exercise-vi","status":"publish","type":"post","link":"https:\/\/www.islandwalking.com\/wordpress\/llvm-exercise-vi\/","title":{"rendered":"LLVM Exercise VI"},"content":{"rendered":"<p>It is time to bring in some conditionals. Adding an &#8220;if&#8221; to our friend foo():<\/p>\n<blockquote>\n<pre>    int foo() {\r\n      int retval1 = 0x0AB;\r\n      int retval2 = 0;\r\n      if (retval2)\r\n        return retval2;\r\n      return retval1;\r\n    }\r\n<\/pre>\n<\/blockquote>\n<p>We need to implement instructions for both conditional and unconditional branches (i.e jumps). An unconditional branch is just like this (assuming no carry flag is set):<\/p>\n<blockquote>\n<pre>    ...\r\n\r\n    def brtarget : Operand;\r\n    \r\n    ...\r\n    \r\n    let isBarrier=1, isBranch=1, isTerminator=1 in\r\n    {\r\n    def JNC : HP41MCODEInst&lt;0x00B, (outs), (ins brtarget:$addr),\r\n                            \"JNC $addr\", [(br bb:$addr)]&gt;;\r\n    }\r\n<\/pre>\n<\/blockquote>\n<p>We will use custom lowered pseudo instructions as an easy solution. This is a start:<\/p>\n<blockquote>\n<pre>    class HP41MCODEPseudo pattern&gt; : HP41MCODEInst&lt;0, outs, ins,\r\n        asmstr, pattern&gt; {\r\n      let isCodeGenOnly = 1;\r\n      let isPseudo = 1;\r\n    }\r\n\r\n    ...\r\n\r\n    SDT_HP41MCODEBRCC : SDTypeProfile&lt;0, 4, [SDTCisVT&lt;0,\r\n                                             OtherVT&gt;]&gt;;\r\n    \r\n    def HP41MCODEBRCC     : SDNode&lt;\"HP41MCODEISD::BRCC\",\r\n            SDT_HP41MCODEBRCC, [SDNPHasChain, SDNPInGlue]&gt;;\r\n\r\n    ...\r\n    \r\n    let isBranch=1, isTerminator=1 in\r\n    {\r\n    def BRCC : HP41MCODEPseudo&lt; (outs), (ins brtarget:$addr,\r\n            RC:$lhs, i32imm:$rhs, i32imm:$cond),\r\n            \"#BRCC $addr $lhs $rhs $cond\",\r\n            [(HP41MCODEBRCC bb:$addr, RC:$lhs, (i32 imm:$rhs),\r\n             (i32 imm:$cond))]&gt;;\r\n    }\r\n<\/pre>\n<\/blockquote>\n<p>Note that this instruction will only match the case we have in this example. Different cases should use different instructions. More code snippets:<\/p>\n<blockquote>\n<pre>    ...\r\n\r\n      BRCC,        \/\/ Branch to dest on condition\r\n          \r\n    ...\r\n          \r\n    SDValue LowerBR_CC(SDValue Op, SelectionDAG &amp;DAG) const;\r\n\r\n    ...\r\n      \r\n    setOperationAction(ISD::BR_CC, MVT::i32, Custom);\r\n      \r\n    ...\r\n      \r\n      case HP41MCODEISD::BRCC: return \"HP41MCODEISD::BRCC\";\r\n      \r\n    ...\r\n    \r\n    SDValue HP41MCODETargetLowering::LowerBR_CC(SDValue Op,\r\n            SelectionDAG &amp;DAG) const {\r\n      SDValue Chain = Op.getOperand(0);\r\n      ISD::CondCode CC = cast(Op.getOperand(1))-&gt;get();\r\n      SDValue LHS = Op.getOperand(2);\r\n      SDValue RHS = Op.getOperand(3);\r\n      SDValue Dest = Op.getOperand(4);\r\n      SDLoc dl(Op);\r\n\r\n      return DAG.getNode(HP41MCODEISD::BRCC, dl, MVT::Other,\r\n              Chain, Dest, LHS, RHS,\r\n              DAG.getConstant(CC, dl, MVT::i32));\r\n    }\r\n    \r\n    ...\r\n\r\n      case ISD::BR_CC:\r\n        return LowerBR_CC(Op, DAG);\r\n    \r\n<\/pre>\n<\/blockquote>\n<p>So for this example we only need to produce machine instructions that compares the C register to <code>0<\/code> and then branches if it is equal. This must be done in a post-RA pass:<\/p>\n<blockquote>\n<pre>    bool HP41MCODEInstrInfo::expandPostRAPseudo(\r\n          MachineInstr &amp;MI) const {\r\n      MachineBasicBlock &amp;MBB = *MI.getParent();\r\n      MachineFunction &amp;MF = *MBB.getParent();\r\n      const HP41MCODEInstrInfo &amp;TII = *static_cast(\r\n          MF.getSubtarget().getInstrInfo());\r\n      DebugLoc dl = MBB.findDebugLoc(MI);\r\n\r\n      switch (MI.getOpcode()) {\r\n      case HP41MCODE::BRCC: {\r\n        assert(MI.getOperand(1).getReg() == HP41MCODE::C &amp;&amp;\r\n               \"Not implemented!\");\r\n        assert(MI.getOperand(2).getImm() == 0 &amp;&amp;\r\n               \"Not implemented!\");\r\n        assert(MI.getOperand(3).getImm() == ISD::SETEQ &amp;&amp;\r\n               \"Not implemented!\");\r\n\r\n        BuildMI(MBB, MI, dl, TII.get(HP41MCODE::qCneq0ALL));\r\n        BuildMI(MBB, MI, dl,\r\n                TII.get(HP41MCODE::JNC)).addMBB(\r\n                        MI.getOperand(0).getMBB());\r\n        MI.eraseFromParent();\r\n        return true;\r\n      }\r\n      }\r\n      return false;\r\n    }\r\n<\/pre>\n<\/blockquote>\n<p>This is the machine instruction used:<\/p>\n<blockquote>\n<pre>    def qCneq0ALL : HP41MCODEInst&lt;0x2EE, (outs), (ins),\r\n                                  \"?C!=0 ALL\", []&gt;;\r\n<\/pre>\n<\/blockquote>\n<p>And we get:<\/p>\n<blockquote>\n<pre>\t.file\t\"hello.c\"\r\n\t.text\r\n\t.globl\tfoo                     ! -- Begin function foo\r\n\t.type\tfoo,@function\r\nfoo:                                    ! @foo\r\n! %bb.0:                                ! %entry\r\n\tLDI S&amp;X HEX: 0AB\r\n\tWRIT 2\r\n\tC=0 ALL\r\n\tWRIT 1\r\n\tREAD 1\r\n\t?C!=0 ALL\r\n\tJNC .LBB0_2\r\n! %bb.1:                                ! %if.then\r\n\tREAD 1\r\n\tWRIT 3\r\n\tJNC .LBB0_3\r\n.LBB0_2:                                ! %if.end\r\n\tREAD 2\r\n\tWRIT 3\r\n.LBB0_3:                                ! %return\r\n\tREAD 3\r\n\tRTN\r\n.Lfunc_end0:\r\n\t.size\tfoo, .Lfunc_end0-foo\r\n                                        ! -- End function\r\n\t.ident\t\"clang version 20.0.0git (https:\/\/github.com\/llvm\/llvm-project.git ea1dfd50bfdfbd75969fd7653bc71c81f2a2350f)\"\r\n\t.section\t\".note.GNU-stack\"\r\n\t.addrsig\r\n<\/pre>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>It is time to bring in some conditionals. Adding an &#8220;if&#8221; to our friend foo(): int foo() { int retval1 = 0x0AB; int retval2 = 0; if (retval2) return retval2; return retval1; } We need to implement instructions for both conditional and unconditional branches (i.e jumps). An unconditional branch is just like this (assuming no &hellip; <a class=\"read-excerpt\" href=\"https:\/\/www.islandwalking.com\/wordpress\/llvm-exercise-vi\/\">Continue reading <span class=\"meta-nav\">&raquo;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5355","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/posts\/5355","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/comments?post=5355"}],"version-history":[{"count":6,"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/posts\/5355\/revisions"}],"predecessor-version":[{"id":5361,"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/posts\/5355\/revisions\/5361"}],"wp:attachment":[{"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/media?parent=5355"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/categories?post=5355"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.islandwalking.com\/wordpress\/wp-json\/wp\/v2\/tags?post=5355"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}