Support for different imm sizes

I’m trying to define a multiclass for arithmetic instructions (ADD and SUB), which should handle both 8,16 and 32 bits values.

Now, I found an issue while developing the ri pattern:

multiclass ArithmeticInst<bits<8> op, string OpcStr, SDNode OpNode, RegisterClass RC, ValueType RegSize, Operand ImmSize> {
def ri : MyInst<op, (outs RC:$rd), (ins RC:$rs1, i32imm:$immSrc),
                 !strconcat(OpcStr, " $rs1 $immSrc"),
                 [(set RegSize:$rd, (OpNode RegSize:$rs1, (RegSize imm:$immSrc)))]>;
defm ADD8 : ArithmeticInst<24, "add", add, GR8, i8, i8imm>;

defm ADD16 : ArithmeticInst<24, "add", add, GR16, i16, i16imm>;

defm ADD32 : ArithmeticInst<24, "add", add, GR32, i32, i32imm>;

The problem is, my backend will only generate 32-bit constant values for immidiates, so 8 and 16 bits cannot be selected like that.

I tried to add trunc to the pattern, but then the 32 bit was ruined.

Is there a way to do it right?

What do you mean by that?

I’m actually not sure.
But for example, if I try to compile the code:

short e = 2;
short f = e + 4;

I get the output

%e = alloca i16, align 2
%f = alloca i16, align 2
store i16 2, ptr %e, align 2
%0 = load i16, ptr %e, align 2
%conv = sext i16 %0 to i32
%add = add nsw i32 %conv, 4
%conv1 = trunc i32 %add to i16
store i16 %conv1, ptr %f, align 2

And it is even more noticeable with

short e = 2;
short f = e << 4;

which doesn’t even compile:

fatal error: error in backend: Cannot select: t16: i16 = shl t6, Constant:i32<4>

Now, it was this error, that made me think that the backend just generates i32imm, and for that reason it is not able to select my instruction (the SHL instruction is defined in a similar way to the ADD instruction I showed before)

Shifts are different from arithmetic and logical instructions in that they can have different argument types.
The size of the shift amount is controlled by TargetLoweringBase::getScalarShiftAmountTy.
You either need to override this method, or doulbe check the type of the shift amount in your instruction set manual, or both.

O i see than.

I tried now to set manually to i32imm and it works!
thanks a lot :smiley:

I still have a question though, which is part of the reason I was confused about it.
it seems that in the case of the ADD instruction, it chose to promote the i16 types to i32 and than trunc them back, then it could just use the ADD16 instruction. is there a reason for it? I would rather it wouldn’t do that…

If you mean input IR, this is how C works. e is promoted to int before addition, hence sext.
If you turn on optimizations, sext + trunc will be folded, I think.

I find it quite weird to be honest, but I guess it’s ok.

Either way, it seems to be all set.
thank you very much for the help! :slight_smile: