Services and Modeling for Embedded Software Development
Embecosm divider strip
Prev  Next

3.3.  archOperand Structure

Before the instruction matcher can be created the archOperand structure must be defined. This represents a parsed machine instruction, storing information about the types and contents of its operands.

[Note]Note

This class inherits from MCParsedAsmOperand, whose API can be found at llvm.org/docs/doxygen/html/classllvm_1_1MCParsedAsmOperand.html.

Within this structure is an enum and union which store the operand along with its type.

In the case for OpenRISC 1000 , these operand types are tokens, registers and immediate. Similarly, SMLocs (source code locations) are stored for the start and stop locations of the operand.

  enum KindTy {
    Token,
    Register,
    Immediate
  } Kind;

  SMLoc StartLoc, EndLoc;

  union {
    struct {
      const char *Data;
      unsigned Length;
    } Tok;
    struct {
      unsigned RegNum;
    } Reg;
    struct {
      const MCExpr *Val;
    } Imm;
  };
        

The majority of functions within this struct are simply getters and setters for the different operands stored in the object. For the getters, asserts are added to check that the operand is of the correct type before returning its value. An example is shown below.

  StringRef getToken() const {
    assert (Kind == Token && "Invalid type access!");
    return StringRef(Tok.Data, Tok.Length);
  }
        

Generator functions called CreateToken, CreateReg etc. are defined which take the data type for the operand as well as the start and end locations of the operand (with the exception of tokens which only take a start location). These functions then create a new object for the provided operand details, set its contents and then returns it.

The final functions in this structure add operands to a particular instruction. These use the addOperand function of a MCInst to add the relevant operand. For registers, the getReg() is simply used. Immediates however use a more complex method where if it is possible to add the instruction as an immediate it is done so, otherwise it is added as an expression, as demonstrated below.

  void addExpr(MCInst &Inst, const MCExpr *Expr) const {
    // Add as immediates where possible. Null MCExpr = 0
    if (Expr == 0)
      Inst.addOperand(MCOperand::CreateImm(0));
    else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
      Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
    else
      Inst.addOperand(MCOperand::CreateExpr(Expr));
  }
        
Embecosm divider strip