Implement the extension GL_AMD_texture_gather_bias_lod
diff --git a/SPIRV/GLSL.ext.AMD.h b/SPIRV/GLSL.ext.AMD.h
index d2098cc..59972bc 100644
--- a/SPIRV/GLSL.ext.AMD.h
+++ b/SPIRV/GLSL.ext.AMD.h
@@ -28,11 +28,12 @@
 #define GLSLextAMD_H
 
 enum BuiltIn;
+enum Capability;
 enum Decoration;
 enum Op;
 
 static const int GLSLextAMDVersion = 100;
-static const int GLSLextAMDRevision = 2;
+static const int GLSLextAMDRevision = 3;
 
 // SPV_AMD_shader_ballot
 static const char* const E_SPV_AMD_shader_ballot = "SPV_AMD_shader_ballot";
@@ -113,4 +114,9 @@
 // SPV_AMD_gpu_shader_half_float
 static const char* const E_SPV_AMD_gpu_shader_half_float = "SPV_AMD_gpu_shader_half_float";
 
+// SPV_AMD_texture_gather_bias_lod
+static const char* const E_SPV_AMD_texture_gather_bias_lod = "SPV_AMD_texture_gather_bias_lod";
+
+static const Capability OpCapabilityImageGatherBiasLodAMD = static_cast<Capability>(5009);
+
 #endif  // #ifndef GLSLextAMD_H
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index e175bfc..f6c3e5d 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -3044,7 +3044,7 @@
             if (i == 6)
                 lvalue = true;
             break;
-         case glslang::EOpSparseTextureGather:
+        case glslang::EOpSparseTextureGather:
             if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2))
                 lvalue = true;
             break;
@@ -3053,6 +3053,17 @@
             if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3))
                 lvalue = true;
             break;
+#ifdef AMD_EXTENSIONS
+        case glslang::EOpSparseTextureGatherLod:
+            if (i == 3)
+                lvalue = true;
+            break;
+        case glslang::EOpSparseTextureGatherLodOffset:
+        case glslang::EOpSparseTextureGatherLodOffsets:
+            if (i == 4)
+                lvalue = true;
+            break;
+#endif
         default:
             break;
         }
@@ -3219,10 +3230,22 @@
 
     // check for bias argument
     bool bias = false;
+#ifdef AMD_EXTENSIONS
+    if (! cracked.lod && ! cracked.grad && ! cracked.fetch && ! cubeCompare) {
+#else
     if (! cracked.lod && ! cracked.gather && ! cracked.grad && ! cracked.fetch && ! cubeCompare) {
+#endif
         int nonBiasArgCount = 2;
+#ifdef AMD_EXTENSIONS
+        if (cracked.gather)
+            ++nonBiasArgCount; // comp argument should be present when bias argument is present
+#endif
         if (cracked.offset)
             ++nonBiasArgCount;
+#ifdef AMD_EXTENSIONS
+        else if (cracked.offsets)
+            ++nonBiasArgCount;
+#endif
         if (cracked.grad)
             nonBiasArgCount += 2;
         if (cracked.lodClamp)
@@ -3241,6 +3264,17 @@
             params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);
     }
 
+#ifdef AMD_EXTENSIONS
+    if (cracked.gather) {
+        const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
+        if (bias || cracked.lod ||
+            sourceExtensions.find(glslang::E_GL_AMD_texture_gather_bias_lod) != sourceExtensions.end()) {
+            builder.addExtension(spv::E_SPV_AMD_texture_gather_bias_lod);
+            builder.addCapability(spv::OpCapabilityImageGatherBiasLodAMD);
+        }
+    }
+#endif
+
     // set the rest of the arguments
 
     params.coords = arguments[1];
@@ -3308,21 +3342,20 @@
         ++extraArgs;
     }
 
-    // bias
-    if (bias) {
-        params.bias = arguments[2 + extraArgs];
-        ++extraArgs;
-    }
-
     // gather component
     if (cracked.gather && ! sampler.shadow) {
         // default component is 0, if missing, otherwise an argument
         if (2 + extraArgs < (int)arguments.size()) {
             params.component = arguments[2 + extraArgs];
             ++extraArgs;
-        } else {
+        } else
             params.component = builder.makeIntConstant(0);
-        }
+    }
+
+    // bias
+    if (bias) {
+        params.bias = arguments[2 + extraArgs];
+        ++extraArgs;
     }
 
     // projective component (might not to move)
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index 49b734b..bae43bd 100755
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -839,6 +839,10 @@
     case 4437: return "DeviceGroup";
     case 4439: return "MultiView";
 
+#ifdef AMD_EXTENSIONS
+    case 5009: return "ImageGatherBiasLodAMD";
+#endif
+
 #ifdef NV_EXTENSIONS
     case 5251: return "GeometryShaderPassthroughNV";
     case 5254: return "ShaderViewportIndexLayerNV";
diff --git a/Test/baseResults/spv.textureGatherBiasLod.frag.out b/Test/baseResults/spv.textureGatherBiasLod.frag.out
new file mode 100644
index 0000000..4e52cac
--- /dev/null
+++ b/Test/baseResults/spv.textureGatherBiasLod.frag.out
@@ -0,0 +1,386 @@
+spv.textureGatherBiasLod.frag
+Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 298
+
+                              Capability Shader
+                              Capability SparseResidency
+                              Capability SampledCubeArray
+                              Capability ImageGatherBiasLodAMD
+                              Extension  "SPV_AMD_texture_gather_bias_lod"
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main" 20 25 37 61 176 296
+                              ExecutionMode 4 OriginUpperLeft
+                              Source GLSL 450
+                              SourceExtension  "GL_AMD_texture_gather_bias_lod"
+                              SourceExtension  "GL_ARB_sparse_texture2"
+                              Name 4  "main"
+                              Name 9  "texel"
+                              Name 12  "result"
+                              Name 16  "s2D"
+                              Name 20  "c2"
+                              Name 25  "bias"
+                              Name 33  "s2DArray"
+                              Name 37  "c3"
+                              Name 47  "sCube"
+                              Name 58  "sCubeArray"
+                              Name 61  "c4"
+                              Name 104  "ResType"
+                              Name 176  "lod"
+                              Name 296  "fragColor"
+                              Decorate 16(s2D) DescriptorSet 0
+                              Decorate 33(s2DArray) DescriptorSet 0
+                              Decorate 47(sCube) DescriptorSet 0
+                              Decorate 58(sCubeArray) DescriptorSet 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 4
+               8:             TypePointer Function 7(fvec4)
+              10:    6(float) Constant 0
+              11:    7(fvec4) ConstantComposite 10 10 10 10
+              13:             TypeImage 6(float) 2D sampled format:Unknown
+              14:             TypeSampledImage 13
+              15:             TypePointer UniformConstant 14
+         16(s2D):     15(ptr) Variable UniformConstant
+              18:             TypeVector 6(float) 2
+              19:             TypePointer Input 18(fvec2)
+          20(c2):     19(ptr) Variable Input
+              22:             TypeInt 32 1
+              23:     22(int) Constant 0
+              24:             TypePointer Input 6(float)
+        25(bias):     24(ptr) Variable Input
+              30:             TypeImage 6(float) 2D array sampled format:Unknown
+              31:             TypeSampledImage 30
+              32:             TypePointer UniformConstant 31
+    33(s2DArray):     32(ptr) Variable UniformConstant
+              35:             TypeVector 6(float) 3
+              36:             TypePointer Input 35(fvec3)
+          37(c3):     36(ptr) Variable Input
+              39:     22(int) Constant 1
+              44:             TypeImage 6(float) Cube sampled format:Unknown
+              45:             TypeSampledImage 44
+              46:             TypePointer UniformConstant 45
+       47(sCube):     46(ptr) Variable UniformConstant
+              50:     22(int) Constant 2
+              55:             TypeImage 6(float) Cube array sampled format:Unknown
+              56:             TypeSampledImage 55
+              57:             TypePointer UniformConstant 56
+  58(sCubeArray):     57(ptr) Variable UniformConstant
+              60:             TypePointer Input 7(fvec4)
+          61(c4):     60(ptr) Variable Input
+              63:     22(int) Constant 3
+              70:             TypeVector 22(int) 2
+              71:   70(ivec2) ConstantComposite 23 23
+              78:   70(ivec2) ConstantComposite 23 39
+              85:             TypeInt 32 0
+              86:     85(int) Constant 4
+              87:             TypeArray 70(ivec2) 86
+              88:   70(ivec2) ConstantComposite 39 23
+              89:   70(ivec2) ConstantComposite 39 39
+              90:          87 ConstantComposite 71 78 88 89
+    104(ResType):             TypeStruct 22(int) 7(fvec4)
+        176(lod):     24(ptr) Variable Input
+             295:             TypePointer Output 7(fvec4)
+  296(fragColor):    295(ptr) Variable Output
+         4(main):           2 Function None 3
+               5:             Label
+        9(texel):      8(ptr) Variable Function
+      12(result):      8(ptr) Variable Function
+                              Store 9(texel) 11
+                              Store 12(result) 11
+              17:          14 Load 16(s2D)
+              21:   18(fvec2) Load 20(c2)
+              26:    6(float) Load 25(bias)
+              27:    7(fvec4) ImageGather 17 21 23 Bias 26
+              28:    7(fvec4) Load 9(texel)
+              29:    7(fvec4) FAdd 28 27
+                              Store 9(texel) 29
+              34:          31 Load 33(s2DArray)
+              38:   35(fvec3) Load 37(c3)
+              40:    6(float) Load 25(bias)
+              41:    7(fvec4) ImageGather 34 38 39 Bias 40
+              42:    7(fvec4) Load 9(texel)
+              43:    7(fvec4) FAdd 42 41
+                              Store 9(texel) 43
+              48:          45 Load 47(sCube)
+              49:   35(fvec3) Load 37(c3)
+              51:    6(float) Load 25(bias)
+              52:    7(fvec4) ImageGather 48 49 50 Bias 51
+              53:    7(fvec4) Load 9(texel)
+              54:    7(fvec4) FAdd 53 52
+                              Store 9(texel) 54
+              59:          56 Load 58(sCubeArray)
+              62:    7(fvec4) Load 61(c4)
+              64:    6(float) Load 25(bias)
+              65:    7(fvec4) ImageGather 59 62 63 Bias 64
+              66:    7(fvec4) Load 9(texel)
+              67:    7(fvec4) FAdd 66 65
+                              Store 9(texel) 67
+              68:          14 Load 16(s2D)
+              69:   18(fvec2) Load 20(c2)
+              72:    6(float) Load 25(bias)
+              73:    7(fvec4) ImageGather 68 69 23 Bias ConstOffset 72 71
+              74:    7(fvec4) Load 9(texel)
+              75:    7(fvec4) FAdd 74 73
+                              Store 9(texel) 75
+              76:          31 Load 33(s2DArray)
+              77:   35(fvec3) Load 37(c3)
+              79:    6(float) Load 25(bias)
+              80:    7(fvec4) ImageGather 76 77 39 Bias ConstOffset 79 78
+              81:    7(fvec4) Load 9(texel)
+              82:    7(fvec4) FAdd 81 80
+                              Store 9(texel) 82
+              83:          14 Load 16(s2D)
+              84:   18(fvec2) Load 20(c2)
+              91:    6(float) Load 25(bias)
+              92:    7(fvec4) ImageGather 83 84 23 Bias ConstOffsets 91 90
+              93:    7(fvec4) Load 9(texel)
+              94:    7(fvec4) FAdd 93 92
+                              Store 9(texel) 94
+              95:          31 Load 33(s2DArray)
+              96:   35(fvec3) Load 37(c3)
+              97:    6(float) Load 25(bias)
+              98:    7(fvec4) ImageGather 95 96 39 Bias ConstOffsets 97 90
+              99:    7(fvec4) Load 9(texel)
+             100:    7(fvec4) FAdd 99 98
+                              Store 9(texel) 100
+             101:          14 Load 16(s2D)
+             102:   18(fvec2) Load 20(c2)
+             103:    6(float) Load 25(bias)
+             105:104(ResType) ImageSparseGather 101 102 23 Bias 103
+             106:    7(fvec4) CompositeExtract 105 1
+                              Store 12(result) 106
+             107:     22(int) CompositeExtract 105 0
+             108:    7(fvec4) Load 12(result)
+             109:    7(fvec4) Load 9(texel)
+             110:    7(fvec4) FAdd 109 108
+                              Store 9(texel) 110
+             111:          31 Load 33(s2DArray)
+             112:   35(fvec3) Load 37(c3)
+             113:    6(float) Load 25(bias)
+             114:104(ResType) ImageSparseGather 111 112 39 Bias 113
+             115:    7(fvec4) CompositeExtract 114 1
+                              Store 12(result) 115
+             116:     22(int) CompositeExtract 114 0
+             117:    7(fvec4) Load 12(result)
+             118:    7(fvec4) Load 9(texel)
+             119:    7(fvec4) FAdd 118 117
+                              Store 9(texel) 119
+             120:          45 Load 47(sCube)
+             121:   35(fvec3) Load 37(c3)
+             122:    6(float) Load 25(bias)
+             123:104(ResType) ImageSparseGather 120 121 50 Bias 122
+             124:    7(fvec4) CompositeExtract 123 1
+                              Store 12(result) 124
+             125:     22(int) CompositeExtract 123 0
+             126:    7(fvec4) Load 12(result)
+             127:    7(fvec4) Load 9(texel)
+             128:    7(fvec4) FAdd 127 126
+                              Store 9(texel) 128
+             129:          56 Load 58(sCubeArray)
+             130:    7(fvec4) Load 61(c4)
+             131:    6(float) Load 25(bias)
+             132:104(ResType) ImageSparseGather 129 130 50 Bias 131
+             133:    7(fvec4) CompositeExtract 132 1
+                              Store 12(result) 133
+             134:     22(int) CompositeExtract 132 0
+             135:    7(fvec4) Load 12(result)
+             136:    7(fvec4) Load 9(texel)
+             137:    7(fvec4) FAdd 136 135
+                              Store 9(texel) 137
+             138:          14 Load 16(s2D)
+             139:   18(fvec2) Load 20(c2)
+             140:    6(float) Load 25(bias)
+             141:104(ResType) ImageSparseGather 138 139 23 Bias ConstOffset 140 71
+             142:    7(fvec4) CompositeExtract 141 1
+                              Store 12(result) 142
+             143:     22(int) CompositeExtract 141 0
+             144:    7(fvec4) Load 12(result)
+             145:    7(fvec4) Load 9(texel)
+             146:    7(fvec4) FAdd 145 144
+                              Store 9(texel) 146
+             147:          31 Load 33(s2DArray)
+             148:   35(fvec3) Load 37(c3)
+             149:    6(float) Load 25(bias)
+             150:104(ResType) ImageSparseGather 147 148 39 Bias ConstOffset 149 78
+             151:    7(fvec4) CompositeExtract 150 1
+                              Store 12(result) 151
+             152:     22(int) CompositeExtract 150 0
+             153:    7(fvec4) Load 12(result)
+             154:    7(fvec4) Load 9(texel)
+             155:    7(fvec4) FAdd 154 153
+                              Store 9(texel) 155
+             156:          14 Load 16(s2D)
+             157:   18(fvec2) Load 20(c2)
+             158:    6(float) Load 25(bias)
+             159:104(ResType) ImageSparseGather 156 157 23 Bias ConstOffsets 158 90
+             160:    7(fvec4) CompositeExtract 159 1
+                              Store 12(result) 160
+             161:     22(int) CompositeExtract 159 0
+             162:    7(fvec4) Load 12(result)
+             163:    7(fvec4) Load 9(texel)
+             164:    7(fvec4) FAdd 163 162
+                              Store 9(texel) 164
+             165:          31 Load 33(s2DArray)
+             166:   35(fvec3) Load 37(c3)
+             167:    6(float) Load 25(bias)
+             168:104(ResType) ImageSparseGather 165 166 39 Bias ConstOffsets 167 90
+             169:    7(fvec4) CompositeExtract 168 1
+                              Store 12(result) 169
+             170:     22(int) CompositeExtract 168 0
+             171:    7(fvec4) Load 12(result)
+             172:    7(fvec4) Load 9(texel)
+             173:    7(fvec4) FAdd 172 171
+                              Store 9(texel) 173
+             174:          14 Load 16(s2D)
+             175:   18(fvec2) Load 20(c2)
+             177:    6(float) Load 176(lod)
+             178:    7(fvec4) ImageGather 174 175 23 Lod 177
+             179:    7(fvec4) Load 9(texel)
+             180:    7(fvec4) FAdd 179 178
+                              Store 9(texel) 180
+             181:          31 Load 33(s2DArray)
+             182:   35(fvec3) Load 37(c3)
+             183:    6(float) Load 176(lod)
+             184:    7(fvec4) ImageGather 181 182 39 Lod 183
+             185:    7(fvec4) Load 9(texel)
+             186:    7(fvec4) FAdd 185 184
+                              Store 9(texel) 186
+             187:          45 Load 47(sCube)
+             188:   35(fvec3) Load 37(c3)
+             189:    6(float) Load 176(lod)
+             190:    7(fvec4) ImageGather 187 188 50 Lod 189
+             191:    7(fvec4) Load 9(texel)
+             192:    7(fvec4) FAdd 191 190
+                              Store 9(texel) 192
+             193:          56 Load 58(sCubeArray)
+             194:    7(fvec4) Load 61(c4)
+             195:    6(float) Load 176(lod)
+             196:    7(fvec4) ImageGather 193 194 63 Lod 195
+             197:    7(fvec4) Load 9(texel)
+             198:    7(fvec4) FAdd 197 196
+                              Store 9(texel) 198
+             199:          14 Load 16(s2D)
+             200:   18(fvec2) Load 20(c2)
+             201:    6(float) Load 176(lod)
+             202:    7(fvec4) ImageGather 199 200 23 Lod ConstOffset 201 71
+             203:    7(fvec4) Load 9(texel)
+             204:    7(fvec4) FAdd 203 202
+                              Store 9(texel) 204
+             205:          31 Load 33(s2DArray)
+             206:   35(fvec3) Load 37(c3)
+             207:    6(float) Load 176(lod)
+             208:    7(fvec4) ImageGather 205 206 39 Lod ConstOffset 207 78
+             209:    7(fvec4) Load 9(texel)
+             210:    7(fvec4) FAdd 209 208
+                              Store 9(texel) 210
+             211:          14 Load 16(s2D)
+             212:   18(fvec2) Load 20(c2)
+             213:    6(float) Load 176(lod)
+             214:    7(fvec4) ImageGather 211 212 23 Lod ConstOffsets 213 90
+             215:    7(fvec4) Load 9(texel)
+             216:    7(fvec4) FAdd 215 214
+                              Store 9(texel) 216
+             217:          31 Load 33(s2DArray)
+             218:   35(fvec3) Load 37(c3)
+             219:    6(float) Load 176(lod)
+             220:    7(fvec4) ImageGather 217 218 39 Lod ConstOffsets 219 90
+             221:    7(fvec4) Load 9(texel)
+             222:    7(fvec4) FAdd 221 220
+                              Store 9(texel) 222
+             223:          14 Load 16(s2D)
+             224:   18(fvec2) Load 20(c2)
+             225:    6(float) Load 176(lod)
+             226:104(ResType) ImageSparseGather 223 224 23 Lod 225
+             227:    7(fvec4) CompositeExtract 226 1
+                              Store 12(result) 227
+             228:     22(int) CompositeExtract 226 0
+             229:    7(fvec4) Load 12(result)
+             230:    7(fvec4) Load 9(texel)
+             231:    7(fvec4) FAdd 230 229
+                              Store 9(texel) 231
+             232:          31 Load 33(s2DArray)
+             233:   35(fvec3) Load 37(c3)
+             234:    6(float) Load 176(lod)
+             235:104(ResType) ImageSparseGather 232 233 39 Lod 234
+             236:    7(fvec4) CompositeExtract 235 1
+                              Store 12(result) 236
+             237:     22(int) CompositeExtract 235 0
+             238:    7(fvec4) Load 12(result)
+             239:    7(fvec4) Load 9(texel)
+             240:    7(fvec4) FAdd 239 238
+                              Store 9(texel) 240
+             241:          45 Load 47(sCube)
+             242:   35(fvec3) Load 37(c3)
+             243:    6(float) Load 176(lod)
+             244:104(ResType) ImageSparseGather 241 242 50 Lod 243
+             245:    7(fvec4) CompositeExtract 244 1
+                              Store 12(result) 245
+             246:     22(int) CompositeExtract 244 0
+             247:    7(fvec4) Load 12(result)
+             248:    7(fvec4) Load 9(texel)
+             249:    7(fvec4) FAdd 248 247
+                              Store 9(texel) 249
+             250:          56 Load 58(sCubeArray)
+             251:    7(fvec4) Load 61(c4)
+             252:    6(float) Load 176(lod)
+             253:104(ResType) ImageSparseGather 250 251 50 Lod 252
+             254:    7(fvec4) CompositeExtract 253 1
+                              Store 12(result) 254
+             255:     22(int) CompositeExtract 253 0
+             256:    7(fvec4) Load 12(result)
+             257:    7(fvec4) Load 9(texel)
+             258:    7(fvec4) FAdd 257 256
+                              Store 9(texel) 258
+             259:          14 Load 16(s2D)
+             260:   18(fvec2) Load 20(c2)
+             261:    6(float) Load 176(lod)
+             262:104(ResType) ImageSparseGather 259 260 23 Lod ConstOffset 261 71
+             263:    7(fvec4) CompositeExtract 262 1
+                              Store 12(result) 263
+             264:     22(int) CompositeExtract 262 0
+             265:    7(fvec4) Load 12(result)
+             266:    7(fvec4) Load 9(texel)
+             267:    7(fvec4) FAdd 266 265
+                              Store 9(texel) 267
+             268:          31 Load 33(s2DArray)
+             269:   35(fvec3) Load 37(c3)
+             270:    6(float) Load 176(lod)
+             271:104(ResType) ImageSparseGather 268 269 39 Lod ConstOffset 270 78
+             272:    7(fvec4) CompositeExtract 271 1
+                              Store 12(result) 272
+             273:     22(int) CompositeExtract 271 0
+             274:    7(fvec4) Load 12(result)
+             275:    7(fvec4) Load 9(texel)
+             276:    7(fvec4) FAdd 275 274
+                              Store 9(texel) 276
+             277:          14 Load 16(s2D)
+             278:   18(fvec2) Load 20(c2)
+             279:    6(float) Load 176(lod)
+             280:104(ResType) ImageSparseGather 277 278 23 Lod ConstOffsets 279 90
+             281:    7(fvec4) CompositeExtract 280 1
+                              Store 12(result) 281
+             282:     22(int) CompositeExtract 280 0
+             283:    7(fvec4) Load 12(result)
+             284:    7(fvec4) Load 9(texel)
+             285:    7(fvec4) FAdd 284 283
+                              Store 9(texel) 285
+             286:          31 Load 33(s2DArray)
+             287:   35(fvec3) Load 37(c3)
+             288:    6(float) Load 176(lod)
+             289:104(ResType) ImageSparseGather 286 287 39 Lod ConstOffsets 288 90
+             290:    7(fvec4) CompositeExtract 289 1
+                              Store 12(result) 290
+             291:     22(int) CompositeExtract 289 0
+             292:    7(fvec4) Load 12(result)
+             293:    7(fvec4) Load 9(texel)
+             294:    7(fvec4) FAdd 293 292
+                              Store 9(texel) 294
+             297:    7(fvec4) Load 9(texel)
+                              Store 296(fragColor) 297
+                              Return
+                              FunctionEnd
diff --git a/Test/spv.textureGatherBiasLod.frag b/Test/spv.textureGatherBiasLod.frag
new file mode 100644
index 0000000..35bd035
--- /dev/null
+++ b/Test/spv.textureGatherBiasLod.frag
@@ -0,0 +1,88 @@
+#version 450 core

+

+#extension GL_ARB_sparse_texture2: enable

+#extension GL_AMD_texture_gather_bias_lod: enable

+

+uniform sampler2D           s2D;

+uniform sampler2DArray      s2DArray;

+uniform samplerCube         sCube;

+uniform samplerCubeArray    sCubeArray;

+

+in vec2 c2;

+in vec3 c3;

+in vec4 c4;

+

+in float lod;

+in float bias;

+

+out vec4 fragColor;

+

+void main()

+{

+    vec4 texel  = vec4(0.0);

+    vec4 result = vec4(0.0);

+

+    const ivec2 offsets[4] = { ivec2(0, 0), ivec2(0, 1), ivec2(1, 0), ivec2(1, 1) };

+

+    texel += textureGather(s2D,        c2, 0, bias);

+    texel += textureGather(s2DArray,   c3, 1, bias);

+    texel += textureGather(sCube,      c3, 2, bias);

+    texel += textureGather(sCubeArray, c4, 3, bias);

+

+    texel += textureGatherOffset(s2D,        c2, offsets[0], 0, bias);

+    texel += textureGatherOffset(s2DArray,   c3, offsets[1], 1, bias);

+

+    texel += textureGatherOffsets(s2D,        c2, offsets, 0, bias);

+    texel += textureGatherOffsets(s2DArray,   c3, offsets, 1, bias);

+

+    sparseTextureGatherARB(s2D,        c2, result, 0, bias);

+    texel += result;

+    sparseTextureGatherARB(s2DArray,   c3, result, 1, bias);

+    texel += result;

+    sparseTextureGatherARB(sCube,      c3, result, 2, bias);

+    texel += result;

+    sparseTextureGatherARB(sCubeArray, c4, result, 2, bias);

+    texel += result;

+

+    sparseTextureGatherOffsetARB(s2D,      c2, offsets[0], result, 0, bias);

+    texel += result;

+    sparseTextureGatherOffsetARB(s2DArray, c3, offsets[1], result, 1, bias);

+    texel += result;

+

+    sparseTextureGatherOffsetsARB(s2D,      c2, offsets, result, 0, bias);

+    texel += result;

+    sparseTextureGatherOffsetsARB(s2DArray, c3, offsets, result, 1, bias);

+    texel += result;

+

+    texel += textureGatherLodAMD(s2D,        c2, lod);

+    texel += textureGatherLodAMD(s2DArray,   c3, lod, 1);

+    texel += textureGatherLodAMD(sCube,      c3, lod, 2);

+    texel += textureGatherLodAMD(sCubeArray, c4, lod, 3);

+

+    texel += textureGatherLodOffsetAMD(s2D,        c2, lod, offsets[0]);

+    texel += textureGatherLodOffsetAMD(s2DArray,   c3, lod, offsets[1], 1);

+

+    texel += textureGatherLodOffsetsAMD(s2D,       c2, lod, offsets);

+    texel += textureGatherLodOffsetsAMD(s2DArray,  c3, lod, offsets, 1);

+

+    sparseTextureGatherLodAMD(s2D,        c2, lod, result);

+    texel += result;

+    sparseTextureGatherLodAMD(s2DArray,   c3, lod, result, 1);

+    texel += result;

+    sparseTextureGatherLodAMD(sCube,      c3, lod, result, 2);

+    texel += result;

+    sparseTextureGatherLodAMD(sCubeArray, c4, lod, result, 2);

+    texel += result;

+

+    sparseTextureGatherLodOffsetAMD(s2D,      c2, lod, offsets[0], result);

+    texel += result;

+    sparseTextureGatherLodOffsetAMD(s2DArray, c3, lod, offsets[1], result, 1);

+    texel += result;

+

+    sparseTextureGatherLodOffsetsAMD(s2D,      c2, lod, offsets, result);

+    texel += result;

+    sparseTextureGatherLodOffsetsAMD(s2DArray, c3, lod, offsets, result, 1);

+    texel += result;

+

+    fragColor = texel;

+}

diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index 5115db9..9618a99 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -567,6 +567,11 @@
     EOpTextureOffsetClamp,
     EOpTextureGradClamp,
     EOpTextureGradOffsetClamp,
+#ifdef AMD_EXTENSIONS
+    EOpTextureGatherLod,
+    EOpTextureGatherLodOffset,
+    EOpTextureGatherLodOffsets,
+#endif
 
     EOpSparseTextureGuardBegin,
 
@@ -586,6 +591,11 @@
     EOpSparseTextureOffsetClamp,
     EOpSparseTextureGradClamp,
     EOpSparseTextureGradOffsetClamp,
+#ifdef AMD_EXTENSIONS
+    EOpSparseTextureGatherLod,
+    EOpSparseTextureGatherLodOffset,
+    EOpSparseTextureGatherLodOffsets,
+#endif
 
     EOpSparseTextureGuardEnd,
     EOpSamplingGuardEnd,
@@ -1075,6 +1085,25 @@
             cracked.gather = true;
             cracked.offsets = true;
             break;
+#ifdef AMD_EXTENSIONS
+        case EOpTextureGatherLod:
+        case EOpSparseTextureGatherLod:
+            cracked.gather = true;
+            cracked.lod    = true;
+            break;
+        case EOpTextureGatherLodOffset:
+        case EOpSparseTextureGatherLodOffset:
+            cracked.gather = true;
+            cracked.offset = true;
+            cracked.lod    = true;
+            break;
+        case EOpTextureGatherLodOffsets:
+        case EOpSparseTextureGatherLodOffsets:
+            cracked.gather  = true;
+            cracked.offsets = true;
+            cracked.lod     = true;
+            break;
+#endif
         case EOpSubpassLoad:
         case EOpSubpassLoadMS:
             cracked.subpass = true;
diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp
index 0771c86..083b3ce 100644
--- a/glslang/MachineIndependent/Initialize.cpp
+++ b/glslang/MachineIndependent/Initialize.cpp
@@ -3844,6 +3844,7 @@
                             else {
                                 addSamplingFunctions(sampler, typeName, version, profile);
                                 addGatherFunctions(sampler, typeName, version, profile);
+
                                 if (spvVersion.vulkan > 0 && sampler.dim == EsdBuffer && sampler.isCombined()) {
                                     // Vulkan wants a textureBuffer to allow texelFetch() --
                                     // a sampled image with no sampler.
@@ -4349,6 +4350,7 @@
                 default:
                     break;
                 }
+
                 if (sparse)
                     s.append("ARB");
                 s.append("(");
@@ -4388,6 +4390,116 @@
             }
         }
     }
+
+#ifdef AMD_EXTENSIONS
+    if (sampler.dim == EsdRect || sampler.shadow)
+        return;
+
+    if (profile == EEsProfile || version < 450)
+        return;
+
+    for (int bias = 0; bias < 2; ++bias) { // loop over presence of bias argument
+
+        for (int lod = 0; lod < 2; ++lod) { // loop over presence of lod argument
+
+            if ((lod && bias) || (lod == 0 && bias == 0))
+                continue;
+
+            for (int offset = 0; offset < 3; ++offset) { // loop over three forms of offset in the call name:  none, Offset, and Offsets
+
+                for (int comp = 0; comp < 2; ++comp) { // loop over presence of comp argument
+
+                    if (comp == 0 && bias)
+                        continue;
+
+                    if (offset > 0 && sampler.dim == EsdCube)
+                        continue;
+
+                    for (int sparse = 0; sparse <= 1; ++sparse) { // loop over "bool" sparse or not
+                        if (sparse && (profile == EEsProfile || version < 450))
+                            continue;
+
+                        TString s;
+
+                        // return type
+                        if (sparse)
+                            s.append("int ");
+                        else {
+                            s.append(prefixes[sampler.type]);
+                            s.append("vec4 ");
+                        }
+
+                        // name
+                        if (sparse)
+                            s.append("sparseTextureGather");
+                        else
+                            s.append("textureGather");
+
+                        if (lod)
+                            s.append("Lod");
+
+                        switch (offset) {
+                        case 1:
+                            s.append("Offset");
+                            break;
+                        case 2:
+                            s.append("Offsets");
+                        default:
+                            break;
+                        }
+
+                        if (lod)
+                            s.append("AMD");
+                        else if (sparse)
+                            s.append("ARB");
+
+                        s.append("(");
+
+                        // sampler type argument
+                        s.append(typeName);
+
+                        // P coordinate argument
+                        s.append(",vec");
+                        int totalDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0);
+                        s.append(postfixes[totalDims]);
+
+                        // lod argument
+                        if (lod)
+                            s.append(",float");
+
+                        // offset argument
+                        if (offset > 0) {
+                            s.append(",ivec2");
+                            if (offset == 2)
+                                s.append("[4]");
+                        }
+
+                        // texel out (for sparse texture)
+                        if (sparse) {
+                            s.append(",out ");
+                            s.append(prefixes[sampler.type]);
+                            s.append("vec4 ");
+                        }
+
+                        // comp argument
+                        if (comp)
+                            s.append(",int");
+
+                        // bias argument
+                        if (bias)
+                            s.append(",float");
+
+                        s.append(");\n");
+                        if (bias)
+                            stageBuiltins[EShLangFragment].append(s);
+                        else
+                            commonBuiltins.append(s);
+                    }
+                }
+            }
+        }
+    }
+#endif
 }
 
 //
@@ -5366,6 +5478,16 @@
             BuiltInVariable("gl_BaryCoordSmoothSampleAMD",      EbvBaryCoordSmoothSample,    symbolTable);
             BuiltInVariable("gl_BaryCoordPullModelAMD",         EbvBaryCoordPullModel,       symbolTable);
         }
+
+        // E_GL_AMD_texture_gather_bias_lod
+        if (profile != EEsProfile) {
+            symbolTable.setFunctionExtensions("textureGatherLodAMD",                1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("textureGatherLodOffsetAMD",          1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("textureGatherLodOffsetsAMD",         1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("sparseTextureGatherLodAMD",          1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("sparseTextureGatherLodOffsetAMD",    1, &E_GL_AMD_texture_gather_bias_lod);
+            symbolTable.setFunctionExtensions("sparseTextureGatherLodOffsetsAMD",   1, &E_GL_AMD_texture_gather_bias_lod);
+        }
 #endif
 
         symbolTable.setVariableExtensions("gl_FragDepthEXT", 1, &E_GL_EXT_frag_depth);
@@ -5752,6 +5874,13 @@
             symbolTable.relateToOperator("cubeFaceIndexAMD",    EOpCubeFaceIndex);
             symbolTable.relateToOperator("cubeFaceCoordAMD",    EOpCubeFaceCoord);
             symbolTable.relateToOperator("timeAMD",             EOpTime);
+
+            symbolTable.relateToOperator("textureGatherLodAMD",                 EOpTextureGatherLod);
+            symbolTable.relateToOperator("textureGatherLodOffsetAMD",           EOpTextureGatherLodOffset);
+            symbolTable.relateToOperator("textureGatherLodOffsetsAMD",          EOpTextureGatherLodOffsets);
+            symbolTable.relateToOperator("sparseTextureGatherLodAMD",           EOpSparseTextureGatherLod);
+            symbolTable.relateToOperator("sparseTextureGatherLodOffsetAMD",     EOpSparseTextureGatherLodOffset);
+            symbolTable.relateToOperator("sparseTextureGatherLodOffsetsAMD",    EOpSparseTextureGatherLodOffsets);
 #endif
         }
     }
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index c1f0b30..f4cf354 100644
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -1442,9 +1442,56 @@
                 error(loc, "must be a compile-time constant:", feature, "component argument");
         }
 
+#ifdef AMD_EXTENSIONS
+        bool bias = false;
+        if (callNode.getOp() == EOpTextureGather)
+            bias = fnCandidate.getParamCount() > 3;
+        else if (callNode.getOp() == EOpTextureGatherOffset ||
+                 callNode.getOp() == EOpTextureGatherOffsets)
+            bias = fnCandidate.getParamCount() > 4;
+
+        if (bias) {
+            featureString = fnCandidate.getName() + "with bias argument";
+            feature = featureString.c_str();
+            profileRequires(loc, ~EEsProfile, 450, nullptr, feature);
+            requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature);
+        }
+#endif
+
         break;
     }
 
+#ifdef AMD_EXTENSIONS
+    case EOpSparseTextureGather:
+    case EOpSparseTextureGatherOffset:
+    case EOpSparseTextureGatherOffsets:
+    {
+        bool bias = false;
+        if (callNode.getOp() == EOpSparseTextureGather)
+            bias = fnCandidate.getParamCount() > 4;
+        else if (callNode.getOp() == EOpSparseTextureGatherOffset ||
+                 callNode.getOp() == EOpSparseTextureGatherOffsets)
+            bias = fnCandidate.getParamCount() > 5;
+
+        if (bias) {
+            TString featureString = fnCandidate.getName() + "with bias argument";
+            const char* feature = featureString.c_str();
+            profileRequires(loc, ~EEsProfile, 450, nullptr, feature);
+            requireExtensions(loc, 1, &E_GL_AMD_texture_gather_bias_lod, feature);
+        }
+
+        break;
+    }
+
+    case EOpSparseTextureGatherLod:
+    case EOpSparseTextureGatherLodOffset:
+    case EOpSparseTextureGatherLodOffsets:
+    {
+        requireExtensions(loc, 1, &E_GL_ARB_sparse_texture2, fnCandidate.getName().c_str());
+        break;
+    }
+#endif
+
     case EOpTextureOffset:
     case EOpTextureFetchOffset:
     case EOpTextureProjOffset:
diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp
index 528333f..9ae6bc1 100644
--- a/glslang/MachineIndependent/Versions.cpp
+++ b/glslang/MachineIndependent/Versions.cpp
@@ -194,6 +194,7 @@
     extensionBehavior[E_GL_AMD_shader_explicit_vertex_parameter]     = EBhDisable;
     extensionBehavior[E_GL_AMD_gcn_shader]                           = EBhDisable;
     extensionBehavior[E_GL_AMD_gpu_shader_half_float]                = EBhDisable;
+    extensionBehavior[E_GL_AMD_texture_gather_bias_lod]              = EBhDisable;
 #endif
 
 #ifdef NV_EXTENSIONS
@@ -316,6 +317,7 @@
             "#define GL_AMD_shader_explicit_vertex_parameter 1\n"
             "#define GL_AMD_gcn_shader 1\n"
             "#define GL_AMD_gpu_shader_half_float 1\n"
+            "#define GL_AMD_texture_gather_bias_lod 1\n"
 #endif
 
 #ifdef NV_EXTENSIONS
diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h
index 7f5d33d..483140c 100644
--- a/glslang/MachineIndependent/Versions.h
+++ b/glslang/MachineIndependent/Versions.h
@@ -146,6 +146,7 @@
 const char* const E_GL_AMD_shader_explicit_vertex_parameter     = "GL_AMD_shader_explicit_vertex_parameter";
 const char* const E_GL_AMD_gcn_shader                           = "GL_AMD_gcn_shader";
 const char* const E_GL_AMD_gpu_shader_half_float                = "GL_AMD_gpu_shader_half_float";
+const char* const E_GL_AMD_texture_gather_bias_lod              = "GL_AMD_texture_gather_bias_lod";
 #endif
 #ifdef NV_EXTENSIONS
 
diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index 31f599c..59faba8 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -390,6 +390,8 @@
     case EOpRcp:                    out.debug << "rcp";                   break;
     case EOpSaturate:               out.debug << "saturate";              break;
 
+    case EOpSparseTexelsResident:   out.debug << "sparseTexelsResident";  break;
+
 #ifdef AMD_EXTENSIONS
     case EOpMinInvocations:             out.debug << "minInvocations";              break;
     case EOpMaxInvocations:             out.debug << "maxInvocations";              break;
@@ -647,6 +649,37 @@
     case EOpTextureGather:              out.debug << "textureGather";         break;
     case EOpTextureGatherOffset:        out.debug << "textureGatherOffset";   break;
     case EOpTextureGatherOffsets:       out.debug << "textureGatherOffsets";  break;
+    case EOpTextureClamp:               out.debug << "textureClamp";          break;
+    case EOpTextureOffsetClamp:         out.debug << "textureOffsetClamp";    break;
+    case EOpTextureGradClamp:           out.debug << "textureGradClamp";      break;
+    case EOpTextureGradOffsetClamp:     out.debug << "textureGradOffsetClamp";  break;
+#ifdef AMD_EXTENSIONS
+    case EOpTextureGatherLod:           out.debug << "textureGatherLod";        break;
+    case EOpTextureGatherLodOffset:     out.debug << "textureGatherLodOffset";  break;
+    case EOpTextureGatherLodOffsets:    out.debug << "textureGatherLodOffsets"; break;
+#endif
+
+    case EOpSparseTexture:                  out.debug << "sparseTexture";                   break;
+    case EOpSparseTextureOffset:            out.debug << "sparseTextureOffset";             break;
+    case EOpSparseTextureLod:               out.debug << "sparseTextureLod";                break;
+    case EOpSparseTextureLodOffset:         out.debug << "sparseTextureLodOffset";          break;
+    case EOpSparseTextureFetch:             out.debug << "sparseTexelFetch";                break;
+    case EOpSparseTextureFetchOffset:       out.debug << "sparseTexelFetchOffset";          break;
+    case EOpSparseTextureGrad:              out.debug << "sparseTextureGrad";               break;
+    case EOpSparseTextureGradOffset:        out.debug << "sparseTextureGradOffset";         break;
+    case EOpSparseTextureGather:            out.debug << "sparseTextureGather";             break;
+    case EOpSparseTextureGatherOffset:      out.debug << "sparseTextureGatherOffset";       break;
+    case EOpSparseTextureGatherOffsets:     out.debug << "sparseTextureGatherOffsets";      break;
+    case EOpSparseImageLoad:                out.debug << "sparseImageLoad";                 break;
+    case EOpSparseTextureClamp:             out.debug << "sparseTextureClamp";              break;
+    case EOpSparseTextureOffsetClamp:       out.debug << "sparseTextureOffsetClamp";        break;
+    case EOpSparseTextureGradClamp:         out.debug << "sparseTextureGradClamp";          break;
+    case EOpSparseTextureGradOffsetClamp:   out.debug << "sparseTextureGradOffsetClam";     break;
+#ifdef AMD_EXTENSIONS
+    case EOpSparseTextureGatherLod:         out.debug << "sparseTextureGatherLod";          break;
+    case EOpSparseTextureGatherLodOffset:   out.debug << "sparseTextureGatherLodOffset";    break;
+    case EOpSparseTextureGatherLodOffsets:  out.debug << "sparseTextureGatherLodOffsets";   break;
+#endif
 
     case EOpAddCarry:                   out.debug << "addCarry";              break;
     case EOpSubBorrow:                  out.debug << "subBorrow";             break;
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index 1552b95..27b6837 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -396,7 +396,8 @@
     Glsl, CompileVulkanToSpirvTestAMD,
     ::testing::ValuesIn(std::vector<std::string>({
         "spv.float16.frag",
-        "spv.shaderBallotAMD.comp"
+        "spv.shaderBallotAMD.comp",
+        "spv.textureGatherBiasLod.frag"
     })),
     FileNameAsCustomTestSuffix
 );