On Thursday, 13 July 2017 at 12:45:19 UTC, Stefan Koch wrote:
[ ... ]
Hi Guys I just fixed another bug that had me puzzled for a while.

The following function

ulong swap(ulong val)
{
    ulong result;

        result |= (val & 0xFF) << 56;
        result |= (val & 0xFF00) << 40;
        result |= (val & 0xFF00_00) << 24;
        result |= (val & 0xFF00_0000) << 8;

        result |= (val & 0xFF00_0000_00) >> 8;
        result |= (val & 0xFF00_0000_0000) >> 24;
        result |= (val & 0xFF00_0000_0000_00) >> 40;
        result |= (val & 0xFF00_0000_0000_0000) >> 56;

    return result;
}

would return strange values.
pragma(msg, swap(0xABCD_EF01_2345_6789)); // returns 9900958322423496704 // expected 9900958322455989675 On further inspection the actual return value has only zeros in the lower 32 bits.

The generated IR however looks completey correct.

    Initialize();
        Line(1);

        auto val_1 = genParameter(BCType(BCTypeEnum.i64));//SP[4]
        beginFunction(0);//swap
            Line(2);
            Line(3);
auto result_1 = genLocal(BCType(BCTypeEnum.i64), "result");//SP[8]
            Set(result_1, BCValue(Imm64(0)));
            Line(5);
auto tmp1 = genTemporary(BCType(BCTypeEnum.i64));//SP[16] auto tmp2 = genTemporary(BCType(BCTypeEnum.i64));//SP[24]
            And3(tmp2, val_1, BCValue(Imm64(255)));
auto tmp3 = genTemporary(BCType(BCTypeEnum.i32));//SP[32]
            Le3(tmp3, BCValue(Imm32(56)), BCValue(Imm32(63)));
auto tmp4 = genTemporary(BCType(BCTypeEnum.i32));//SP[36]
            Set(tmp4, BCValue(Imm32(56)));
auto tmp5 = genTemporary(BCType(BCTypeEnum.i32));//SP[40]
            Set(tmp5, BCValue(Imm32(63)));
Assert(tmp3, Imm32(1) /*"shift by %d is outside the range 0..%d", BCValue(Imm32(56)), BCValue(Imm32(63))*/;);
            Lsh3(tmp1, tmp2, BCValue(Imm32(56)));
            Or3(result_1, result_1, tmp1);
            Line(6);
auto tmp6 = genTemporary(BCType(BCTypeEnum.i64));//SP[44] auto tmp7 = genTemporary(BCType(BCTypeEnum.i64));//SP[52]
            And3(tmp7, val_1, BCValue(Imm64(65280)));
auto tmp8 = genTemporary(BCType(BCTypeEnum.i32));//SP[60]
            Le3(tmp8, BCValue(Imm32(40)), BCValue(Imm32(63)));
auto tmp9 = genTemporary(BCType(BCTypeEnum.i32));//SP[64]
            Set(tmp9, BCValue(Imm32(40)));
auto tmp10 = genTemporary(BCType(BCTypeEnum.i32));//SP[68]
            Set(tmp10, BCValue(Imm32(63)));
Assert(tmp8, Imm32(2) /*"shift by %d is outside the range 0..%d", BCValue(Imm32(40)), BCValue(Imm32(63))*/;);
            Lsh3(tmp6, tmp7, BCValue(Imm32(40)));
            Or3(result_1, result_1, tmp6);
            Line(7);
auto tmp11 = genTemporary(BCType(BCTypeEnum.i64));//SP[72] auto tmp12 = genTemporary(BCType(BCTypeEnum.i64));//SP[80]
            And3(tmp12, val_1, BCValue(Imm64(16711680)));
auto tmp13 = genTemporary(BCType(BCTypeEnum.i32));//SP[88]
            Le3(tmp13, BCValue(Imm32(24)), BCValue(Imm32(63)));
auto tmp14 = genTemporary(BCType(BCTypeEnum.i32));//SP[92]
            Set(tmp14, BCValue(Imm32(24)));
auto tmp15 = genTemporary(BCType(BCTypeEnum.i32));//SP[96]
            Set(tmp15, BCValue(Imm32(63)));
Assert(tmp13, Imm32(3) /*"shift by %d is outside the range 0..%d", BCValue(Imm32(24)), BCValue(Imm32(63))*/;);
            Lsh3(tmp11, tmp12, BCValue(Imm32(24)));
            Or3(result_1, result_1, tmp11);
            Line(8);
auto tmp16 = genTemporary(BCType(BCTypeEnum.i64));//SP[100] auto tmp17 = genTemporary(BCType(BCTypeEnum.i64));//SP[108]
            And3(tmp17, val_1, BCValue(Imm64(4278190080)));
auto tmp18 = genTemporary(BCType(BCTypeEnum.i32));//SP[116]
            Le3(tmp18, BCValue(Imm32(8)), BCValue(Imm32(63)));
auto tmp19 = genTemporary(BCType(BCTypeEnum.i32));//SP[120]
            Set(tmp19, BCValue(Imm32(8)));
auto tmp20 = genTemporary(BCType(BCTypeEnum.i32));//SP[124]
            Set(tmp20, BCValue(Imm32(63)));
Assert(tmp18, Imm32(4) /*"shift by %d is outside the range 0..%d", BCValue(Imm32(8)), BCValue(Imm32(63))*/;);
            Lsh3(tmp16, tmp17, BCValue(Imm32(8)));
            Or3(result_1, result_1, tmp16);
            Line(10);
auto tmp21 = genTemporary(BCType(BCTypeEnum.i64));//SP[128] auto tmp22 = genTemporary(BCType(BCTypeEnum.i64));//SP[136]
            And3(tmp22, val_1, BCValue(Imm64(1095216660480)));
auto tmp23 = genTemporary(BCType(BCTypeEnum.i32));//SP[144]
            Le3(tmp23, BCValue(Imm32(8)), BCValue(Imm32(63)));
auto tmp24 = genTemporary(BCType(BCTypeEnum.i32));//SP[148]
            Set(tmp24, BCValue(Imm32(8)));
auto tmp25 = genTemporary(BCType(BCTypeEnum.i32));//SP[152]
            Set(tmp25, BCValue(Imm32(63)));
Assert(tmp23, Imm32(5) /*"shift by %d is outside the range 0..%d", BCValue(Imm32(8)), BCValue(Imm32(63))*/;);
            Rsh3(tmp21, tmp22, BCValue(Imm32(8)));
            Or3(result_1, result_1, tmp21);
            Line(11);
auto tmp26 = genTemporary(BCType(BCTypeEnum.i64));//SP[156] auto tmp27 = genTemporary(BCType(BCTypeEnum.i64));//SP[164]
            And3(tmp27, val_1, BCValue(Imm64(280375465082880)));
auto tmp28 = genTemporary(BCType(BCTypeEnum.i32));//SP[172]
            Le3(tmp28, BCValue(Imm32(24)), BCValue(Imm32(63)));
auto tmp29 = genTemporary(BCType(BCTypeEnum.i32));//SP[176]
            Set(tmp29, BCValue(Imm32(24)));
auto tmp30 = genTemporary(BCType(BCTypeEnum.i32));//SP[180]
            Set(tmp30, BCValue(Imm32(63)));
Assert(tmp28, Imm32(6) /*"shift by %d is outside the range 0..%d", BCValue(Imm32(24)), BCValue(Imm32(63))*/;);
            Rsh3(tmp26, tmp27, BCValue(Imm32(24)));
            Or3(result_1, result_1, tmp26);
            Line(12);
auto tmp31 = genTemporary(BCType(BCTypeEnum.i64));//SP[184] auto tmp32 = genTemporary(BCType(BCTypeEnum.i64));//SP[192]
            And3(tmp32, val_1, BCValue(Imm64(71776119061217280)));
auto tmp33 = genTemporary(BCType(BCTypeEnum.i32));//SP[200]
            Le3(tmp33, BCValue(Imm32(40)), BCValue(Imm32(63)));
auto tmp34 = genTemporary(BCType(BCTypeEnum.i32));//SP[204]
            Set(tmp34, BCValue(Imm32(40)));
auto tmp35 = genTemporary(BCType(BCTypeEnum.i32));//SP[208]
            Set(tmp35, BCValue(Imm32(63)));
Assert(tmp33, Imm32(7) /*"shift by %d is outside the range 0..%d", BCValue(Imm32(40)), BCValue(Imm32(63))*/;);
            Rsh3(tmp31, tmp32, BCValue(Imm32(40)));
            Or3(result_1, result_1, tmp31);
            Line(13);
auto tmp36 = genTemporary(BCType(BCTypeEnum.i64));//SP[212] auto tmp37 = genTemporary(BCType(BCTypeEnum.i64));//SP[220] And3(tmp37, val_1, BCValue(Imm64(18374686479671623680))); auto tmp38 = genTemporary(BCType(BCTypeEnum.i32));//SP[228]
            Le3(tmp38, BCValue(Imm32(56)), BCValue(Imm32(63)));
auto tmp39 = genTemporary(BCType(BCTypeEnum.i32));//SP[232]
            Set(tmp39, BCValue(Imm32(56)));
auto tmp40 = genTemporary(BCType(BCTypeEnum.i32));//SP[236]
            Set(tmp40, BCValue(Imm32(63)));
Assert(tmp38, Imm32(8) /*"shift by %d is outside the range 0..%d", BCValue(Imm32(56)), BCValue(Imm32(63))*/;);
            Rsh3(tmp36, tmp37, BCValue(Imm32(56)));
            Or3(result_1, result_1, tmp36);
            Line(26);
            Ret(result_1);
            Line(27);
        endFunction();

        Line(28);
    Finalize();

So what is going wrong here ?

The 4 lines responsible for the lower 32bit of the result
have immediate and-instructions with constants larger then 32 bits.
like : And3(tmp37, val_1, BCValue(Imm64(18374686479671623680)));
which will cause the bytecode-interpreter to the immediate-bytecode instruction And tmp37, (immvalue & 0xFFFF_FFFF) Which in this case will become And tmp37, #0 (since the lower bits of 18374686479671623680 are zero)

This is now fixed by pushing 64bit value into a register and issuing a reg-reg instruction.

So, you see, there is never a boring day in newCTFE-land :)

Cheers, Stefan

Reply via email to