You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: documentation/advanced-usage.md
+52-9
Original file line number
Diff line number
Diff line change
@@ -33,22 +33,65 @@ Notice that the second operand of `'ldr#` is `'reg-sp`.
33
33
34
34
<aname="vector"></a>
35
35
### Vector Instructions
36
-
Typically, when define a program state element is a primitive entity with the same number of bits as the define bitwidth ([Step 1.1 of Extending GreenThumb to a New ISA](new-isa.md#step1.1)). In this section, we describe how to define a program state element as a collection of primitive entities. For example, we will define a program state element type `vec4` to be a vector of four primitive entities. To do so, we simply pass an additional argument when calling `define-progstate-type` ([Step 1.3 of Extending GreenThumb to a New ISA](new-isa.md#step1.1)) as follows:
36
+
Typically, we define a program state element as a primitive entity with the same number of bits as the defined bitwidth ([Step 1.1 of Extending GreenThumb to a New ISA](new-isa.md#step1.1)). In this section, we describe how to define a program state element as a collection of primitive entities. For example, we will define a program state element type `vec4`(vector register with 4 lanes) to be a vector of 4 primitive entities. To do so, we simply pass an additional argument`#:structure` when calling `define-progstate-type` ([Step 1.3 of Extending GreenThumb to a New ISA](new-isa.md#step1.1)) as follows:
37
37
```
38
38
(define-progstate-type
39
39
'vec4
40
-
#:structure (for/vector ([i 4]) 'x) ;; a vector contains 4 primitive elements
The expression passed to `#:structure` should evaluate to a collection of `'x` where `'x` represents a primitive entity.
44
+
The expression passed to `#:structure` should evaluate to a collection of `'x`, where `'x` represents a primitive entity.
45
45
46
-
TODO:
47
-
- define-instruction-class
48
-
- #:scalar (groups-of-opcodes = 1 only)
49
-
- backward if no scalar
50
-
- const-vec4
51
-
- see llvm as an example
46
+
Now we can define an intruction class for vector add `vadd` and vector multiply `vmul` as follows:
47
+
```
48
+
(define-instruction-class
49
+
'rrr-commute-vec4
50
+
'(vadd vmul)
51
+
#:scalar '(add mul) #:vector-width 4
52
+
#:args '(vec4 vec4 vec4)
53
+
#:ins '(1 2) #:outs '(0) #:commute '(1 . 2))
54
+
```
55
+
This is similar to defining instruction classes for scalar instructions except the additional arguments `#:scalar` and `#:vector-width`. When defining vector instructions, we have to inform GreenThumb their corresponding scalar version and vector width. If developers do not provide such information, the backward search part of the enumerative will not work. If a vector instruction has no corresponding scalar instruction, developers must create a fake scalar instruction, and set the cost of such instruction to be very high to prevent the superoptimizer from using it to synthesize output programs.
56
+
57
+
**Important note:** This vector support only works when there is one opcode per instruction (i.e. `(init-machine-description 1)`). If there are more than one opcodes per instruction, please contact [email protected]
58
+
59
+
##### Vector Constants
60
+
A scalar instruction may contain constants, while a vector instruction may contain vector constants. Therefore, we may need another type of instruction operand type. For example, in LLVM, we can add a vector variable to a vector of ones: `%out = add <4 x i32> %in, <i32 1, i32 1, i32 1, i32 1>`. In this case, we define an operand type for vector constants as:
61
+
```
62
+
(define-arg-type 'const-vec4
63
+
(lambda (config) (list (vector 0 0 0 0)
64
+
(vector 1 1 1 1))))
65
+
```
66
+
Recall that the stochastic search and enumerative search will try to construct instructions from the values from this list, but the symbolic search is not.
67
+
68
+
##### Instruction Skeleton (For Symbolic Search)
69
+
Typically, the framework automatically infers an instruction skeleton from the defined instruction classes by treating all instruction operands to be primitive numbers. However, vector instructions may contain non-primitive numbers as operands, such as vector constants; a register/variable (either scalar or vector) is considered to be a primitive number because we use a single ID which is a number to represent a register/variable. Becase of vector constants, we have to manually provide the instruction skeleton by overriding the method `(gen-sym-inst)` of the class `symbolic%`. The skeleton can be constructed by using the provided lambda functions `sym-op` and `sym-arg`. The framework expects a program skeleton to be an `inst` with `(sym-op)` as its opcode and `(sym-arg)` as its arguments.
70
+
71
+
For example, the default `(gen-sym-inst)` for scalar instructions may look like:
72
+
```
73
+
(define/override (gen-sym-inst)
74
+
(define n (get-field max-number-of-args machine))
75
+
(inst (sym-op)
76
+
(for/vector ([i n]) (sym-arg))))
77
+
```
78
+
However, `(sym-arg)` represents a privitive number. Since we know that the first operand cannot be is always a register/variable (either scalar or vector), vector constants cannot be the first operand. Therefore, we define the first entry of operands (or arguments) to be `(sym-arg)` as before, but the rest are `(sym-arg-vec)`; we define `(sym-arg-vec)` to either be `(sym-arg)` or a vector of four `(sym-arg)`s.
79
+
```
80
+
(define/override (gen-sym-inst)
81
+
(define n (get-field max-number-of-args machine))
82
+
(inst (sym-op)
83
+
(vector-append (vector (sym-arg))
84
+
(for/vector ([i (sub1 n)]) (sym-arg-vec)))))
85
+
86
+
(define (sym-arg-vec) ;; either sym-arg or 4 x sym-arg
Our LLVM IR superoptimizer supports a few vector instructions. See `llvm/llvm-machine.rkt` on how to define vector instructions and `llvm/llvm-symbolic.rkt` on how to define the instruction skeleton.
0 commit comments