Ios Updates

30 years or so after my first visit to the island, my Ios page has finally been updated with some actual walks. Is Ios a good island for walking? Absolutely not! But it has other qualities…

Categories: Uncategorized | Comments Off on Ios Updates

Ios

Added a few pictures from Ios.

Categories: Uncategorized | Comments Off on Ios

Ioannina page

I have made a small page about Ioannina. There is at least one particularly wonderful walk/stroll you can do in this beautiful town.

Categories: Uncategorized | Comments Off on Ioannina page

Ioannina

New pictures, this time from beautiful Ioannina.

Categories: Uncategorized | Comments Off on Ioannina

Symi Updates

The Symi page has updates for most of the walks from last year plus two new short walks.

Categories: Uncategorized | Comments Off on Symi Updates

Symi Again

More pictures from Symi at https://www.islandwalking.com/piwigo/index.php?/category/167.

Categories: Uncategorized | Comments Off on Symi Again

LLVM Exercise VII

So why does the code produced in the last exercise contain the labels .LBB0_2 and .LBB0_3 but no .LBB0_1?

Well that is because I have added a code generation pass that deletes useless jumps like:

    	JNC .LBB0_1
    .LBB0_1:

Code snippets:

void HP41MCODEPassConfig::addPreEmitPass() {
    addPass(new RemoveUselessJMP()); }

...

bool RemoveUselessJMP::runOnMachineBasicBlock(
    MachineBasicBlock &MBB, MachineBasicBlock &MBBN) {
  bool Modified = false;

  MachineBasicBlock::iterator I = MBB.end();
  if (I != MBB.begin())
    I--;
  else
    return Modified;

  if (I->getOpcode() == HP41MCODE::JNC &&
        I->getOperand(0).getMBB() == &MBBN) {
    MBB.erase(I);
    Modified = true;
  }

  return Modified;
}

bool RemoveUselessJMP::runOnMachineFunction(MachineFunction &MF) {
  bool Modified = false;
  MachineFunction::iterator FJ = MF.begin();
  if (FJ != MF.end())
    FJ++;
  if (FJ == MF.end())
    return Modified;
  for (MachineFunction::iterator FI = MF.begin(),
       FE = MF.end(); FJ != FE; ++FI, ++FJ)
    Modified |= runOnMachineBasicBlock(*FI, *FJ);
 
  return Modified;
}

Categories: Uncategorized | Comments Off on LLVM Exercise VII

LLVM Exercise VI

It is time to bring in some conditionals. Adding an “if” 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 carry flag is set):

    ...

    def brtarget : Operand;
    
    ...
    
    let isBarrier=1, isBranch=1, isTerminator=1 in
    {
    def JNC : HP41MCODEInst<0x00B, (outs), (ins brtarget:$addr),
                            "JNC $addr", [(br bb:$addr)]>;
    }

We will use custom lowered pseudo instructions as an easy solution. This is a start:

    class HP41MCODEPseudo pattern> : HP41MCODEInst<0, outs, ins,
        asmstr, pattern> {
      let isCodeGenOnly = 1;
      let isPseudo = 1;
    }

    ...

    SDT_HP41MCODEBRCC : SDTypeProfile<0, 4, [SDTCisVT<0,
                                             OtherVT>]>;
    
    def HP41MCODEBRCC     : SDNode<"HP41MCODEISD::BRCC",
            SDT_HP41MCODEBRCC, [SDNPHasChain, SDNPInGlue]>;

    ...
    
    let isBranch=1, isTerminator=1 in
    {
    def BRCC : HP41MCODEPseudo< (outs), (ins brtarget:$addr,
            RC:$lhs, i32imm:$rhs, i32imm:$cond),
            "#BRCC $addr $lhs $rhs $cond",
            [(HP41MCODEBRCC bb:$addr, RC:$lhs, (i32 imm:$rhs),
             (i32 imm:$cond))]>;
    }

Note that this instruction will only match the case we have in this example. Different cases should use different instructions. More code snippets:

    ...

      BRCC,        // Branch to dest on condition
          
    ...
          
    SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;

    ...
      
    setOperationAction(ISD::BR_CC, MVT::i32, Custom);
      
    ...
      
      case HP41MCODEISD::BRCC: return "HP41MCODEISD::BRCC";
      
    ...
    
    SDValue HP41MCODETargetLowering::LowerBR_CC(SDValue Op,
            SelectionDAG &DAG) const {
      SDValue Chain = Op.getOperand(0);
      ISD::CondCode CC = cast(Op.getOperand(1))->get();
      SDValue LHS = Op.getOperand(2);
      SDValue RHS = Op.getOperand(3);
      SDValue Dest = Op.getOperand(4);
      SDLoc dl(Op);

      return DAG.getNode(HP41MCODEISD::BRCC, dl, MVT::Other,
              Chain, Dest, LHS, RHS,
              DAG.getConstant(CC, dl, MVT::i32));
    }
    
    ...

      case ISD::BR_CC:
        return LowerBR_CC(Op, DAG);
    

So for this example we only need to produce machine instructions that compares the C register to 0 and then branches if it is equal. This must be done in a post-RA pass:

    bool HP41MCODEInstrInfo::expandPostRAPseudo(
          MachineInstr &MI) const {
      MachineBasicBlock &MBB = *MI.getParent();
      MachineFunction &MF = *MBB.getParent();
      const HP41MCODEInstrInfo &TII = *static_cast(
          MF.getSubtarget().getInstrInfo());
      DebugLoc dl = MBB.findDebugLoc(MI);

      switch (MI.getOpcode()) {
      case HP41MCODE::BRCC: {
        assert(MI.getOperand(1).getReg() == HP41MCODE::C &&
               "Not implemented!");
        assert(MI.getOperand(2).getImm() == 0 &&
               "Not implemented!");
        assert(MI.getOperand(3).getImm() == ISD::SETEQ &&
               "Not implemented!");

        BuildMI(MBB, MI, dl, TII.get(HP41MCODE::qCneq0ALL));
        BuildMI(MBB, MI, dl,
                TII.get(HP41MCODE::JNC)).addMBB(
                        MI.getOperand(0).getMBB());
        MI.eraseFromParent();
        return true;
      }
      }
      return false;
    }

This is the machine instruction used:

    def qCneq0ALL : HP41MCODEInst<0x2EE, (outs), (ins),
                                  "?C!=0 ALL", []>;

And we get:

	.file	"hello.c"
	.text
	.globl	foo                     ! -- Begin function foo
	.type	foo,@function
foo:                                    ! @foo
! %bb.0:                                ! %entry
	LDI S&X HEX: 0AB
	WRIT 2
	C=0 ALL
	WRIT 1
	READ 1
	?C!=0 ALL
	JNC .LBB0_2
! %bb.1:                                ! %if.then
	READ 1
	WRIT 3
	JNC .LBB0_3
.LBB0_2:                                ! %if.end
	READ 2
	WRIT 3
.LBB0_3:                                ! %return
	READ 3
	RTN
.Lfunc_end0:
	.size	foo, .Lfunc_end0-foo
                                        ! -- End function
	.ident	"clang version 20.0.0git (https://github.com/llvm/llvm-project.git ea1dfd50bfdfbd75969fd7653bc71c81f2a2350f)"
	.section	".note.GNU-stack"
	.addrsig
Categories: Uncategorized | Comments Off on LLVM Exercise VI

LLVM Exercise V

Let us add some local variables:

int foo() {
  int retval = 0x0AB;
  int dummy = 0;
  return retval;
}

This requires adding some information about accessing memory. I will just postulate that I have memory available from address 1 growing upwards. As anyone that really knows the HP-41 understands, this is a very bad idea. However we are still just showing some basic LLVM principles, not producing actually useful Nut code. I am however excluding the possibility of generating READ 0, as that instruction does not even exist.

Some code snippets:

    // Addressing modes.
    def ADDR : ComplexPattern<iPTR, 2, "SelectADDR",
                              [frameindex], []>;

    // Address operands
    def MEM : Operand {
      let MIOperandInfo = (ops RC, i16imm);
      let PrintMethod = "printMemOperand";
      let DecoderMethod = "decodeMemOperand";
    }
    
    ...
    
    let mayLoad=1 in {
    def READ : HP41MCODEInst<0x078, (outs RC:$r),
            (ins MEM:$addr), "READ $addr",
            [(set RC:$r, (load ADDR:$addr))]>;
    }

    let mayStore=1 in {
    def WRIT : HP41MCODEInst<0x068, (outs), (ins MEM:$addr,
            RC:$r), "WRIT $addr", [(store RC:$r, ADDR:$addr)]>;
    }

    ...

    bool
    HP41MCODERegisterInfo::eliminateFrameIndex(
            MachineBasicBlock::iterator II,
            int SPAdj, unsigned FIOperandNum,
            RegScavenger *RS) const {
        MachineInstr &MI = *II;
        int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
        MachineFunction &MF = *MI.getParent()->getParent();
        const HP41MCODEFrameLowering *TFI = getFrameLowering(MF);
        llvm::Register FrameReg;
        int Offset;
        Offset = TFI->getFrameIndexReference(MF, FrameIndex,
                FrameReg).getFixed()/4+1;
        MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg,
                false);
        MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
        return false;
    }

    ...

    void HP41MCODEInstPrinter::printMemOperand(const MCInst *MI,
            int opNum,
            const MCSubtargetInfo &STI,
            raw_ostream &O, const char *Modifier) {
        const MCOperand &MO = MI->getOperand(opNum+1);
        
        if (MO.isImm()) {
            O << format_decimal((int)MO.getImm(), 1); return; }
                    assert(MO.isExpr() &&
                    "Unknown operand kind in printMemOperand");
                    MO.getExpr()->print(O, &MAI);
    }

    ...

    bool HP41MCODEDAGToDAGISel::SelectADDR(SDValue Addr,
            SDValue &Base, SDValue &Offset) {
      if (FrameIndexSDNode *FIN = dyn_cast(Addr)) {
        Base = CurDAG->getTargetFrameIndex(
                FIN->getIndex(), TLI->getPointerTy(
                        CurDAG->getDataLayout()));
        Offset = CurDAG->getTargetConstant(0, SDLoc(Addr),
                        MVT::i32);
        return true;
      }

      return false;
    }


Then we end up with:

	.file	"hello.c"
	.text
	.globl	foo                     ! -- Begin function foo
	.type	foo,@function
foo:                                    ! @foo
! %bb.0:                                ! %entry
	LDI S&X HEX: 0AB
	WRIT 2
	C=0 ALL
	WRIT 1
	READ 2
	RTN
.Lfunc_end0:
	.size	foo, .Lfunc_end0-foo
                                        ! -- End function
	.ident	"clang version 20.0.0git (https://github.com/llvm/llvm-project.git ea1dfd50bfdfbd75969fd7653bc71c81f2a2350f)"
	.section	".note.GNU-stack"
	.addrsig

Categories: Uncategorized | Comments Off on LLVM Exercise V

LLVM Exercise IV

How about calling another function:

int foo() {
    return 0xFF;
}

int bar() {
    return foo();
}

Code snippets:

...

def CC_HP41MCODE : CallingConv<[]>;

...

def SDT_HP41MCODENCXQ : SDTypeProfile<0, -1,
                                      [SDTCisVT<0, iPTR>]>;
def HP41MCODENCXQ : SDNode<"HP41MCODEISD::NCXQ",
                           SDT_HP41MCODENCXQ,
                           [SDNPHasChain, SDNPOptInGlue,
                            SDNPOutGlue, SDNPVariadic]>;

...

def calltarget : Operand;

...

let isCall=1 in {
    def NCXQ : HP41MCODEInst<0x001, (outs),
                             (ins calltarget:$addr),
                             "?NC XQ $addr",
                             [(HP41MCODENCXQ
                              tglobaladdr:$addr)]>;
}

...

NCXQ,         // A call instruction.

...

SDValue
HP41MCODETargetLowering::LowerCall(
        TargetLowering::CallLoweringInfo &CLI,
        SmallVectorImpl &InVals) const {
    ...

    CCInfo.AnalyzeCallOperands(Outs, CC_HP41MCODE);

    ...

    Chain = DAG.getNode(HP41MCODEISD::NCXQ, DL, NodeTys, Ops);

    ...

    return Chain;
}

...

The following assembly is produced:

	.file	"hello.c"
	.text
	.globl	foo                     ! -- Begin function foo
	.type	foo,@function
foo:                                    ! @foo
! %bb.0:                                ! %entry
	LDI S&X HEX: 0FF
	RTN
.Lfunc_end0:
	.size	foo, .Lfunc_end0-foo
                                        ! -- End function
	.globl	bar                     ! -- Begin function bar
	.type	bar,@function
bar:                                    ! @bar
! %bb.0:                                ! %entry
	?NC XQ foo
	RTN
.Lfunc_end1:
	.size	bar, .Lfunc_end1-bar
                                        ! -- End function
	.ident	"clang version 20.0.0git (https://github.com/llvm/llvm-project.git ea1dfd50bfdfbd75969fd7653bc71c81f2a2350f)"
	.section	".note.GNU-stack"
	.addrsig
	.addrsig_sym foo

Categories: Uncategorized | Comments Off on LLVM Exercise IV