blob: 1660da1b3a2732bee5391f6eeb29742c89949f62 [file] [log] [blame]
Ben Clayton96fbe082019-04-16 19:28:11 -04001// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Ben Clayton96fbe082019-04-16 19:28:11 -040015#include "SpirvShader.hpp"
16
Ben Claytonbc1c0672019-12-17 20:37:37 +000017#include "SamplerCore.hpp" // TODO: Figure out what's needed.
18#include "Device/Config.hpp"
Ben Clayton25e06e02020-02-07 11:19:08 +000019#include "System/Debug.hpp"
Ben Clayton96fbe082019-04-16 19:28:11 -040020#include "System/Math.hpp"
Alexis Hetu6448bd62019-06-11 15:58:59 -040021#include "Vulkan/VkDescriptorSetLayout.hpp"
22#include "Vulkan/VkDevice.hpp"
Ben Clayton96fbe082019-04-16 19:28:11 -040023#include "Vulkan/VkImageView.hpp"
24#include "Vulkan/VkSampler.hpp"
Ben Clayton96fbe082019-04-16 19:28:11 -040025
26#include <spirv/unified1/spirv.hpp>
Ben Clayton96fbe082019-04-16 19:28:11 -040027
Alexis Hetu710fcd52019-05-24 17:20:21 -040028#include <climits>
Ben Clayton96fbe082019-04-16 19:28:11 -040029#include <mutex>
30
Ben Clayton96fbe082019-04-16 19:28:11 -040031namespace sw {
32
Chris Forbes45f9a932019-05-08 13:30:38 -070033SpirvShader::ImageSampler *SpirvShader::getImageSampler(uint32_t inst, vk::SampledImageDescriptor const *imageDescriptor, const vk::Sampler *sampler)
Nicolas Capens125dba02019-04-24 02:03:22 -040034{
Nicolas Capensfa7d1362019-05-01 20:26:14 -040035 ImageInstruction instruction(inst);
Nicolas Capensdbd02752019-08-20 10:59:58 -040036 const auto samplerId = sampler ? sampler->id : 0;
37 ASSERT(imageDescriptor->imageViewId != 0 && (samplerId != 0 || instruction.samplerMethod == Fetch));
Nicolas Capens9b83ddb2020-04-06 15:54:03 -040038 ASSERT(imageDescriptor->device);
Nicolas Capensfa7d1362019-05-01 20:26:14 -040039
Ben Claytonbc1c0672019-12-17 20:37:37 +000040 vk::Device::SamplingRoutineCache::Key key = { inst, imageDescriptor->imageViewId, samplerId };
Ben Clayton96fbe082019-04-16 19:28:11 -040041
Ben Claytonbc1c0672019-12-17 20:37:37 +000042 vk::Device::SamplingRoutineCache *cache = imageDescriptor->device->getSamplingRoutineCache();
Alexis Hetu6448bd62019-06-11 15:58:59 -040043
Nicolas Capens1c294772020-03-28 23:04:55 -040044 auto createSamplingRoutine = [&](const vk::Device::SamplingRoutineCache::Key &key) {
45 auto type = imageDescriptor->type;
Ben Clayton96fbe082019-04-16 19:28:11 -040046
Nicolas Capens1c294772020-03-28 23:04:55 -040047 Sampler samplerState = {};
48 samplerState.textureType = type;
49 samplerState.textureFormat = imageDescriptor->format;
Chris Forbes45f9a932019-05-08 13:30:38 -070050
Nicolas Capens1c294772020-03-28 23:04:55 -040051 samplerState.addressingModeU = convertAddressingMode(0, sampler, type);
52 samplerState.addressingModeV = convertAddressingMode(1, sampler, type);
53 samplerState.addressingModeW = convertAddressingMode(2, sampler, type);
54 samplerState.addressingModeY = convertAddressingMode(3, sampler, type);
Nicolas Capens51e9e562019-05-16 14:01:16 -040055
Nicolas Capensdbd02752019-08-20 10:59:58 -040056 samplerState.mipmapFilter = convertMipmapMode(sampler);
Nicolas Capens1c294772020-03-28 23:04:55 -040057 samplerState.swizzle = imageDescriptor->swizzle;
58 samplerState.gatherComponent = instruction.gatherComponent;
Nicolas Capensdbd02752019-08-20 10:59:58 -040059
Nicolas Capens1c294772020-03-28 23:04:55 -040060 if(sampler)
61 {
62 samplerState.textureFilter = (instruction.samplerMethod == Gather) ? FILTER_GATHER : convertFilterMode(sampler);
63 samplerState.border = sampler->borderColor;
Nicolas Capensdbd02752019-08-20 10:59:58 -040064
Nicolas Capens1c294772020-03-28 23:04:55 -040065 samplerState.mipmapFilter = convertMipmapMode(sampler);
Antonio Maioranod9ba4b72020-05-04 14:38:59 -040066 samplerState.highPrecisionFiltering = (sampler->filteringPrecision == VK_SAMPLER_FILTERING_PRECISION_MODE_HIGH_GOOGLE);
Nicolas Capens7f469172020-03-17 17:29:11 -040067
Nicolas Capens1c294772020-03-28 23:04:55 -040068 samplerState.compareEnable = (sampler->compareEnable != VK_FALSE);
69 samplerState.compareOp = sampler->compareOp;
70 samplerState.unnormalizedCoordinates = (sampler->unnormalizedCoordinates != VK_FALSE);
Nicolas Capense2535df2019-05-06 10:37:50 -040071
Nicolas Capens1c294772020-03-28 23:04:55 -040072 samplerState.ycbcrModel = sampler->ycbcrModel;
73 samplerState.studioSwing = sampler->studioSwing;
74 samplerState.swappedChroma = sampler->swappedChroma;
Ben Clayton96fbe082019-04-16 19:28:11 -040075
Nicolas Capens1c294772020-03-28 23:04:55 -040076 samplerState.mipLodBias = sampler->mipLodBias;
77 samplerState.maxAnisotropy = sampler->maxAnisotropy;
78 samplerState.minLod = sampler->minLod;
79 samplerState.maxLod = sampler->maxLod;
80 }
81
82 return emitSamplerRoutine(instruction, samplerState);
83 };
84
85 auto routine = cache->getOrCreate(key, createSamplingRoutine);
86
Ben Claytonbc1c0672019-12-17 20:37:37 +000087 return (ImageSampler *)(routine->getEntry());
Nicolas Capens97da7822019-04-30 17:33:26 -040088}
Nicolas Capens125dba02019-04-24 02:03:22 -040089
Ben Clayton6897e9b2019-07-16 17:27:27 +010090std::shared_ptr<rr::Routine> SpirvShader::emitSamplerRoutine(ImageInstruction instruction, const Sampler &samplerState)
Nicolas Capens97da7822019-04-30 17:33:26 -040091{
92 // TODO(b/129523279): Hold a separate mutex lock for the sampler being built.
Nicolas Capens6c11cf22020-03-19 15:21:13 -040093 rr::Function<Void(Pointer<Byte>, Pointer<SIMD::Float>, Pointer<SIMD::Float>, Pointer<Byte>)> function;
Nicolas Capensa47a5162019-04-24 02:41:27 -040094 {
Nicolas Capens97da7822019-04-30 17:33:26 -040095 Pointer<Byte> texture = function.Arg<0>();
Nicolas Capens6c11cf22020-03-19 15:21:13 -040096 Pointer<SIMD::Float> in = function.Arg<1>();
97 Pointer<SIMD::Float> out = function.Arg<2>();
98 Pointer<Byte> constants = function.Arg<3>();
Nicolas Capensa195abb2019-04-25 17:15:56 -040099
Ben Claytonbc1c0672019-12-17 20:37:37 +0000100 SIMD::Float uvw[4] = { 0, 0, 0, 0 };
Ben Clayton1d6301d2019-06-27 10:35:02 +0100101 SIMD::Float q = 0;
102 SIMD::Float lodOrBias = 0; // Explicit level-of-detail, or bias added to the implicit level-of-detail (depending on samplerMethod).
Ben Claytonbc1c0672019-12-17 20:37:37 +0000103 Vector4f dsx = { 0, 0, 0, 0 };
104 Vector4f dsy = { 0, 0, 0, 0 };
105 Vector4f offset = { 0, 0, 0, 0 };
Alexis Hetu8a6dcf72019-11-26 17:24:42 -0500106 SIMD::Int sampleId = 0;
Nicolas Capens97da7822019-04-30 17:33:26 -0400107 SamplerFunction samplerFunction = instruction.getSamplerFunction();
108
109 uint32_t i = 0;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000110 for(; i < instruction.coordinates; i++)
Nicolas Capens420d9da2019-04-26 17:44:42 -0400111 {
Nicolas Capens97da7822019-04-30 17:33:26 -0400112 uvw[i] = in[i];
Nicolas Capens420d9da2019-04-26 17:44:42 -0400113 }
114
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500115 if(instruction.isDref())
Chris Forbesc71c17f2019-05-04 10:01:04 -0700116 {
117 q = in[i];
118 i++;
119 }
120
Nicolas Capens8ac0bd62019-06-06 13:03:56 -0400121 // TODO(b/134669567): Currently 1D textures are treated as 2D by setting the second coordinate to 0.
Nicolas Capens97da7822019-04-30 17:33:26 -0400122 // Implement optimized 1D sampling.
Chris Forbes3aec8a32019-07-18 11:48:22 -0700123 if(samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D)
Nicolas Capens420d9da2019-04-26 17:44:42 -0400124 {
Nicolas Capens97da7822019-04-30 17:33:26 -0400125 uvw[1] = SIMD::Float(0);
Nicolas Capens022bd572019-04-29 23:45:25 -0400126 }
Chris Forbes3aec8a32019-07-18 11:48:22 -0700127 else if(samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
Nicolas Capense2535df2019-05-06 10:37:50 -0400128 {
129 uvw[1] = SIMD::Float(0);
130 uvw[2] = in[1]; // Move 1D layer coordinate to 2D layer coordinate index.
131 }
Nicolas Capens97da7822019-04-30 17:33:26 -0400132
Chris Forbesf7d78f72019-05-17 16:20:01 -0700133 if(instruction.samplerMethod == Lod || instruction.samplerMethod == Bias || instruction.samplerMethod == Fetch)
Nicolas Capens97da7822019-04-30 17:33:26 -0400134 {
135 lodOrBias = in[i];
136 i++;
137 }
138 else if(instruction.samplerMethod == Grad)
139 {
Nicolas Capens2a25ed82019-06-14 11:26:14 -0400140 for(uint32_t j = 0; j < instruction.grad; j++, i++)
Nicolas Capens97da7822019-04-30 17:33:26 -0400141 {
142 dsx[j] = in[i];
143 }
144
Nicolas Capens2a25ed82019-06-14 11:26:14 -0400145 for(uint32_t j = 0; j < instruction.grad; j++, i++)
Nicolas Capens97da7822019-04-30 17:33:26 -0400146 {
147 dsy[j] = in[i];
148 }
149 }
150
Nicolas Capens2a25ed82019-06-14 11:26:14 -0400151 for(uint32_t j = 0; j < instruction.offset; j++, i++)
Nicolas Capens97da7822019-04-30 17:33:26 -0400152 {
Nicolas Capens2a25ed82019-06-14 11:26:14 -0400153 offset[j] = in[i];
Nicolas Capens97da7822019-04-30 17:33:26 -0400154 }
155
Alexis Hetu8a6dcf72019-11-26 17:24:42 -0500156 if(instruction.sample)
157 {
158 sampleId = As<SIMD::Int>(in[i]);
159 }
Nicolas Capens2a25ed82019-06-14 11:26:14 -0400160
Nicolas Capens977a0a42019-05-16 16:44:05 -0400161 SamplerCore s(constants, samplerState);
Nicolas Capens97da7822019-04-30 17:33:26 -0400162
Nicolas Capens8ac0bd62019-06-06 13:03:56 -0400163 // For explicit-lod instructions the LOD can be different per SIMD lane. SamplerCore currently assumes
164 // a single LOD per four elements, so we sample the image again for each LOD separately.
165 if(samplerFunction.method == Lod || samplerFunction.method == Grad) // TODO(b/133868964): Also handle divergent Bias and Fetch with Lod.
166 {
167 auto lod = Pointer<Float>(&lodOrBias);
168
169 For(Int i = 0, i < SIMD::Width, i++)
170 {
171 SIMD::Float dPdx;
172 SIMD::Float dPdy;
173
174 dPdx.x = Pointer<Float>(&dsx.x)[i];
175 dPdx.y = Pointer<Float>(&dsx.y)[i];
176 dPdx.z = Pointer<Float>(&dsx.z)[i];
177
178 dPdy.x = Pointer<Float>(&dsy.x)[i];
179 dPdy.y = Pointer<Float>(&dsy.y)[i];
180 dPdy.z = Pointer<Float>(&dsy.z)[i];
181
182 // 1D textures are treated as 2D texture with second coordinate 0, so we also need to zero out the second grad component. TODO(b/134669567)
Chris Forbes3aec8a32019-07-18 11:48:22 -0700183 if(samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D || samplerState.textureType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
Nicolas Capens8ac0bd62019-06-06 13:03:56 -0400184 {
185 dPdx.y = Float(0.0f);
186 dPdy.y = Float(0.0f);
187 }
188
Nicolas Capens6c11cf22020-03-19 15:21:13 -0400189 Vector4f sample = s.sampleTexture(texture, uvw, q, lod[i], dPdx, dPdy, offset, sampleId, samplerFunction);
Nicolas Capens8ac0bd62019-06-06 13:03:56 -0400190
191 Pointer<Float> rgba = out;
192 rgba[0 * SIMD::Width + i] = Pointer<Float>(&sample.x)[i];
193 rgba[1 * SIMD::Width + i] = Pointer<Float>(&sample.y)[i];
194 rgba[2 * SIMD::Width + i] = Pointer<Float>(&sample.z)[i];
195 rgba[3 * SIMD::Width + i] = Pointer<Float>(&sample.w)[i];
196 }
197 }
198 else
199 {
Nicolas Capens6c11cf22020-03-19 15:21:13 -0400200 Vector4f sample = s.sampleTexture(texture, uvw, q, lodOrBias.x, (dsx.x), (dsy.x), offset, sampleId, samplerFunction);
Nicolas Capens8ac0bd62019-06-06 13:03:56 -0400201
202 Pointer<SIMD::Float> rgba = out;
203 rgba[0] = sample.x;
204 rgba[1] = sample.y;
205 rgba[2] = sample.z;
206 rgba[3] = sample.w;
207 }
Nicolas Capens022bd572019-04-29 23:45:25 -0400208 }
209
Alexis Hetu6448bd62019-06-11 15:58:59 -0400210 return function("sampler");
Nicolas Capens9e735102019-04-18 15:03:06 -0400211}
212
213sw::FilterType SpirvShader::convertFilterMode(const vk::Sampler *sampler)
214{
Nicolas Capens8fff8c32020-01-22 03:07:14 -0500215 if(sampler->anisotropyEnable != VK_FALSE)
Alexis Hetu21be09d2019-12-17 16:53:53 -0500216 {
217 return FILTER_ANISOTROPIC;
218 }
219
Nicolas Capens9e735102019-04-18 15:03:06 -0400220 switch(sampler->magFilter)
221 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000222 case VK_FILTER_NEAREST:
223 switch(sampler->minFilter)
224 {
225 case VK_FILTER_NEAREST: return FILTER_POINT;
226 case VK_FILTER_LINEAR: return FILTER_MIN_LINEAR_MAG_POINT;
227 default:
Nicolas Capens865f8892020-01-21 14:27:10 -0500228 UNSUPPORTED("minFilter %d", sampler->minFilter);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000229 return FILTER_POINT;
230 }
231 break;
232 case VK_FILTER_LINEAR:
233 switch(sampler->minFilter)
234 {
235 case VK_FILTER_NEAREST: return FILTER_MIN_POINT_MAG_LINEAR;
236 case VK_FILTER_LINEAR: return FILTER_LINEAR;
237 default:
Nicolas Capens865f8892020-01-21 14:27:10 -0500238 UNSUPPORTED("minFilter %d", sampler->minFilter);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000239 return FILTER_POINT;
240 }
241 break;
Nicolas Capens9e735102019-04-18 15:03:06 -0400242 default:
Ben Claytonbc1c0672019-12-17 20:37:37 +0000243 break;
Nicolas Capens9e735102019-04-18 15:03:06 -0400244 }
Ben Clayton8115f1e2019-06-11 16:13:56 +0100245
Nicolas Capens865f8892020-01-21 14:27:10 -0500246 UNSUPPORTED("magFilter %d", sampler->magFilter);
Ben Clayton8115f1e2019-06-11 16:13:56 +0100247 return FILTER_POINT;
Nicolas Capens9e735102019-04-18 15:03:06 -0400248}
249
250sw::MipmapType SpirvShader::convertMipmapMode(const vk::Sampler *sampler)
251{
Nicolas Capensdbd02752019-08-20 10:59:58 -0400252 if(!sampler)
253 {
254 return MIPMAP_POINT; // Samplerless operations (OpImageFetch) can take an integer Lod operand.
255 }
256
Nicolas Capensf948cd12020-03-23 13:00:43 -0400257 if(sampler->ycbcrModel != VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY)
Nicolas Capens51e9e562019-05-16 14:01:16 -0400258 {
Nicolas Capens77b43d62020-03-12 00:20:00 -0400259 // TODO(b/151263485): Check image view level count instead.
260 return MIPMAP_NONE;
Nicolas Capens51e9e562019-05-16 14:01:16 -0400261 }
262
Nicolas Capens9e735102019-04-18 15:03:06 -0400263 switch(sampler->mipmapMode)
264 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000265 case VK_SAMPLER_MIPMAP_MODE_NEAREST: return MIPMAP_POINT;
266 case VK_SAMPLER_MIPMAP_MODE_LINEAR: return MIPMAP_LINEAR;
267 default:
Nicolas Capens865f8892020-01-21 14:27:10 -0500268 UNSUPPORTED("mipmapMode %d", sampler->mipmapMode);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000269 return MIPMAP_POINT;
Nicolas Capens9e735102019-04-18 15:03:06 -0400270 }
271}
272
Nicolas Capensdbd02752019-08-20 10:59:58 -0400273sw::AddressingMode SpirvShader::convertAddressingMode(int coordinateIndex, const vk::Sampler *sampler, VkImageViewType imageViewType)
Nicolas Capens9e735102019-04-18 15:03:06 -0400274{
Nicolas Capens6a12e092019-04-29 17:26:51 -0400275 switch(imageViewType)
276 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000277 case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
278 if(coordinateIndex == 3)
279 {
280 return ADDRESSING_LAYER;
281 }
282 // Fall through to CUBE case:
283 case VK_IMAGE_VIEW_TYPE_CUBE:
284 if(coordinateIndex <= 1) // Cube faces themselves are addressed as 2D images.
285 {
286 // Vulkan 1.1 spec:
287 // "Cube images ignore the wrap modes specified in the sampler. Instead, if VK_FILTER_NEAREST is used within a mip level then
288 // VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE is used, and if VK_FILTER_LINEAR is used within a mip level then sampling at the edges
289 // is performed as described earlier in the Cube map edge handling section."
290 // This corresponds with our 'SEAMLESS' addressing mode.
291 return ADDRESSING_SEAMLESS;
292 }
293 else if(coordinateIndex == 2)
294 {
295 // The cube face is an index into array layers.
296 return ADDRESSING_CUBEFACE;
297 }
298 else
299 {
300 return ADDRESSING_UNUSED;
301 }
302 break;
Nicolas Capens8da52532019-05-07 14:22:31 -0400303
Ben Claytonbc1c0672019-12-17 20:37:37 +0000304 case VK_IMAGE_VIEW_TYPE_1D: // Treated as 2D texture with second coordinate 0. TODO(b/134669567)
305 if(coordinateIndex == 1)
306 {
307 return ADDRESSING_WRAP;
308 }
309 else if(coordinateIndex >= 2)
310 {
311 return ADDRESSING_UNUSED;
312 }
313 break;
314
315 case VK_IMAGE_VIEW_TYPE_3D:
316 if(coordinateIndex >= 3)
317 {
318 return ADDRESSING_UNUSED;
319 }
320 break;
321
322 case VK_IMAGE_VIEW_TYPE_1D_ARRAY: // Treated as 2D texture with second coordinate 0. TODO(b/134669567)
323 if(coordinateIndex == 1)
324 {
325 return ADDRESSING_WRAP;
326 }
327 // Fall through to 2D_ARRAY case:
328 case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
329 if(coordinateIndex == 2)
330 {
331 return ADDRESSING_LAYER;
332 }
333 else if(coordinateIndex >= 3)
334 {
335 return ADDRESSING_UNUSED;
336 }
337 // Fall through to 2D case:
338 case VK_IMAGE_VIEW_TYPE_2D:
339 if(coordinateIndex >= 2)
340 {
341 return ADDRESSING_UNUSED;
342 }
343 break;
344
345 default:
Nicolas Capens865f8892020-01-21 14:27:10 -0500346 UNSUPPORTED("imageViewType %d", imageViewType);
Nicolas Capens8da52532019-05-07 14:22:31 -0400347 return ADDRESSING_WRAP;
Nicolas Capensa195abb2019-04-25 17:15:56 -0400348 }
349
Nicolas Capensdbd02752019-08-20 10:59:58 -0400350 if(!sampler)
351 {
352 // OpImageFetch does not take a sampler descriptor, but still needs a valid,
353 // arbitrary addressing mode that prevents out-of-bounds accesses:
354 // "The value returned by a read of an invalid texel is undefined, unless that
355 // read operation is from a buffer resource and the robustBufferAccess feature
356 // is enabled. In that case, an invalid texel is replaced as described by the
357 // robustBufferAccess feature." - Vulkan 1.1
358
359 return ADDRESSING_WRAP;
360 }
361
362 VkSamplerAddressMode addressMode = VK_SAMPLER_ADDRESS_MODE_REPEAT;
363 switch(coordinateIndex)
364 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000365 case 0: addressMode = sampler->addressModeU; break;
366 case 1: addressMode = sampler->addressModeV; break;
367 case 2: addressMode = sampler->addressModeW; break;
368 default: UNSUPPORTED("coordinateIndex: %d", coordinateIndex);
Nicolas Capensdbd02752019-08-20 10:59:58 -0400369 }
370
Nicolas Capens9e735102019-04-18 15:03:06 -0400371 switch(addressMode)
372 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000373 case VK_SAMPLER_ADDRESS_MODE_REPEAT: return ADDRESSING_WRAP;
374 case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: return ADDRESSING_MIRROR;
375 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: return ADDRESSING_CLAMP;
376 case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: return ADDRESSING_BORDER;
377 case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: return ADDRESSING_MIRRORONCE;
378 default:
Nicolas Capens865f8892020-01-21 14:27:10 -0500379 UNSUPPORTED("addressMode %d", addressMode);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000380 return ADDRESSING_WRAP;
Nicolas Capens9e735102019-04-18 15:03:06 -0400381 }
Ben Clayton96fbe082019-04-16 19:28:11 -0400382}
383
Ben Claytonbc1c0672019-12-17 20:37:37 +0000384} // namespace sw