Welcome to Walking the Greek Islands


Welcome to islandwalking.com! This site contains travelling and trekking tips for the Greek islands as well as many other islands in or not too far from the Mediterranean. It is not intended to replace any tourist or walking guides that you might have, it is only a small supplement. And indeed, it is even a prerequisite for most of the descriptions of walks on these pages that you own the guide book(s) referred to in the text.

In this blog you can also expect rants about just about anything possibly related to walking as well as music or computers or beer or other “interesting” topics.

This site is dedicated to my parents Elsa (1934-2013) and Lars (1930-2020)

Categories: Uncategorized | Comments Off on Welcome to Walking the Greek Islands

Wonder Woman

Categories: Uncategorized | Comments Off on Wonder Woman

One Day Late

Categories: Uncategorized | Comments Off on One Day Late

No Words

Categories: Uncategorized | Comments Off on No Words

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

Superdense Coding Emulation on a TI-84 Plus CE-T

This is sort of the opposite of the Quantum Teleportation we have covered earlier. Here you use quantum bits to transfer classical bits:

We have all the building blocks we need from the previous episode, so let me just show you the additional code:

#Alice bits
a1=1
a2=1
print("Alice bits:",a1,a2)

#Initialize inputs
q=[[1],[0],[0],[0]]

#Build circuit
U=kron(H,I)
U=mult(CNOT,U)

#Encode bits
if a2==1:
  U=mult(kron(X,I),U)
if a1==1:
  U=mult(kron(Z,I),U)

#Run circuit
q=mult(U,q)

#Bob applies gates
q=mult(CNOT,q)
q=mult(kron(H,I),q)

#Bob measurements
b1=qbit(0,M(q))
q=qbitset(0,b1,q)
b2=qbit(1,M(q))
q=qbitset(1,b2,q)

print("Bob measurements:",b1,b2)

So as an example we try to give Bob the bits 1 and 1. Bob does his measurements and this is the result:

Categories: Uncategorized | Comments Off on Superdense Coding Emulation on a TI-84 Plus CE-T

LLVM Exercise III

Let us return a larger constant:

int foo() {
    return 0xFF;
}

For numbers up to 12 bits we can use the LDI S&X instruction. Some code snippets:

def immSExt12 : PatLeaf<(imm),
                    [{ return isInt<12>(N->getSExtValue()); }]>;

def : Pat<(i32 immSExt12:$in), (LDI imm:$in)>;

def LDI : HP41MCODEInst<0x130, (outs RC:$r), (ins i32imm:$sx),
                        "LDI S&X HEX: $sx",
                        [(set RC:$r, (i32 immSExt12:$sx))]>;

This produces:

	.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
	.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 III

LLVM Exercise II

A tiny addition to the empty function. Returning zero:

int foo() {
    return 0;
}

Remember, we will not care about returning values to the calculator registers (at not least for now). We will only generate functions callable from MCODE. So as a convention we will choose to return values in the C register.

So we will need an instruction to load 0 into the C register:

def Ceq0ALL : HP41MCODEInst<0x04E, (outs RC:$r), (ins),
                            "C=0 ALL", [(set RC:$r, 0)]>;

This replacement pattern will make sure a constant 0 is loaded with this instruction:

def : Pat<(i32 0), (Ceq0ALL)>;

A register class for just this register (the instruction is only used with the C register, i.e. implicit addressing):

def RC : RegisterClass<"HP41MCODE", [i32], 8, (add C)>;

Defining the calling convention to return values in the C register:

def RetCC_HP41MCODE : CallingConv<[
      CCAssignToReg<[C]>
    ]>;

Adding this calling convention to the LowerReturn() function mentioned earlier, to analyze returns:

SDValue
HP41MCODETargetLowering::LowerReturn(SDValue Chain,
        CallingConv::ID CallConv,
        bool IsVarArg,
        const SmallVectorImpl &Outs,
        const SmallVectorImpl &OutVals,
        const SDLoc &DL, SelectionDAG &DAG) const {
  ...
  // Analyze return values.
  CCInfo.AnalyzeReturn(Outs, RetCC_HP41MCODE);
  ...
  return DAG.getNode(HP41MCODEISD::RTN, DL, MVT::Other, RetOps);
}

That gives us this MCODE assembly:

	.file	"hello.c"
	.text
	.globl	foo                     ! -- Begin function foo
	.type	foo,@function
foo:                                    ! @foo
! %bb.0:                                ! %entry
	C=0 ALL
	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 II