summaryrefslogtreecommitdiffstats
path: root/libs/wpewebkit/patches/139-JavaScriptCore-offlineasm-RISCV64-vregs-bitext.patch
blob: 0756aaf324f3a96b7b02828e903140a7d3e6ffe8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
--- a/Source/JavaScriptCore/offlineasm/riscv64.rb
+++ b/Source/JavaScriptCore/offlineasm/riscv64.rb
@@ -122,6 +122,12 @@ def riscv64OperandTypes(operands)
             else
                 raise "Invalid Tmp operand #{op.kind}"
             end
+        elsif op.is_a? VecRegisterID
+            # Vector registers are aliased to single FPRs on RISC-V (no V
+            # extension); treat them as FPRegisterID for validation so the
+            # existing [Address, FPRegisterID] / [FPRegisterID, Address]
+            # patterns match loadv/storev/pushv/popv operands.
+            FPRegisterID
         else
             op.class
         end
@@ -273,6 +279,40 @@ class FPRegisterID
     end
 end
 
+class VecRegisterID
+    # Pseudo-vector registers v0..v7 (and lane variants) for the IPInt
+    # interpreter, which stores every wasm operand-stack value in a
+    # 16-byte slot regardless of type. RISC-V baseline rv64gc has no V
+    # extension and no 128-bit register, so each v-reg is aliased to a
+    # single 64-bit FPR (the low half of the slot); pushv/popv/loadv/
+    # storev below operate on 16-byte slots but only move 8 bytes of
+    # payload. Safe because wasm SIMD is gated off at runtime
+    # (Options::useWasmSIMD = false on RISCV64) so the upper 8 bytes
+    # are pure padding.
+    def riscv64Operand
+        case @name
+        when 'v0', 'v0_b', 'v0_h', 'v0_i', 'v0_q'
+            'f0'
+        when 'v1', 'v1_b', 'v1_h', 'v1_i', 'v1_q'
+            'f1'
+        when 'v2', 'v2_b', 'v2_h', 'v2_i', 'v2_q'
+            'f2'
+        when 'v3', 'v3_b', 'v3_h', 'v3_i', 'v3_q'
+            'f3'
+        when 'v4', 'v4_b', 'v4_h', 'v4_i', 'v4_q'
+            'f4'
+        when 'v5', 'v5_b', 'v5_h', 'v5_i', 'v5_q'
+            'f5'
+        when 'v6', 'v6_b', 'v6_h', 'v6_i', 'v6_q'
+            'f6'
+        when 'v7', 'v7_b', 'v7_h', 'v7_i', 'v7_q'
+            'f7'
+        else
+            raise "Bad vector register name #{@name} at #{codeOriginString}"
+        end
+    end
+end
+
 class SpecialRegister
     def riscv64Operand
         @name
@@ -651,6 +691,43 @@ def riscv64LowerOperation(list)
         newList << Instruction.new(node.codeOrigin, "rv_addi", [sp, Immediate.new(node.codeOrigin, size), sp])
     end
 
+    # pushv / popv reserve 16 bytes per operand because the IPInt wasm
+    # operand stack uses 16-byte slots uniformly. RISC-V baseline rv64gc
+    # has no V extension, so each v-reg is aliased to a single 64-bit FPR;
+    # only the low 8 bytes are written/read, the upper 8 bytes are pure
+    # padding (wasm SIMD is disabled at runtime on this arch).
+    def emitPushv(newList, node)
+        sp = RegisterID.forName(node.codeOrigin, 'sp')
+        size = 16 * node.operands.size
+        newList << Instruction.new(node.codeOrigin, "rv_addi", [sp, Immediate.new(node.codeOrigin, -size), sp])
+        node.operands.reverse.each_with_index {
+            | op, index |
+            offset = size - 16 * (index + 1)
+            newList << Instruction.new(node.codeOrigin, "rv_fsd", [op, Address.new(node.codeOrigin, sp, Immediate.new(node.codeOrigin, offset))])
+        }
+    end
+
+    def emitPopv(newList, node)
+        sp = RegisterID.forName(node.codeOrigin, 'sp')
+        size = 16 * node.operands.size
+        node.operands.each_with_index {
+            | op, index |
+            offset = size - 16 * (index + 1)
+            newList << Instruction.new(node.codeOrigin, "rv_fld", [Address.new(node.codeOrigin, sp, Immediate.new(node.codeOrigin, offset)), op])
+        }
+        newList << Instruction.new(node.codeOrigin, "rv_addi", [sp, Immediate.new(node.codeOrigin, size), sp])
+    end
+
+    def emitLoadv(newList, node)
+        riscv64ValidateOperands(node.operands, [Address, FPRegisterID])
+        newList << Instruction.new(node.codeOrigin, "rv_fld", node.operands)
+    end
+
+    def emitStorev(newList, node)
+        riscv64ValidateOperands(node.operands, [FPRegisterID, Address])
+        newList << Instruction.new(node.codeOrigin, "rv_fsd", node.operands)
+    end
+
     def emitAdditionOperation(newList, node, operation, size)
         operands = node.operands
         if operands.size == 2
@@ -790,38 +867,56 @@ def riscv64LowerOperation(list)
     def emitBitExtensionOperation(newList, node, extension, fromSize, toSize)
         raise "Invalid operand types" unless riscv64OperandTypes(node.operands) == [RegisterID, RegisterID]
 
-        if [[:s, :i, :p], [:s, :i, :q]].include? [extension, fromSize, toSize]
-            newList << Instruction.new(node.codeOrigin, "rv_sext.w", node.operands)
-            return
-        end
-
         source = node.operands[0]
         dest = node.operands[1]
 
-        if [[:z, :i, :p], [:z, :i, :q]].include? [extension, fromSize, toSize]
+        # On RISC-V :p (pointer) is the same width as :q (64-bit).
+        targetSize = (toSize == :p) ? :q : toSize
+
+        case [extension, fromSize, targetSize]
+        when [:s, :i, :q]
+            newList << Instruction.new(node.codeOrigin, "rv_sext.w", [source, dest])
+            return
+        when [:s, :i, :i]
+            # Already an i32 in canonical RISC-V form (low 32 bits = value,
+            # upper 32 bits = sign-extension of bit 31). sext.w re-normalises
+            # in case the source was produced by a non-canonical sequence.
+            newList << Instruction.new(node.codeOrigin, "rv_sext.w", [source, dest])
+            return
+        when [:z, :i, :q]
+            newList << Instruction.new(node.codeOrigin, "rv_slli", [source, Immediate.new(node.codeOrigin, 32), dest])
+            newList << Instruction.new(node.codeOrigin, "rv_srli", [dest, Immediate.new(node.codeOrigin, 32), dest])
+            return
+        when [:z, :i, :i]
+            # Lower 32 bits of source already hold the value; clearing the
+            # upper 32 bits gives the :i canonical representation.
             newList << Instruction.new(node.codeOrigin, "rv_slli", [source, Immediate.new(node.codeOrigin, 32), dest])
             newList << Instruction.new(node.codeOrigin, "rv_srli", [dest, Immediate.new(node.codeOrigin, 32), dest])
             return
         end
 
-        raise "Invalid zero extension" unless extension == :s
-        case [fromSize, toSize]
-        when [:b, :i]
+        case [extension, fromSize, targetSize]
+        when [:s, :b, :i]
             newList << Instruction.new(node.codeOrigin, "rv_slli", [source, Immediate.new(node.codeOrigin, 56), dest])
             newList << Instruction.new(node.codeOrigin, "rv_srai", [dest, Immediate.new(node.codeOrigin, 24), dest])
             newList << Instruction.new(node.codeOrigin, "rv_srli", [dest, Immediate.new(node.codeOrigin, 32), dest])
-        when [:b, :q]
+        when [:s, :b, :q]
             newList << Instruction.new(node.codeOrigin, "rv_slli", [source, Immediate.new(node.codeOrigin, 56), dest])
             newList << Instruction.new(node.codeOrigin, "rv_srai", [dest, Immediate.new(node.codeOrigin, 56), dest])
-        when [:h, :i]
+        when [:s, :h, :i]
             newList << Instruction.new(node.codeOrigin, "rv_slli", [source, Immediate.new(node.codeOrigin, 48), dest])
             newList << Instruction.new(node.codeOrigin, "rv_srai", [dest, Immediate.new(node.codeOrigin, 16), dest])
             newList << Instruction.new(node.codeOrigin, "rv_srli", [dest, Immediate.new(node.codeOrigin, 32), dest])
-        when [:h, :q]
+        when [:s, :h, :q]
             newList << Instruction.new(node.codeOrigin, "rv_slli", [source, Immediate.new(node.codeOrigin, 48), dest])
             newList << Instruction.new(node.codeOrigin, "rv_srai", [dest, Immediate.new(node.codeOrigin, 48), dest])
+        when [:z, :b, :i], [:z, :b, :q]
+            newList << Instruction.new(node.codeOrigin, "rv_andi", [source, Immediate.new(node.codeOrigin, 0xff), dest])
+        when [:z, :h, :i], [:z, :h, :q]
+            newList << Instruction.new(node.codeOrigin, "rv_slli", [source, Immediate.new(node.codeOrigin, 48), dest])
+            newList << Instruction.new(node.codeOrigin, "rv_srli", [dest, Immediate.new(node.codeOrigin, 48), dest])
         else
-            raise "Invalid bit-extension combination"
+            raise "Invalid bit-extension combination #{[extension, fromSize, toSize]}"
         end
     end
 
@@ -882,6 +977,14 @@ def riscv64LowerOperation(list)
                 emitPush(newList, node)
             when "pop"
                 emitPop(newList, node)
+            when "pushv"
+                emitPushv(newList, node)
+            when "popv"
+                emitPopv(newList, node)
+            when "loadv"
+                emitLoadv(newList, node)
+            when "storev"
+                emitStorev(newList, node)
             when /^(add|sub)(i|p|q)$/
                 emitAdditionOperation(newList, node, $1.to_sym, $2.to_sym)
             when /^(mul|div|rem)(i|p|q)(s?)$/
@@ -1543,8 +1646,7 @@ def riscv64GenerateWASMPlaceholders(list
         if node.is_a? Instruction
             case node.opcode
             when "loadlinkacqb", "loadlinkacqh", "loadlinkacqi", "loadlinkacqq",
-                 "storecondrelb", "storecondrelh", "storecondreli", "storecondrelq",
-                 "loadv", "storev"
+                 "storecondrelb", "storecondrelh", "storecondreli", "storecondrelq"
                 newList << Instruction.new(node.codeOrigin, "rv_ebreak", [], "WebAssembly placeholder for opcode #{node.opcode}")
             else
                 newList << node
@@ -1570,6 +1672,7 @@ class Sequence
                 false
             end
         }
+        result = riscLowerMalformedAddressesDouble(result)
         result = riscv64LowerMisplacedAddresses(result)
         result = riscLowerMisplacedAddresses(result)
         result = riscv64LowerAddressLoads(result)