Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Primitives] Fix slice primitives #1139

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions docs/primitives.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,23 +249,26 @@ Slice function interfaces:
* width: constant slice width


### set_bit
### set_index
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be in favor of renaming the function (publicly, i.e. in the docs) to set_bit. We could deprecate set_index for now with warning (doubt anyone is using it anyway...)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was changed to set_index because the pattern is more general than just set_bit (i.e. you can use it on generic arrays, rather than just on Bits), so I think it makes more sense to keep it as set_index for generality

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. In that case, why do we need a separate function? I.e. why is it not covered by set slice with width 1?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simpler to use when you know you're only interested in one index. For the same reasons in Python we have x[1] versus having to do x[1:2].

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense -- but I would argue x[1] and x[1:2] is the same interface with different arguments (in fact it literally is the function __getitem__).

Maybe we don't need to do this in this change, but seems reasonable to refactor to have the following interface:

"""
* target: Array[N, T]
* value: Union[Array[M, T], T]
* start: UInt[W]

where M < N and W <= clog2(N)
"""
def set(target: Array, value: Union[Type, Array], start: UInt):
    ...

Now that I think about it there are few new concerns here:

  • Should this function work with all Arrays and not just Bits? I kind of assumed it did, but looking at the code closer I'm not certain.
  • Do we need a width argument? Can it just be inferred from value? If value is an array of the same dimensionality as target then it is a slice set; else if it is of dimensionality one less than value then it is an index set (of course assuming the contained types match up and all).
  • In the case start being a constant value, should we optimize for the simple wiring (non-dynamic mux) case?

Similar to set_slice/get_slice, this function allows you to dynamically set the
value of a bit in a Bits value. Here's an example:
value of one index in an Array. Here's an example:

```python
class SetBit(m.Circuit):
io = m.IO(I=m.In(m.Bits[4]),
val=m.In(m.Bit),
idx=m.In(m.Bits[2]),
O=m.Out(m.Bits[4]))
io.O @= m.set_bit(io.I, io.val, io.idx)
io.O @= m.set_index(io.I, io.val, io.idx)
```

Interface:
```python
def set_bit(target: Bits, value: Bit, idx: UInt):
def set_index(target: Array, value, idx: UInt):
"""
Returns a new value where index `idx` of value `target` is set to `value`
* `target` - a value of type `Array[N, T]`
* `value` - a value of type `T`
* `idx` - a value of type `UInt[clog2(N)]`
"""
```
24 changes: 17 additions & 7 deletions magma/primitives/slice.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Union

from magma.bit import Bit
from magma.bits import Bits, UInt
from magma.bitutils import clog2
Expand Down Expand Up @@ -40,15 +42,18 @@ def slice(*args, **kwargs):
return get_slice(*args, **kwargs)


def set_slice(target: Bits, value: Bits, start: UInt, width: int):
def set_slice(target: Bits, value: Bits, start: Union[UInt, int], width: int):
"""
target: the output with a dynamic slice range replaced by value
value: the output driving a slice of target
start: dynamic start index of the slice
width: constant slice width
"""
if not isinstance(start, UInt):
raise TypeError("start should be a UInt")
if not isinstance(start, (UInt, int)):
raise TypeError("start should be a UInt or int")
if isinstance(start, int):
start = uint(start)

T = magma_type(type(target))
output = T.qualify(Direction.Undirected)()
orig_start_len = len(start)
Expand All @@ -61,8 +66,13 @@ def set_slice(target: Bits, value: Bits, start: UInt, width: int):
in_slice_range &= start <= i
if i > 0:
in_slice_range &= i <= (start + width - 1)
value_idx = (uint(i, clog2(len(target))) - start)[:clog2(len(value))]
if len(value_idx) == 1:
value_idx = value_idx[0]
output[i] @= in_slice_range.ite(value[value_idx], target[i])
if width == 1:
curr_value = value[0]
else:
value_idx = uint(i, clog2(len(target))) - start
value_idx = value_idx[:clog2(len(value))]
if len(value_idx) == 1:
value_idx = value_idx[0]
curr_value = value[value_idx]
output[i] @= in_slice_range.ite(curr_value, target[i])
return output
296 changes: 296 additions & 0 deletions tests/test_operators/gold/TestSetSliceInt.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
hw.module @TestSetSliceInt(%I: i6) -> (O: i12) {
%0 = hw.constant 1 : i1
%1 = hw.constant 0 : i4
%2 = hw.constant 2 : i4
%3 = comb.sub %1, %2 : i4
%4 = comb.extract %3 from 0 : (i4) -> i1
%5 = comb.extract %3 from 1 : (i4) -> i1
%6 = comb.extract %3 from 2 : (i4) -> i1
%7 = hw.constant 0 : i1
%8 = hw.constant 0 : i1
%9 = hw.constant 0 : i1
%10 = comb.concat %9, %8, %7, %6, %5, %4 : i1, i1, i1, i1, i1, i1
%11 = comb.shru %I, %10 : i6
%12 = comb.extract %11 from 0 : (i6) -> i1
%13 = hw.constant 1 : i1
%14 = hw.constant 2 : i4
%15 = hw.constant 0 : i4
%16 = comb.icmp ule %14, %15 : i4
%17 = comb.and %13, %16 : i1
%19 = hw.array_create %12, %0 : i1
%18 = hw.array_get %19[%17] : !hw.array<2xi1>
%20 = hw.constant 1 : i1
%21 = hw.constant 1 : i4
%22 = hw.constant 2 : i4
%23 = comb.sub %21, %22 : i4
%24 = comb.extract %23 from 0 : (i4) -> i1
%25 = comb.extract %23 from 1 : (i4) -> i1
%26 = comb.extract %23 from 2 : (i4) -> i1
%27 = hw.constant 0 : i1
%28 = hw.constant 0 : i1
%29 = hw.constant 0 : i1
%30 = comb.concat %29, %28, %27, %26, %25, %24 : i1, i1, i1, i1, i1, i1
%31 = comb.shru %I, %30 : i6
%32 = comb.extract %31 from 0 : (i6) -> i1
%33 = hw.constant 1 : i1
%34 = hw.constant 2 : i4
%35 = hw.constant 1 : i4
%36 = comb.icmp ule %34, %35 : i4
%37 = comb.and %33, %36 : i1
%38 = hw.constant 2 : i4
%39 = hw.constant 6 : i4
%40 = comb.add %38, %39 : i4
%41 = hw.constant 1 : i4
%42 = comb.sub %40, %41 : i4
%43 = hw.constant 1 : i4
%44 = comb.icmp uge %42, %43 : i4
%45 = comb.and %37, %44 : i1
%47 = hw.array_create %32, %20 : i1
%46 = hw.array_get %47[%45] : !hw.array<2xi1>
%48 = hw.constant 1 : i1
%49 = hw.constant 2 : i4
%50 = hw.constant 2 : i4
%51 = comb.sub %49, %50 : i4
%52 = comb.extract %51 from 0 : (i4) -> i1
%53 = comb.extract %51 from 1 : (i4) -> i1
%54 = comb.extract %51 from 2 : (i4) -> i1
%55 = hw.constant 0 : i1
%56 = hw.constant 0 : i1
%57 = hw.constant 0 : i1
%58 = comb.concat %57, %56, %55, %54, %53, %52 : i1, i1, i1, i1, i1, i1
%59 = comb.shru %I, %58 : i6
%60 = comb.extract %59 from 0 : (i6) -> i1
%61 = hw.constant 1 : i1
%62 = hw.constant 2 : i4
%63 = hw.constant 2 : i4
%64 = comb.icmp ule %62, %63 : i4
%65 = comb.and %61, %64 : i1
%66 = hw.constant 2 : i4
%67 = hw.constant 6 : i4
%68 = comb.add %66, %67 : i4
%69 = hw.constant 1 : i4
%70 = comb.sub %68, %69 : i4
%71 = hw.constant 2 : i4
%72 = comb.icmp uge %70, %71 : i4
%73 = comb.and %65, %72 : i1
%75 = hw.array_create %60, %48 : i1
%74 = hw.array_get %75[%73] : !hw.array<2xi1>
%76 = hw.constant 1 : i1
%77 = hw.constant 3 : i4
%78 = hw.constant 2 : i4
%79 = comb.sub %77, %78 : i4
%80 = comb.extract %79 from 0 : (i4) -> i1
%81 = comb.extract %79 from 1 : (i4) -> i1
%82 = comb.extract %79 from 2 : (i4) -> i1
%83 = hw.constant 0 : i1
%84 = hw.constant 0 : i1
%85 = hw.constant 0 : i1
%86 = comb.concat %85, %84, %83, %82, %81, %80 : i1, i1, i1, i1, i1, i1
%87 = comb.shru %I, %86 : i6
%88 = comb.extract %87 from 0 : (i6) -> i1
%89 = hw.constant 1 : i1
%90 = hw.constant 2 : i4
%91 = hw.constant 6 : i4
%92 = comb.add %90, %91 : i4
%93 = hw.constant 1 : i4
%94 = comb.sub %92, %93 : i4
%95 = hw.constant 3 : i4
%96 = comb.icmp uge %94, %95 : i4
%97 = comb.and %89, %96 : i1
%99 = hw.array_create %88, %76 : i1
%98 = hw.array_get %99[%97] : !hw.array<2xi1>
%100 = hw.constant 1 : i1
%101 = hw.constant 4 : i4
%102 = hw.constant 2 : i4
%103 = comb.sub %101, %102 : i4
%104 = comb.extract %103 from 0 : (i4) -> i1
%105 = comb.extract %103 from 1 : (i4) -> i1
%106 = comb.extract %103 from 2 : (i4) -> i1
%107 = hw.constant 0 : i1
%108 = hw.constant 0 : i1
%109 = hw.constant 0 : i1
%110 = comb.concat %109, %108, %107, %106, %105, %104 : i1, i1, i1, i1, i1, i1
%111 = comb.shru %I, %110 : i6
%112 = comb.extract %111 from 0 : (i6) -> i1
%113 = hw.constant 1 : i1
%114 = hw.constant 2 : i4
%115 = hw.constant 6 : i4
%116 = comb.add %114, %115 : i4
%117 = hw.constant 1 : i4
%118 = comb.sub %116, %117 : i4
%119 = hw.constant 4 : i4
%120 = comb.icmp uge %118, %119 : i4
%121 = comb.and %113, %120 : i1
%123 = hw.array_create %112, %100 : i1
%122 = hw.array_get %123[%121] : !hw.array<2xi1>
%124 = hw.constant 1 : i1
%125 = hw.constant 5 : i4
%126 = hw.constant 2 : i4
%127 = comb.sub %125, %126 : i4
%128 = comb.extract %127 from 0 : (i4) -> i1
%129 = comb.extract %127 from 1 : (i4) -> i1
%130 = comb.extract %127 from 2 : (i4) -> i1
%131 = hw.constant 0 : i1
%132 = hw.constant 0 : i1
%133 = hw.constant 0 : i1
%134 = comb.concat %133, %132, %131, %130, %129, %128 : i1, i1, i1, i1, i1, i1
%135 = comb.shru %I, %134 : i6
%136 = comb.extract %135 from 0 : (i6) -> i1
%137 = hw.constant 1 : i1
%138 = hw.constant 2 : i4
%139 = hw.constant 6 : i4
%140 = comb.add %138, %139 : i4
%141 = hw.constant 1 : i4
%142 = comb.sub %140, %141 : i4
%143 = hw.constant 5 : i4
%144 = comb.icmp uge %142, %143 : i4
%145 = comb.and %137, %144 : i1
%147 = hw.array_create %136, %124 : i1
%146 = hw.array_get %147[%145] : !hw.array<2xi1>
%148 = hw.constant 1 : i1
%149 = hw.constant 6 : i4
%150 = hw.constant 2 : i4
%151 = comb.sub %149, %150 : i4
%152 = comb.extract %151 from 0 : (i4) -> i1
%153 = comb.extract %151 from 1 : (i4) -> i1
%154 = comb.extract %151 from 2 : (i4) -> i1
%155 = hw.constant 0 : i1
%156 = hw.constant 0 : i1
%157 = hw.constant 0 : i1
%158 = comb.concat %157, %156, %155, %154, %153, %152 : i1, i1, i1, i1, i1, i1
%159 = comb.shru %I, %158 : i6
%160 = comb.extract %159 from 0 : (i6) -> i1
%161 = hw.constant 1 : i1
%162 = hw.constant 2 : i4
%163 = hw.constant 6 : i4
%164 = comb.add %162, %163 : i4
%165 = hw.constant 1 : i4
%166 = comb.sub %164, %165 : i4
%167 = hw.constant 6 : i4
%168 = comb.icmp uge %166, %167 : i4
%169 = comb.and %161, %168 : i1
%171 = hw.array_create %160, %148 : i1
%170 = hw.array_get %171[%169] : !hw.array<2xi1>
%172 = hw.constant 1 : i1
%173 = hw.constant 7 : i4
%174 = hw.constant 2 : i4
%175 = comb.sub %173, %174 : i4
%176 = comb.extract %175 from 0 : (i4) -> i1
%177 = comb.extract %175 from 1 : (i4) -> i1
%178 = comb.extract %175 from 2 : (i4) -> i1
%179 = hw.constant 0 : i1
%180 = hw.constant 0 : i1
%181 = hw.constant 0 : i1
%182 = comb.concat %181, %180, %179, %178, %177, %176 : i1, i1, i1, i1, i1, i1
%183 = comb.shru %I, %182 : i6
%184 = comb.extract %183 from 0 : (i6) -> i1
%185 = hw.constant 1 : i1
%186 = hw.constant 2 : i4
%187 = hw.constant 6 : i4
%188 = comb.add %186, %187 : i4
%189 = hw.constant 1 : i4
%190 = comb.sub %188, %189 : i4
%191 = hw.constant 7 : i4
%192 = comb.icmp uge %190, %191 : i4
%193 = comb.and %185, %192 : i1
%195 = hw.array_create %184, %172 : i1
%194 = hw.array_get %195[%193] : !hw.array<2xi1>
%196 = hw.constant 1 : i1
%197 = hw.constant 8 : i4
%198 = hw.constant 2 : i4
%199 = comb.sub %197, %198 : i4
%200 = comb.extract %199 from 0 : (i4) -> i1
%201 = comb.extract %199 from 1 : (i4) -> i1
%202 = comb.extract %199 from 2 : (i4) -> i1
%203 = hw.constant 0 : i1
%204 = hw.constant 0 : i1
%205 = hw.constant 0 : i1
%206 = comb.concat %205, %204, %203, %202, %201, %200 : i1, i1, i1, i1, i1, i1
%207 = comb.shru %I, %206 : i6
%208 = comb.extract %207 from 0 : (i6) -> i1
%209 = hw.constant 1 : i1
%210 = hw.constant 2 : i4
%211 = hw.constant 6 : i4
%212 = comb.add %210, %211 : i4
%213 = hw.constant 1 : i4
%214 = comb.sub %212, %213 : i4
%215 = hw.constant 8 : i4
%216 = comb.icmp uge %214, %215 : i4
%217 = comb.and %209, %216 : i1
%219 = hw.array_create %208, %196 : i1
%218 = hw.array_get %219[%217] : !hw.array<2xi1>
%220 = hw.constant 1 : i1
%221 = hw.constant 9 : i4
%222 = hw.constant 2 : i4
%223 = comb.sub %221, %222 : i4
%224 = comb.extract %223 from 0 : (i4) -> i1
%225 = comb.extract %223 from 1 : (i4) -> i1
%226 = comb.extract %223 from 2 : (i4) -> i1
%227 = hw.constant 0 : i1
%228 = hw.constant 0 : i1
%229 = hw.constant 0 : i1
%230 = comb.concat %229, %228, %227, %226, %225, %224 : i1, i1, i1, i1, i1, i1
%231 = comb.shru %I, %230 : i6
%232 = comb.extract %231 from 0 : (i6) -> i1
%233 = hw.constant 1 : i1
%234 = hw.constant 2 : i4
%235 = hw.constant 6 : i4
%236 = comb.add %234, %235 : i4
%237 = hw.constant 1 : i4
%238 = comb.sub %236, %237 : i4
%239 = hw.constant 9 : i4
%240 = comb.icmp uge %238, %239 : i4
%241 = comb.and %233, %240 : i1
%243 = hw.array_create %232, %220 : i1
%242 = hw.array_get %243[%241] : !hw.array<2xi1>
%244 = hw.constant 1 : i1
%245 = hw.constant 10 : i4
%246 = hw.constant 2 : i4
%247 = comb.sub %245, %246 : i4
%248 = comb.extract %247 from 0 : (i4) -> i1
%249 = comb.extract %247 from 1 : (i4) -> i1
%250 = comb.extract %247 from 2 : (i4) -> i1
%251 = hw.constant 0 : i1
%252 = hw.constant 0 : i1
%253 = hw.constant 0 : i1
%254 = comb.concat %253, %252, %251, %250, %249, %248 : i1, i1, i1, i1, i1, i1
%255 = comb.shru %I, %254 : i6
%256 = comb.extract %255 from 0 : (i6) -> i1
%257 = hw.constant 1 : i1
%258 = hw.constant 2 : i4
%259 = hw.constant 6 : i4
%260 = comb.add %258, %259 : i4
%261 = hw.constant 1 : i4
%262 = comb.sub %260, %261 : i4
%263 = hw.constant 10 : i4
%264 = comb.icmp uge %262, %263 : i4
%265 = comb.and %257, %264 : i1
%267 = hw.array_create %256, %244 : i1
%266 = hw.array_get %267[%265] : !hw.array<2xi1>
%268 = hw.constant 1 : i1
%269 = hw.constant 11 : i4
%270 = hw.constant 2 : i4
%271 = comb.sub %269, %270 : i4
%272 = comb.extract %271 from 0 : (i4) -> i1
%273 = comb.extract %271 from 1 : (i4) -> i1
%274 = comb.extract %271 from 2 : (i4) -> i1
%275 = hw.constant 0 : i1
%276 = hw.constant 0 : i1
%277 = hw.constant 0 : i1
%278 = comb.concat %277, %276, %275, %274, %273, %272 : i1, i1, i1, i1, i1, i1
%279 = comb.shru %I, %278 : i6
%280 = comb.extract %279 from 0 : (i6) -> i1
%281 = hw.constant 1 : i1
%282 = hw.constant 2 : i4
%283 = hw.constant 6 : i4
%284 = comb.add %282, %283 : i4
%285 = hw.constant 1 : i4
%286 = comb.sub %284, %285 : i4
%287 = hw.constant 11 : i4
%288 = comb.icmp uge %286, %287 : i4
%289 = comb.and %281, %288 : i1
%291 = hw.array_create %280, %268 : i1
%290 = hw.array_get %291[%289] : !hw.array<2xi1>
%292 = comb.concat %290, %266, %242, %218, %194, %170, %146, %122, %98, %74, %46, %18 : i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1
hw.output %292 : i12
}
Loading