What is the difference in the behavior of the following pieces of code? What does i32 specify in the first code? What’s the procedure if I want to declare one of my operands as an immediate value of 12 bits?
The last line specifies the pattern for the selection DAG. Using i32 makes sure that the operand has the specified type - it works as a predicate.
Why would you need this? When you define the register class you specify a (possible empty) list of types this register can hold. For example, a floating point register may hold f32 or f64 values. You may then want to specify the type to limit instruction selection to that type.
To define an 12bit immediate operand, you can begin with:
let OperandType = "OPERAND_IMMEDIATE" in
def i12imm : Operand<i2>;
Most likely, you also want a predicate to use for the instruction selection. Both can be combined, e.g.
class ImmediateOp<ValueType vt> : Operand<vt> {
let OperandType = "OPERAND_IMMEDIATE";
}
def i12imm : ImmediateOp<12>, IntImmLeaf<i12, [{
uint64_t Val = Imm.getZExtValue();
return isUInt<12>(Val);
}]>;