xls icon indicating copy to clipboard operation
xls copied to clipboard

[enhancement] Treat for-loop iterator value as constant when iteration over constant values

Open rw1nkler opened this issue 10 months ago • 2 comments

What's hard to do? (limit 100 words)

As for today, the value of DSLX for-loop iterator is not treated as constant when iterating over constant values. Having the ability to use the for-loop iterator in this way can improve the expressiveness of the language. In all these cases, when iterating over constant values it should be possible to unroll the for-loop.

These small examples show the current limitations of the language:


let data = u64:0x00_11_22_33_44_55_66_77;
for (i, ()) in s32:0..s32:8 {
    // works if rewritten with width slices
    let slice = data[(i * s32:8) : (i + s32:1) * s32:8];
    trace_fmt!("slice is {}", slice);
}(());

// for (i, ()) in s32:0..s32:8 {
//     let slice = data[(i * s32:8) : (i + s32:1) * s32:8];
// ~~~~~~~~~~~~~~~~~~~~~~~~^ TypeInferenceError: Unable to resolve slice start to a compile-time constant.

// the unrolled version works
let slice = data[(s32:0 * s32:8) : (s32:0 + s32:1) * s32:8];
let slice = data[(s32:1 * s32:8) : (s32:1 + s32:1) * s32:8];
let slice = data[(s32:2 * s32:8) : (s32:2 + s32:1) * s32:8];
//...
let slice = data[(s32:7 * s32:8) : (s32:7 + s32:1) * s32:8];
fn add_const<Y: s32>(x: s32) -> s32 { x + Y }
for (i, acc) in s32:0..s32:8 {
    add_const<i>(acc);
}((u32:3));

// for (i, acc) in s32:0..s32:8 {
//     add_const<i>(acc);
// ~~~~~~~~~~~~~~^ TypeInferenceError: sN[32] Parametric expression `i` was not constexpr -- parametric values must be compile-time constants
  • An example of data concatenation. We tried to use similar logic as a part of a buffering proc. The proc accumulated incoming data in the state and sent back the requested number of bytes of data.
//This data may come from channels
let s = s32:4;
let data1 = u64:0x00_11_22_33_44_55_66_77;
let data2 = u64:0x88_99_AA_BB_CC_DD_EE_FF;

let slice = for (i, slice) in s32:0..s32:8 {
   if (s == i) {
       data1[i * s32:8 : s32:64] ++ data2[0 : i * s32:8]
   } else {
       slice
   }
}(u64:0);
trace_fmt!("slice is {}", slice);

let slice = if  s == s32:0 {data1[s32:0 * s32:8 : s32:64] ++ data2[0 : s32:0 * s32:8]} else {u64:0};
let slice = if  s == s32:1 {data1[s32:1 * s32:8 : s32:64] ++ data2[0 : s32:1 * s32:8]} else {slice};
let slice = if  s == s32:2 {data1[s32:2 * s32:8 : s32:64] ++ data2[0 : s32:2 * s32:8]} else {slice};
let slice = if  s == s32:3 {data1[s32:3 * s32:8 : s32:64] ++ data2[0 : s32:3 * s32:8]} else {slice};
let slice = if  s == s32:4 {data1[s32:4 * s32:8 : s32:64] ++ data2[0 : s32:4 * s32:8]} else {slice};
let slice = if  s == s32:5 {data1[s32:5 * s32:8 : s32:64] ++ data2[0 : s32:5 * s32:8]} else {slice};
let slice = if  s == s32:6 {data1[s32:6 * s32:8 : s32:64] ++ data2[0 : s32:6 * s32:8]} else {slice};
let slice = if  s == s32:7 {data1[s32:7 * s32:8 : s32:64] ++ data2[0 : s32:7 * s32:8]} else {slice};
trace_fmt!("slice: {:#x}", slice);

Current best alternative workaround (limit 100 words)

Unroll the for-loop as in the examples above

Your view of the "best case XLS enhancement" (limit 100 words)

In cases when the for-loop iterates over constant values, the iterator can be treated as a constant and XLS can treat the loop as if it were unrolled

rw1nkler avatar Apr 19 '24 14:04 rw1nkler