[clang] [llvm] [Matrix] Implement matrix support for the `pow` intrinsic (PR #212514)

Kaitlin Peng via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 28 08:04:47 PDT 2026


https://github.com/kmpeng created https://github.com/llvm/llvm-project/pull/212514

Closes #184513.

This PR implements the matrix api for `pow` in `HLSLintrinsics.td`, adds matrix codegen tests, matrix sema tests, and matrix backend tests.

>From 2fb6383beb9b8d8d73a38106bb72b862b3c58861 Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Tue, 28 Jul 2026 07:56:46 -0700
Subject: [PATCH] pow matrix implementation and tests

---
 clang/include/clang/Basic/HLSLIntrinsics.td   |   1 -
 .../lib/Headers/hlsl/hlsl_compat_overloads.h  |   2 +
 .../builtins/pow_mat-overloads.hlsl           |  52 ++
 clang/test/CodeGenHLSL/builtins/pow_mat.hlsl  | 203 +++++++
 .../binary-compat-overload-warnings.hlsl      |   2 +-
 .../SemaHLSL/BuiltIns/pow_mat-errors.hlsl     |   7 +
 llvm/test/CodeGen/DirectX/pow_mat.ll          |  47 ++
 .../CodeGen/SPIRV/hlsl-intrinsics/pow_mat.ll  | 551 ++++++++++++++++++
 8 files changed, 863 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CodeGenHLSL/builtins/pow_mat-overloads.hlsl
 create mode 100644 clang/test/CodeGenHLSL/builtins/pow_mat.hlsl
 create mode 100644 clang/test/SemaHLSL/BuiltIns/pow_mat-errors.hlsl
 create mode 100644 llvm/test/CodeGen/DirectX/pow_mat.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pow_mat.ll

diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td
index 99259046940f1..331f87bddbcca 100644
--- a/clang/include/clang/Basic/HLSLIntrinsics.td
+++ b/clang/include/clang/Basic/HLSLIntrinsics.td
@@ -1319,7 +1319,6 @@ def hlsl_pow : HLSLTwoArgBuiltin<"pow", "__builtin_elementwise_pow"> {
 \param Pow The specified power.
 }];
   let VaryingTypes = [HalfTy, FloatTy];
-  let VaryingMatDims = [];
 }
 
 // Reads the value from the lane across the X axis of the quad.
diff --git a/clang/lib/Headers/hlsl/hlsl_compat_overloads.h b/clang/lib/Headers/hlsl/hlsl_compat_overloads.h
index d97039128ea85..3a75050129aa5 100644
--- a/clang/lib/Headers/hlsl/hlsl_compat_overloads.h
+++ b/clang/lib/Headers/hlsl/hlsl_compat_overloads.h
@@ -484,6 +484,8 @@ _DXC_COMPAT_UNARY_INTEGER_OVERLOADS(normalize)
 
 _DXC_COMPAT_BINARY_DOUBLE_OVERLOADS(pow)
 _DXC_COMPAT_BINARY_INTEGER_OVERLOADS(pow)
+_DXC_COMPAT_BINARY_DOUBLE_MATRIX_OVERLOADS(pow)
+_DXC_COMPAT_BINARY_INTEGER_MATRIX_OVERLOADS(pow)
 
 //===----------------------------------------------------------------------===//
 // rsqrt builtins overloads
diff --git a/clang/test/CodeGenHLSL/builtins/pow_mat-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/pow_mat-overloads.hlsl
new file mode 100644
index 0000000000000..4910f096d86f8
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/pow_mat-overloads.hlsl
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -emit-llvm  \
+// RUN:   -o - | FileCheck %s --check-prefixes=CHECK -DSPIR_FUNC="" 
+// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \
+// RUN:   spirv-unknown-vulkan-library %s -emit-llvm  \
+// RUN:   -o - | FileCheck %s --check-prefixes=CHECK -DSPIR_FUNC="spir_func "
+
+
+// CHECK: define hidden [[SPIR_FUNC]]noundef nofpclass(nan inf) <12 x float> @_{{.*}}test_pow_double3x4{{.*}}(
+// CHECK:    [[CONVI:%.*]] = fptrunc {{.*}} <12 x double> %{{.*}} to <12 x float>
+// CHECK:    [[CONV1I:%.*]] = fptrunc {{.*}} <12 x double> %{{.*}} to <12 x float>
+// CHECK:    [[V5:%.*]] = call {{.*}} <12 x float> @llvm.pow.v12f32(<12 x float> [[CONVI]], <12 x float> [[CONV1I]])
+// CHECK:    ret <12 x float> [[V5]]
+float3x4 test_pow_double3x4 (double3x4 p0, double3x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK: define hidden [[SPIR_FUNC]]noundef nofpclass(nan inf) <12 x float> @_{{.*}}test_pow_uint3x4{{.*}}(
+// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} <12 x i32> %{{.*}} to <12 x float>
+// CHECK:    [[CONV1I:%.*]] = uitofp {{.*}} <12 x i32> %{{.*}} to <12 x float>
+// CHECK:    [[V5:%.*]] = call {{.*}} <12 x float> @llvm.pow.v12f32(<12 x float> [[CONVI]], <12 x float> [[CONV1I]])
+// CHECK:    ret <12 x float> [[V5]]
+float3x4 test_pow_uint3x4 (uint3x4 p0, uint3x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK: define hidden [[SPIR_FUNC]]noundef nofpclass(nan inf) <12 x float> @_{{.*}}test_pow_int3x4{{.*}}(
+// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} <12 x i32> %{{.*}} to <12 x float>
+// CHECK:    [[CONV1I:%.*]] = sitofp {{.*}} <12 x i32> %{{.*}} to <12 x float>
+// CHECK:    [[V5:%.*]] = call {{.*}} <12 x float> @llvm.pow.v12f32(<12 x float> [[CONVI]], <12 x float> [[CONV1I]])
+// CHECK:    ret <12 x float> [[V5]]
+float3x4 test_pow_int3x4 (int3x4 p0, int3x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK: define hidden [[SPIR_FUNC]]noundef nofpclass(nan inf) <12 x float> @_{{.*}}test_pow_int64_t3x4{{.*}}(
+// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} <12 x i64> %{{.*}} to <12 x float>
+// CHECK:    [[CONV1I:%.*]] = sitofp {{.*}} <12 x i64> %{{.*}} to <12 x float>
+// CHECK:    [[V5:%.*]] = call {{.*}} <12 x float> @llvm.pow.v12f32(<12 x float> [[CONVI]], <12 x float> [[CONV1I]])
+// CHECK:    ret <12 x float> [[V5]]
+float3x4 test_pow_int64_t3x4 (int64_t3x4 p0, int64_t3x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK: define hidden [[SPIR_FUNC]]noundef nofpclass(nan inf) <12 x float> @_{{.*}}test_pow_uint64_t3x4{{.*}}(
+// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} <12 x i64> %{{.*}} to <12 x float>
+// CHECK:    [[CONV1I:%.*]] = uitofp {{.*}} <12 x i64> %{{.*}} to <12 x float>
+// CHECK:    [[V5:%.*]] = call {{.*}} <12 x float> @llvm.pow.v12f32(<12 x float> [[CONVI]], <12 x float> [[CONV1I]])
+// CHECK:    ret <12 x float> [[V5]]
+float3x4 test_pow_uint64_t3x4 (uint64_t3x4 p0, uint64_t3x4 p1) {
+  return pow(p0, p1);
+}
diff --git a/clang/test/CodeGenHLSL/builtins/pow_mat.hlsl b/clang/test/CodeGenHLSL/builtins/pow_mat.hlsl
new file mode 100644
index 0000000000000..1877888189518
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/pow_mat.hlsl
@@ -0,0 +1,203 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s -fnative-half-type -fnative-int16-type \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
+// RUN:   --check-prefixes=CHECK,NATIVE_HALF
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   spirv-unknown-vulkan-library %s -emit-llvm -disable-llvm-passes \
+// RUN:   -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF
+
+// CHECK-LABEL: test_pow_half1x2
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.pow.v2f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.pow.v2f32
+half1x2 test_pow_half1x2 (half1x2 p0, half1x2 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half1x3
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.pow.v3f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.pow.v3f32
+half1x3 test_pow_half1x3 (half1x3 p0, half1x3 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half1x4
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.pow.v4f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.pow.v4f32
+half1x4 test_pow_half1x4 (half1x4 p0, half1x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half2x1
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.pow.v2f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.pow.v2f32
+half2x1 test_pow_half2x1 (half2x1 p0, half2x1 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half2x2
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.pow.v4f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.pow.v4f32
+half2x2 test_pow_half2x2 (half2x2 p0, half2x2 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half2x3
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <6 x half> @llvm.pow.v6f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <6 x float> @llvm.pow.v6f32
+half2x3 test_pow_half2x3 (half2x3 p0, half2x3 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half2x4
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <8 x half> @llvm.pow.v8f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <8 x float> @llvm.pow.v8f32
+half2x4 test_pow_half2x4 (half2x4 p0, half2x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half3x1
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.pow.v3f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.pow.v3f32
+half3x1 test_pow_half3x1 (half3x1 p0, half3x1 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half3x2
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <6 x half> @llvm.pow.v6f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <6 x float> @llvm.pow.v6f32
+half3x2 test_pow_half3x2 (half3x2 p0, half3x2 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half3x3
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <9 x half> @llvm.pow.v9f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <9 x float> @llvm.pow.v9f32
+half3x3 test_pow_half3x3 (half3x3 p0, half3x3 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half3x4
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <12 x half> @llvm.pow.v12f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <12 x float> @llvm.pow.v12f32
+half3x4 test_pow_half3x4 (half3x4 p0, half3x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half4x1
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.pow.v4f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.pow.v4f32
+half4x1 test_pow_half4x1 (half4x1 p0, half4x1 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half4x2
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <8 x half> @llvm.pow.v8f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <8 x float> @llvm.pow.v8f32
+half4x2 test_pow_half4x2 (half4x2 p0, half4x2 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half4x3
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <12 x half> @llvm.pow.v12f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <12 x float> @llvm.pow.v12f32
+half4x3 test_pow_half4x3 (half4x3 p0, half4x3 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_half4x4
+// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <16 x half> @llvm.pow.v16f16
+// NO_HALF: call reassoc nnan ninf nsz arcp afn <16 x float> @llvm.pow.v16f32
+half4x4 test_pow_half4x4 (half4x4 p0, half4x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float1x2
+// CHECK:  call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.pow.v2f32
+float1x2 test_pow_float1x2 (float1x2 p0, float1x2 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float1x3
+// CHECK:  call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.pow.v3f32
+float1x3 test_pow_float1x3 (float1x3 p0, float1x3 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float1x4
+// CHECK:  call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.pow.v4f32
+float1x4 test_pow_float1x4 (float1x4 p0, float1x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float2x1
+// CHECK:  call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.pow.v2f32
+float2x1 test_pow_float2x1 (float2x1 p0, float2x1 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float2x2
+// CHECK:  call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.pow.v4f32
+float2x2 test_pow_float2x2 (float2x2 p0, float2x2 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float2x3
+// CHECK:  call reassoc nnan ninf nsz arcp afn <6 x float> @llvm.pow.v6f32
+float2x3 test_pow_float2x3 (float2x3 p0, float2x3 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float2x4
+// CHECK:  call reassoc nnan ninf nsz arcp afn <8 x float> @llvm.pow.v8f32
+float2x4 test_pow_float2x4 (float2x4 p0, float2x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float3x1
+// CHECK:  call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.pow.v3f32
+float3x1 test_pow_float3x1 (float3x1 p0, float3x1 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float3x2
+// CHECK:  call reassoc nnan ninf nsz arcp afn <6 x float> @llvm.pow.v6f32
+float3x2 test_pow_float3x2 (float3x2 p0, float3x2 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float3x3
+// CHECK:  call reassoc nnan ninf nsz arcp afn <9 x float> @llvm.pow.v9f32
+float3x3 test_pow_float3x3 (float3x3 p0, float3x3 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float3x4
+// CHECK:  call reassoc nnan ninf nsz arcp afn <12 x float> @llvm.pow.v12f32
+float3x4 test_pow_float3x4 (float3x4 p0, float3x4 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float4x1
+// CHECK:  call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.pow.v4f32
+float4x1 test_pow_float4x1 (float4x1 p0, float4x1 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float4x2
+// CHECK:  call reassoc nnan ninf nsz arcp afn <8 x float> @llvm.pow.v8f32
+float4x2 test_pow_float4x2 (float4x2 p0, float4x2 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float4x3
+// CHECK:  call reassoc nnan ninf nsz arcp afn <12 x float> @llvm.pow.v12f32
+float4x3 test_pow_float4x3 (float4x3 p0, float4x3 p1) {
+  return pow(p0, p1);
+}
+
+// CHECK-LABEL: test_pow_float4x4
+// CHECK:  call reassoc nnan ninf nsz arcp afn <16 x float> @llvm.pow.v16f32
+float4x4 test_pow_float4x4 (float4x4 p0, float4x4 p1) {
+  return pow(p0, p1);
+}
+
diff --git a/clang/test/SemaHLSL/BuiltIns/binary-compat-overload-warnings.hlsl b/clang/test/SemaHLSL/BuiltIns/binary-compat-overload-warnings.hlsl
index e798acbf67dd2..d521e7f7dd5c0 100644
--- a/clang/test/SemaHLSL/BuiltIns/binary-compat-overload-warnings.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/binary-compat-overload-warnings.hlsl
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -finclude-default-header -triple dxilv1.0-unknown-shadermodel6.0-library -std=hlsl202x -emit-llvm-only -disable-llvm-passes -DFUNC=atan2 %s 2>&1 | FileCheck %s -DFUNC=atan2 --check-prefixes=CHECK,CHECK-MAT
-// RUN: %clang_cc1 -finclude-default-header -triple dxilv1.0-unknown-shadermodel6.0-library -std=hlsl202x -emit-llvm-only -disable-llvm-passes -DFUNC=pow %s 2>&1 | FileCheck %s -DFUNC=pow
+// RUN: %clang_cc1 -finclude-default-header -triple dxilv1.0-unknown-shadermodel6.0-library -std=hlsl202x -emit-llvm-only -disable-llvm-passes -DFUNC=pow %s 2>&1 | FileCheck %s -DFUNC=pow --check-prefixes=CHECK,CHECK-MAT
 // RUN: %clang_cc1 -finclude-default-header -triple dxilv1.0-unknown-shadermodel6.0-library -std=hlsl202x -emit-llvm-only -disable-llvm-passes -DFUNC=step %s 2>&1 | FileCheck %s -DFUNC=step
 
 // binary double overloads
diff --git a/clang/test/SemaHLSL/BuiltIns/pow_mat-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/pow_mat-errors.hlsl
new file mode 100644
index 0000000000000..ca01f8ee70214
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/pow_mat-errors.hlsl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -fnative-int16-type -emit-llvm-only -disable-llvm-passes -verify
+
+
+double2x2 test_vec_double_builtin(double2x2 p0, double2x2 p1) {
+    return __builtin_elementwise_pow(p0, p1);
+  // expected-error at -1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'double2x2' (aka 'matrix<double, 2, 2>'))}}
+}
diff --git a/llvm/test/CodeGen/DirectX/pow_mat.ll b/llvm/test/CodeGen/DirectX/pow_mat.ll
new file mode 100644
index 0000000000000..cf095a60d51de
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/pow_mat.ll
@@ -0,0 +1,47 @@
+; RUN: opt -S -dxil-intrinsic-expansion -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=EXPCHECK
+; RUN: opt -S -dxil-intrinsic-expansion -scalarizer -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=DOPCHECK
+
+; Make sure correct dxil expansions for pow are generated for float and half.
+
+define noundef <16 x half> @pow_half4x4(<16 x half> noundef %a, <16 x half> noundef %b) {
+entry:
+; Just Expansion, no scalarization or lowering:
+; EXPCHECK: [[LOG2:%.+]] = call <16 x half> @llvm.log2.v16f16(<16 x half> %a)
+; EXPCHECK: [[MUL:%.+]] = fmul <16 x half> [[LOG2]], %b
+; EXPCHECK: [[EXP2:%.+]] = call <16 x half> @llvm.exp2.v16f16(<16 x half> [[MUL]])
+; EXPCHECK: ret <16 x half> [[EXP2]]
+
+; Scalarization occurs after expansion, so log2/exp2 scalarization is tested separately.
+; Expansion, scalarization and lowering:
+; Just make sure this expands to exactly 16 scalar DXIL log2 (OpCode=23) and 16 scalar DXIL exp2 (OpCode=21) calls.
+; DOPCHECK-COUNT-16: call half @dx.op.unary.f16(i32 23, half %{{.*}})
+; DOPCHECK-NOT: call half @dx.op.unary.f16(i32 23,
+; DOPCHECK-COUNT-16: call half @dx.op.unary.f16(i32 21, half %{{.*}})
+; DOPCHECK-NOT: call half @dx.op.unary.f16(i32 21,
+
+  %elt.pow = call <16 x half> @llvm.pow.v16f16(<16 x half> %a, <16 x half> %b)
+  ret <16 x half> %elt.pow
+}
+
+define noundef <16 x float> @pow_float4x4(<16 x float> noundef %a, <16 x float> noundef %b) {
+entry:
+; Just Expansion, no scalarization or lowering:
+; EXPCHECK: [[LOG2:%.+]] = call <16 x float> @llvm.log2.v16f32(<16 x float> %a)
+; EXPCHECK: [[MUL:%.+]] = fmul <16 x float> [[LOG2]], %b
+; EXPCHECK: [[EXP2:%.+]] = call <16 x float> @llvm.exp2.v16f32(<16 x float> [[MUL]])
+; EXPCHECK: ret <16 x float> [[EXP2]]
+
+; Scalarization occurs after expansion, so log2/exp2 scalarization is tested separately.
+; Expansion, scalarization and lowering:
+; Just make sure this expands to exactly 16 scalar DXIL log2 (OpCode=23) and 16 scalar DXIL exp2 (OpCode=21) calls.
+; DOPCHECK-COUNT-16: call float @dx.op.unary.f32(i32 23, float %{{.*}})
+; DOPCHECK-NOT: call float @dx.op.unary.f32(i32 23,
+; DOPCHECK-COUNT-16: call float @dx.op.unary.f32(i32 21, float %{{.*}})
+; DOPCHECK-NOT: call float @dx.op.unary.f32(i32 21,
+
+  %elt.pow = call <16 x float> @llvm.pow.v16f32(<16 x float> %a, <16 x float> %b)
+  ret <16 x float> %elt.pow
+}
+
+declare <16 x half> @llvm.pow.v16f16(<16 x half>, <16 x half>)
+declare <16 x float> @llvm.pow.v16f32(<16 x float>, <16 x float>)
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pow_mat.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pow_mat.ll
new file mode 100644
index 0000000000000..777017ecc6efc
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/pow_mat.ll
@@ -0,0 +1,551 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %}
+
+; Vulkan/Shader does not allow the Vector16 capability, so an MxN HLSL matrix
+; is represented as [M x <N x float>] in LLVM IR and elementwise pow is
+; computed per-row as M OpExtInst Pow calls on <N x float> (and similarly
+; for half). Matrices with N=3 exercise the legalizer's handling of
+; non-power-of-2 vector widths (legal for shader via allShaderFloatVectors).
+
+; CHECK-NOT: OpCapability Vector16
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
+; CHECK-DAG: %[[#void:]] = OpTypeVoid
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+; CHECK-DAG: %[[#vec3_float_32:]] = OpTypeVector %[[#float_32]] 3
+; CHECK-DAG: %[[#vec3_float_16:]] = OpTypeVector %[[#float_16]] 3
+; CHECK-DAG: %[[#vec2_float_32:]] = OpTypeVector %[[#float_32]] 2
+; CHECK-DAG: %[[#vec2_float_16:]] = OpTypeVector %[[#float_16]] 2
+; CHECK-DAG: %[[#int_32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#const_0:]] = OpConstant %[[#int_32]] 0
+; CHECK-DAG: %[[#const_1:]] = OpConstant %[[#int_32]] 1
+; CHECK-DAG: %[[#const_2:]] = OpConstant %[[#int_32]] 2
+; CHECK-DAG: %[[#const_3:]] = OpConstant %[[#int_32]] 3
+; CHECK-DAG: %[[#const_4:]] = OpConstant %[[#int_32]] 4
+; CHECK-DAG: %[[#arr_f32:]] = OpTypeArray %[[#vec4_float_32]] %[[#const_4]]
+; CHECK-DAG: %[[#arr_f16:]] = OpTypeArray %[[#vec4_float_16]] %[[#const_4]]
+; CHECK-DAG: %[[#arr3_f32:]] = OpTypeArray %[[#vec3_float_32]] %[[#const_3]]
+; CHECK-DAG: %[[#arr3_f16:]] = OpTypeArray %[[#vec3_float_16]] %[[#const_3]]
+; CHECK-DAG: %[[#ptr_arr_f32:]] = OpTypePointer Private %[[#arr_f32]]
+; CHECK-DAG: %[[#ptr_arr_f16:]] = OpTypePointer Private %[[#arr_f16]]
+; CHECK-DAG: %[[#ptr_arr3_f32:]] = OpTypePointer Private %[[#arr3_f32]]
+; CHECK-DAG: %[[#ptr_arr3_f16:]] = OpTypePointer Private %[[#arr3_f16]]
+; CHECK-DAG: %[[#ptr_vec4_f32:]] = OpTypePointer Private %[[#vec4_float_32]]
+; CHECK-DAG: %[[#ptr_vec4_f16:]] = OpTypePointer Private %[[#vec4_float_16]]
+; CHECK-DAG: %[[#ptr_vec3_f32:]] = OpTypePointer Private %[[#vec3_float_32]]
+; CHECK-DAG: %[[#ptr_vec3_f16:]] = OpTypePointer Private %[[#vec3_float_16]]
+; CHECK-DAG: %[[#fn_f32:]] = OpTypeFunction %[[#void]] %[[#ptr_arr_f32]] %[[#ptr_arr_f32]] %[[#ptr_arr_f32]]
+; CHECK-DAG: %[[#fn_f16:]] = OpTypeFunction %[[#void]] %[[#ptr_arr_f16]] %[[#ptr_arr_f16]] %[[#ptr_arr_f16]]
+; CHECK-DAG: %[[#fn3_f32:]] = OpTypeFunction %[[#void]] %[[#ptr_arr3_f32]] %[[#ptr_arr3_f32]] %[[#ptr_arr3_f32]]
+; CHECK-DAG: %[[#fn3_f16:]] = OpTypeFunction %[[#void]] %[[#ptr_arr3_f16]] %[[#ptr_arr3_f16]] %[[#ptr_arr3_f16]]
+
+define internal void @pow_float4x4(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None %[[#fn_f32]]
+  ; CHECK: %[[#out_f32:]] = OpFunctionParameter %[[#ptr_arr_f32]]
+  ; CHECK: %[[#a_f32:]] = OpFunctionParameter %[[#ptr_arr_f32]]
+  ; CHECK: %[[#b_f32:]] = OpFunctionParameter %[[#ptr_arr_f32]]
+  ; CHECK: %[[#a0_ptr_f32:]] = OpAccessChain %[[#ptr_vec4_f32]] %[[#a_f32]] %[[#const_0]]
+  ; CHECK: %[[#a1_ptr_f32:]] = OpAccessChain %[[#ptr_vec4_f32]] %[[#a_f32]] %[[#const_1]]
+  ; CHECK: %[[#a2_ptr_f32:]] = OpAccessChain %[[#ptr_vec4_f32]] %[[#a_f32]] %[[#const_2]]
+  ; CHECK: %[[#a3_ptr_f32:]] = OpAccessChain %[[#ptr_vec4_f32]] %[[#a_f32]] %[[#const_3]]
+  ; CHECK: %[[#b0_ptr_f32:]] = OpAccessChain %[[#ptr_vec4_f32]] %[[#b_f32]] %[[#const_0]]
+  ; CHECK: %[[#b1_ptr_f32:]] = OpAccessChain %[[#ptr_vec4_f32]] %[[#b_f32]] %[[#const_1]]
+  ; CHECK: %[[#b2_ptr_f32:]] = OpAccessChain %[[#ptr_vec4_f32]] %[[#b_f32]] %[[#const_2]]
+  ; CHECK: %[[#b3_ptr_f32:]] = OpAccessChain %[[#ptr_vec4_f32]] %[[#b_f32]] %[[#const_3]]
+  ; CHECK: %[[#a0_f32:]] = OpLoad %[[#vec4_float_32]] %[[#a0_ptr_f32]]
+  ; CHECK: %[[#a1_f32:]] = OpLoad %[[#vec4_float_32]] %[[#a1_ptr_f32]]
+  ; CHECK: %[[#a2_f32:]] = OpLoad %[[#vec4_float_32]] %[[#a2_ptr_f32]]
+  ; CHECK: %[[#a3_f32:]] = OpLoad %[[#vec4_float_32]] %[[#a3_ptr_f32]]
+  ; CHECK: %[[#b0_f32:]] = OpLoad %[[#vec4_float_32]] %[[#b0_ptr_f32]]
+  ; CHECK: %[[#b1_f32:]] = OpLoad %[[#vec4_float_32]] %[[#b1_ptr_f32]]
+  ; CHECK: %[[#b2_f32:]] = OpLoad %[[#vec4_float_32]] %[[#b2_ptr_f32]]
+  ; CHECK: %[[#b3_f32:]] = OpLoad %[[#vec4_float_32]] %[[#b3_ptr_f32]]
+  ; CHECK: OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Pow %[[#a0_f32]] %[[#b0_f32]]
+  ; CHECK: OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Pow %[[#a1_f32]] %[[#b1_f32]]
+  ; CHECK: OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Pow %[[#a2_f32]] %[[#b2_f32]]
+  ; CHECK: OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Pow %[[#a3_f32]] %[[#b3_f32]]
+  %a0 = getelementptr [4 x <4 x float>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [4 x <4 x float>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [4 x <4 x float>], ptr addrspace(10) %a, i32 0, i32 2
+  %a3 = getelementptr [4 x <4 x float>], ptr addrspace(10) %a, i32 0, i32 3
+  %b0 = getelementptr [4 x <4 x float>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [4 x <4 x float>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [4 x <4 x float>], ptr addrspace(10) %b, i32 0, i32 2
+  %b3 = getelementptr [4 x <4 x float>], ptr addrspace(10) %b, i32 0, i32 3
+  %va0 = load <4 x float>, ptr addrspace(10) %a0
+  %va1 = load <4 x float>, ptr addrspace(10) %a1
+  %va2 = load <4 x float>, ptr addrspace(10) %a2
+  %va3 = load <4 x float>, ptr addrspace(10) %a3
+  %vb0 = load <4 x float>, ptr addrspace(10) %b0
+  %vb1 = load <4 x float>, ptr addrspace(10) %b1
+  %vb2 = load <4 x float>, ptr addrspace(10) %b2
+  %vb3 = load <4 x float>, ptr addrspace(10) %b3
+  %r0 = call <4 x float> @llvm.pow.v4f32(<4 x float> %va0, <4 x float> %vb0)
+  %r1 = call <4 x float> @llvm.pow.v4f32(<4 x float> %va1, <4 x float> %vb1)
+  %r2 = call <4 x float> @llvm.pow.v4f32(<4 x float> %va2, <4 x float> %vb2)
+  %r3 = call <4 x float> @llvm.pow.v4f32(<4 x float> %va3, <4 x float> %vb3)
+  %out0 = getelementptr [4 x <4 x float>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [4 x <4 x float>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [4 x <4 x float>], ptr addrspace(10) %out, i32 0, i32 2
+  %out3 = getelementptr [4 x <4 x float>], ptr addrspace(10) %out, i32 0, i32 3
+  store <4 x float> %r0, ptr addrspace(10) %out0
+  store <4 x float> %r1, ptr addrspace(10) %out1
+  store <4 x float> %r2, ptr addrspace(10) %out2
+  store <4 x float> %r3, ptr addrspace(10) %out3
+  ret void
+}
+
+define internal void @pow_half4x4(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None %[[#fn_f16]]
+  ; CHECK: %[[#out_f16:]] = OpFunctionParameter %[[#ptr_arr_f16]]
+  ; CHECK: %[[#a_f16:]] = OpFunctionParameter %[[#ptr_arr_f16]]
+  ; CHECK: %[[#b_f16:]] = OpFunctionParameter %[[#ptr_arr_f16]]
+  ; CHECK: %[[#a0_ptr_f16:]] = OpAccessChain %[[#ptr_vec4_f16]] %[[#a_f16]] %[[#const_0]]
+  ; CHECK: %[[#a1_ptr_f16:]] = OpAccessChain %[[#ptr_vec4_f16]] %[[#a_f16]] %[[#const_1]]
+  ; CHECK: %[[#a2_ptr_f16:]] = OpAccessChain %[[#ptr_vec4_f16]] %[[#a_f16]] %[[#const_2]]
+  ; CHECK: %[[#a3_ptr_f16:]] = OpAccessChain %[[#ptr_vec4_f16]] %[[#a_f16]] %[[#const_3]]
+  ; CHECK: %[[#b0_ptr_f16:]] = OpAccessChain %[[#ptr_vec4_f16]] %[[#b_f16]] %[[#const_0]]
+  ; CHECK: %[[#b1_ptr_f16:]] = OpAccessChain %[[#ptr_vec4_f16]] %[[#b_f16]] %[[#const_1]]
+  ; CHECK: %[[#b2_ptr_f16:]] = OpAccessChain %[[#ptr_vec4_f16]] %[[#b_f16]] %[[#const_2]]
+  ; CHECK: %[[#b3_ptr_f16:]] = OpAccessChain %[[#ptr_vec4_f16]] %[[#b_f16]] %[[#const_3]]
+  ; CHECK: %[[#a0_f16:]] = OpLoad %[[#vec4_float_16]] %[[#a0_ptr_f16]]
+  ; CHECK: %[[#a1_f16:]] = OpLoad %[[#vec4_float_16]] %[[#a1_ptr_f16]]
+  ; CHECK: %[[#a2_f16:]] = OpLoad %[[#vec4_float_16]] %[[#a2_ptr_f16]]
+  ; CHECK: %[[#a3_f16:]] = OpLoad %[[#vec4_float_16]] %[[#a3_ptr_f16]]
+  ; CHECK: %[[#b0_f16:]] = OpLoad %[[#vec4_float_16]] %[[#b0_ptr_f16]]
+  ; CHECK: %[[#b1_f16:]] = OpLoad %[[#vec4_float_16]] %[[#b1_ptr_f16]]
+  ; CHECK: %[[#b2_f16:]] = OpLoad %[[#vec4_float_16]] %[[#b2_ptr_f16]]
+  ; CHECK: %[[#b3_f16:]] = OpLoad %[[#vec4_float_16]] %[[#b3_ptr_f16]]
+  ; CHECK: OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Pow %[[#a0_f16]] %[[#b0_f16]]
+  ; CHECK: OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Pow %[[#a1_f16]] %[[#b1_f16]]
+  ; CHECK: OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Pow %[[#a2_f16]] %[[#b2_f16]]
+  ; CHECK: OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Pow %[[#a3_f16]] %[[#b3_f16]]
+  %a0 = getelementptr [4 x <4 x half>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [4 x <4 x half>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [4 x <4 x half>], ptr addrspace(10) %a, i32 0, i32 2
+  %a3 = getelementptr [4 x <4 x half>], ptr addrspace(10) %a, i32 0, i32 3
+  %b0 = getelementptr [4 x <4 x half>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [4 x <4 x half>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [4 x <4 x half>], ptr addrspace(10) %b, i32 0, i32 2
+  %b3 = getelementptr [4 x <4 x half>], ptr addrspace(10) %b, i32 0, i32 3
+  %va0 = load <4 x half>, ptr addrspace(10) %a0
+  %va1 = load <4 x half>, ptr addrspace(10) %a1
+  %va2 = load <4 x half>, ptr addrspace(10) %a2
+  %va3 = load <4 x half>, ptr addrspace(10) %a3
+  %vb0 = load <4 x half>, ptr addrspace(10) %b0
+  %vb1 = load <4 x half>, ptr addrspace(10) %b1
+  %vb2 = load <4 x half>, ptr addrspace(10) %b2
+  %vb3 = load <4 x half>, ptr addrspace(10) %b3
+  %r0 = call <4 x half> @llvm.pow.v4f16(<4 x half> %va0, <4 x half> %vb0)
+  %r1 = call <4 x half> @llvm.pow.v4f16(<4 x half> %va1, <4 x half> %vb1)
+  %r2 = call <4 x half> @llvm.pow.v4f16(<4 x half> %va2, <4 x half> %vb2)
+  %r3 = call <4 x half> @llvm.pow.v4f16(<4 x half> %va3, <4 x half> %vb3)
+  %out0 = getelementptr [4 x <4 x half>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [4 x <4 x half>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [4 x <4 x half>], ptr addrspace(10) %out, i32 0, i32 2
+  %out3 = getelementptr [4 x <4 x half>], ptr addrspace(10) %out, i32 0, i32 3
+  store <4 x half> %r0, ptr addrspace(10) %out0
+  store <4 x half> %r1, ptr addrspace(10) %out1
+  store <4 x half> %r2, ptr addrspace(10) %out2
+  store <4 x half> %r3, ptr addrspace(10) %out3
+  ret void
+}
+
+define internal void @pow_float3x3(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None %[[#fn3_f32]]
+  ; CHECK: %[[#out3_f32:]] = OpFunctionParameter %[[#ptr_arr3_f32]]
+  ; CHECK: %[[#a3v_f32:]] = OpFunctionParameter %[[#ptr_arr3_f32]]
+  ; CHECK: %[[#b3v_f32:]] = OpFunctionParameter %[[#ptr_arr3_f32]]
+  ; CHECK: %[[#a3v0_ptr_f32:]] = OpAccessChain %[[#ptr_vec3_f32]] %[[#a3v_f32]] %[[#const_0]]
+  ; CHECK: %[[#a3v1_ptr_f32:]] = OpAccessChain %[[#ptr_vec3_f32]] %[[#a3v_f32]] %[[#const_1]]
+  ; CHECK: %[[#a3v2_ptr_f32:]] = OpAccessChain %[[#ptr_vec3_f32]] %[[#a3v_f32]] %[[#const_2]]
+  ; CHECK: %[[#b3v0_ptr_f32:]] = OpAccessChain %[[#ptr_vec3_f32]] %[[#b3v_f32]] %[[#const_0]]
+  ; CHECK: %[[#b3v1_ptr_f32:]] = OpAccessChain %[[#ptr_vec3_f32]] %[[#b3v_f32]] %[[#const_1]]
+  ; CHECK: %[[#b3v2_ptr_f32:]] = OpAccessChain %[[#ptr_vec3_f32]] %[[#b3v_f32]] %[[#const_2]]
+  ; CHECK: %[[#a3v0_f32:]] = OpLoad %[[#vec3_float_32]] %[[#a3v0_ptr_f32]]
+  ; CHECK: %[[#a3v1_f32:]] = OpLoad %[[#vec3_float_32]] %[[#a3v1_ptr_f32]]
+  ; CHECK: %[[#a3v2_f32:]] = OpLoad %[[#vec3_float_32]] %[[#a3v2_ptr_f32]]
+  ; CHECK: %[[#b3v0_f32:]] = OpLoad %[[#vec3_float_32]] %[[#b3v0_ptr_f32]]
+  ; CHECK: %[[#b3v1_f32:]] = OpLoad %[[#vec3_float_32]] %[[#b3v1_ptr_f32]]
+  ; CHECK: %[[#b3v2_f32:]] = OpLoad %[[#vec3_float_32]] %[[#b3v2_ptr_f32]]
+  ; CHECK: OpExtInst %[[#vec3_float_32]] %[[#op_ext_glsl]] Pow %[[#a3v0_f32]] %[[#b3v0_f32]]
+  ; CHECK: OpExtInst %[[#vec3_float_32]] %[[#op_ext_glsl]] Pow %[[#a3v1_f32]] %[[#b3v1_f32]]
+  ; CHECK: OpExtInst %[[#vec3_float_32]] %[[#op_ext_glsl]] Pow %[[#a3v2_f32]] %[[#b3v2_f32]]
+  %a0 = getelementptr [3 x <3 x float>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [3 x <3 x float>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [3 x <3 x float>], ptr addrspace(10) %a, i32 0, i32 2
+  %b0 = getelementptr [3 x <3 x float>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [3 x <3 x float>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [3 x <3 x float>], ptr addrspace(10) %b, i32 0, i32 2
+  %va0 = load <3 x float>, ptr addrspace(10) %a0
+  %va1 = load <3 x float>, ptr addrspace(10) %a1
+  %va2 = load <3 x float>, ptr addrspace(10) %a2
+  %vb0 = load <3 x float>, ptr addrspace(10) %b0
+  %vb1 = load <3 x float>, ptr addrspace(10) %b1
+  %vb2 = load <3 x float>, ptr addrspace(10) %b2
+  %r0 = call <3 x float> @llvm.pow.v3f32(<3 x float> %va0, <3 x float> %vb0)
+  %r1 = call <3 x float> @llvm.pow.v3f32(<3 x float> %va1, <3 x float> %vb1)
+  %r2 = call <3 x float> @llvm.pow.v3f32(<3 x float> %va2, <3 x float> %vb2)
+  %out0 = getelementptr [3 x <3 x float>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [3 x <3 x float>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [3 x <3 x float>], ptr addrspace(10) %out, i32 0, i32 2
+  store <3 x float> %r0, ptr addrspace(10) %out0
+  store <3 x float> %r1, ptr addrspace(10) %out1
+  store <3 x float> %r2, ptr addrspace(10) %out2
+  ret void
+}
+
+define internal void @pow_half3x3(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None %[[#fn3_f16]]
+  ; CHECK: %[[#out3_f16:]] = OpFunctionParameter %[[#ptr_arr3_f16]]
+  ; CHECK: %[[#a3v_f16:]] = OpFunctionParameter %[[#ptr_arr3_f16]]
+  ; CHECK: %[[#b3v_f16:]] = OpFunctionParameter %[[#ptr_arr3_f16]]
+  ; CHECK: %[[#a3v0_ptr_f16:]] = OpAccessChain %[[#ptr_vec3_f16]] %[[#a3v_f16]] %[[#const_0]]
+  ; CHECK: %[[#a3v1_ptr_f16:]] = OpAccessChain %[[#ptr_vec3_f16]] %[[#a3v_f16]] %[[#const_1]]
+  ; CHECK: %[[#a3v2_ptr_f16:]] = OpAccessChain %[[#ptr_vec3_f16]] %[[#a3v_f16]] %[[#const_2]]
+  ; CHECK: %[[#b3v0_ptr_f16:]] = OpAccessChain %[[#ptr_vec3_f16]] %[[#b3v_f16]] %[[#const_0]]
+  ; CHECK: %[[#b3v1_ptr_f16:]] = OpAccessChain %[[#ptr_vec3_f16]] %[[#b3v_f16]] %[[#const_1]]
+  ; CHECK: %[[#b3v2_ptr_f16:]] = OpAccessChain %[[#ptr_vec3_f16]] %[[#b3v_f16]] %[[#const_2]]
+  ; CHECK: %[[#a3v0_f16:]] = OpLoad %[[#vec3_float_16]] %[[#a3v0_ptr_f16]]
+  ; CHECK: %[[#a3v1_f16:]] = OpLoad %[[#vec3_float_16]] %[[#a3v1_ptr_f16]]
+  ; CHECK: %[[#a3v2_f16:]] = OpLoad %[[#vec3_float_16]] %[[#a3v2_ptr_f16]]
+  ; CHECK: %[[#b3v0_f16:]] = OpLoad %[[#vec3_float_16]] %[[#b3v0_ptr_f16]]
+  ; CHECK: %[[#b3v1_f16:]] = OpLoad %[[#vec3_float_16]] %[[#b3v1_ptr_f16]]
+  ; CHECK: %[[#b3v2_f16:]] = OpLoad %[[#vec3_float_16]] %[[#b3v2_ptr_f16]]
+  ; CHECK: OpExtInst %[[#vec3_float_16]] %[[#op_ext_glsl]] Pow %[[#a3v0_f16]] %[[#b3v0_f16]]
+  ; CHECK: OpExtInst %[[#vec3_float_16]] %[[#op_ext_glsl]] Pow %[[#a3v1_f16]] %[[#b3v1_f16]]
+  ; CHECK: OpExtInst %[[#vec3_float_16]] %[[#op_ext_glsl]] Pow %[[#a3v2_f16]] %[[#b3v2_f16]]
+  %a0 = getelementptr [3 x <3 x half>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [3 x <3 x half>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [3 x <3 x half>], ptr addrspace(10) %a, i32 0, i32 2
+  %b0 = getelementptr [3 x <3 x half>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [3 x <3 x half>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [3 x <3 x half>], ptr addrspace(10) %b, i32 0, i32 2
+  %va0 = load <3 x half>, ptr addrspace(10) %a0
+  %va1 = load <3 x half>, ptr addrspace(10) %a1
+  %va2 = load <3 x half>, ptr addrspace(10) %a2
+  %vb0 = load <3 x half>, ptr addrspace(10) %b0
+  %vb1 = load <3 x half>, ptr addrspace(10) %b1
+  %vb2 = load <3 x half>, ptr addrspace(10) %b2
+  %r0 = call <3 x half> @llvm.pow.v3f16(<3 x half> %va0, <3 x half> %vb0)
+  %r1 = call <3 x half> @llvm.pow.v3f16(<3 x half> %va1, <3 x half> %vb1)
+  %r2 = call <3 x half> @llvm.pow.v3f16(<3 x half> %va2, <3 x half> %vb2)
+  %out0 = getelementptr [3 x <3 x half>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [3 x <3 x half>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [3 x <3 x half>], ptr addrspace(10) %out, i32 0, i32 2
+  store <3 x half> %r0, ptr addrspace(10) %out0
+  store <3 x half> %r1, ptr addrspace(10) %out1
+  store <3 x half> %r2, ptr addrspace(10) %out2
+  ret void
+}
+
+define internal void @pow_float2x2(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-2: OpExtInst %[[#vec2_float_32]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [2 x <2 x float>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [2 x <2 x float>], ptr addrspace(10) %a, i32 0, i32 1
+  %b0 = getelementptr [2 x <2 x float>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [2 x <2 x float>], ptr addrspace(10) %b, i32 0, i32 1
+  %va0 = load <2 x float>, ptr addrspace(10) %a0
+  %va1 = load <2 x float>, ptr addrspace(10) %a1
+  %vb0 = load <2 x float>, ptr addrspace(10) %b0
+  %vb1 = load <2 x float>, ptr addrspace(10) %b1
+  %r0 = call <2 x float> @llvm.pow.v2f32(<2 x float> %va0, <2 x float> %vb0)
+  %r1 = call <2 x float> @llvm.pow.v2f32(<2 x float> %va1, <2 x float> %vb1)
+  %out0 = getelementptr [2 x <2 x float>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [2 x <2 x float>], ptr addrspace(10) %out, i32 0, i32 1
+  store <2 x float> %r0, ptr addrspace(10) %out0
+  store <2 x float> %r1, ptr addrspace(10) %out1
+  ret void
+}
+
+define internal void @pow_half2x2(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-2: OpExtInst %[[#vec2_float_16]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [2 x <2 x half>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [2 x <2 x half>], ptr addrspace(10) %a, i32 0, i32 1
+  %b0 = getelementptr [2 x <2 x half>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [2 x <2 x half>], ptr addrspace(10) %b, i32 0, i32 1
+  %va0 = load <2 x half>, ptr addrspace(10) %a0
+  %va1 = load <2 x half>, ptr addrspace(10) %a1
+  %vb0 = load <2 x half>, ptr addrspace(10) %b0
+  %vb1 = load <2 x half>, ptr addrspace(10) %b1
+  %r0 = call <2 x half> @llvm.pow.v2f16(<2 x half> %va0, <2 x half> %vb0)
+  %r1 = call <2 x half> @llvm.pow.v2f16(<2 x half> %va1, <2 x half> %vb1)
+  %out0 = getelementptr [2 x <2 x half>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [2 x <2 x half>], ptr addrspace(10) %out, i32 0, i32 1
+  store <2 x half> %r0, ptr addrspace(10) %out0
+  store <2 x half> %r1, ptr addrspace(10) %out1
+  ret void
+}
+
+; 2x3: 2 rows of <3 x float> — non-power-of-2 vector width.
+define internal void @pow_float2x3(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-2: OpExtInst %[[#vec3_float_32]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [2 x <3 x float>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [2 x <3 x float>], ptr addrspace(10) %a, i32 0, i32 1
+  %b0 = getelementptr [2 x <3 x float>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [2 x <3 x float>], ptr addrspace(10) %b, i32 0, i32 1
+  %va0 = load <3 x float>, ptr addrspace(10) %a0
+  %va1 = load <3 x float>, ptr addrspace(10) %a1
+  %vb0 = load <3 x float>, ptr addrspace(10) %b0
+  %vb1 = load <3 x float>, ptr addrspace(10) %b1
+  %r0 = call <3 x float> @llvm.pow.v3f32(<3 x float> %va0, <3 x float> %vb0)
+  %r1 = call <3 x float> @llvm.pow.v3f32(<3 x float> %va1, <3 x float> %vb1)
+  %out0 = getelementptr [2 x <3 x float>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [2 x <3 x float>], ptr addrspace(10) %out, i32 0, i32 1
+  store <3 x float> %r0, ptr addrspace(10) %out0
+  store <3 x float> %r1, ptr addrspace(10) %out1
+  ret void
+}
+
+define internal void @pow_half2x3(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-2: OpExtInst %[[#vec3_float_16]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [2 x <3 x half>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [2 x <3 x half>], ptr addrspace(10) %a, i32 0, i32 1
+  %b0 = getelementptr [2 x <3 x half>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [2 x <3 x half>], ptr addrspace(10) %b, i32 0, i32 1
+  %va0 = load <3 x half>, ptr addrspace(10) %a0
+  %va1 = load <3 x half>, ptr addrspace(10) %a1
+  %vb0 = load <3 x half>, ptr addrspace(10) %b0
+  %vb1 = load <3 x half>, ptr addrspace(10) %b1
+  %r0 = call <3 x half> @llvm.pow.v3f16(<3 x half> %va0, <3 x half> %vb0)
+  %r1 = call <3 x half> @llvm.pow.v3f16(<3 x half> %va1, <3 x half> %vb1)
+  %out0 = getelementptr [2 x <3 x half>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [2 x <3 x half>], ptr addrspace(10) %out, i32 0, i32 1
+  store <3 x half> %r0, ptr addrspace(10) %out0
+  store <3 x half> %r1, ptr addrspace(10) %out1
+  ret void
+}
+
+define internal void @pow_float3x2(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-3: OpExtInst %[[#vec2_float_32]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [3 x <2 x float>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [3 x <2 x float>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [3 x <2 x float>], ptr addrspace(10) %a, i32 0, i32 2
+  %b0 = getelementptr [3 x <2 x float>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [3 x <2 x float>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [3 x <2 x float>], ptr addrspace(10) %b, i32 0, i32 2
+  %va0 = load <2 x float>, ptr addrspace(10) %a0
+  %va1 = load <2 x float>, ptr addrspace(10) %a1
+  %va2 = load <2 x float>, ptr addrspace(10) %a2
+  %vb0 = load <2 x float>, ptr addrspace(10) %b0
+  %vb1 = load <2 x float>, ptr addrspace(10) %b1
+  %vb2 = load <2 x float>, ptr addrspace(10) %b2
+  %r0 = call <2 x float> @llvm.pow.v2f32(<2 x float> %va0, <2 x float> %vb0)
+  %r1 = call <2 x float> @llvm.pow.v2f32(<2 x float> %va1, <2 x float> %vb1)
+  %r2 = call <2 x float> @llvm.pow.v2f32(<2 x float> %va2, <2 x float> %vb2)
+  %out0 = getelementptr [3 x <2 x float>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [3 x <2 x float>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [3 x <2 x float>], ptr addrspace(10) %out, i32 0, i32 2
+  store <2 x float> %r0, ptr addrspace(10) %out0
+  store <2 x float> %r1, ptr addrspace(10) %out1
+  store <2 x float> %r2, ptr addrspace(10) %out2
+  ret void
+}
+
+define internal void @pow_float2x4(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-2: OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [2 x <4 x float>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [2 x <4 x float>], ptr addrspace(10) %a, i32 0, i32 1
+  %b0 = getelementptr [2 x <4 x float>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [2 x <4 x float>], ptr addrspace(10) %b, i32 0, i32 1
+  %va0 = load <4 x float>, ptr addrspace(10) %a0
+  %va1 = load <4 x float>, ptr addrspace(10) %a1
+  %vb0 = load <4 x float>, ptr addrspace(10) %b0
+  %vb1 = load <4 x float>, ptr addrspace(10) %b1
+  %r0 = call <4 x float> @llvm.pow.v4f32(<4 x float> %va0, <4 x float> %vb0)
+  %r1 = call <4 x float> @llvm.pow.v4f32(<4 x float> %va1, <4 x float> %vb1)
+  %out0 = getelementptr [2 x <4 x float>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [2 x <4 x float>], ptr addrspace(10) %out, i32 0, i32 1
+  store <4 x float> %r0, ptr addrspace(10) %out0
+  store <4 x float> %r1, ptr addrspace(10) %out1
+  ret void
+}
+
+define internal void @pow_float4x2(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-4: OpExtInst %[[#vec2_float_32]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [4 x <2 x float>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [4 x <2 x float>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [4 x <2 x float>], ptr addrspace(10) %a, i32 0, i32 2
+  %a3 = getelementptr [4 x <2 x float>], ptr addrspace(10) %a, i32 0, i32 3
+  %b0 = getelementptr [4 x <2 x float>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [4 x <2 x float>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [4 x <2 x float>], ptr addrspace(10) %b, i32 0, i32 2
+  %b3 = getelementptr [4 x <2 x float>], ptr addrspace(10) %b, i32 0, i32 3
+  %va0 = load <2 x float>, ptr addrspace(10) %a0
+  %va1 = load <2 x float>, ptr addrspace(10) %a1
+  %va2 = load <2 x float>, ptr addrspace(10) %a2
+  %va3 = load <2 x float>, ptr addrspace(10) %a3
+  %vb0 = load <2 x float>, ptr addrspace(10) %b0
+  %vb1 = load <2 x float>, ptr addrspace(10) %b1
+  %vb2 = load <2 x float>, ptr addrspace(10) %b2
+  %vb3 = load <2 x float>, ptr addrspace(10) %b3
+  %r0 = call <2 x float> @llvm.pow.v2f32(<2 x float> %va0, <2 x float> %vb0)
+  %r1 = call <2 x float> @llvm.pow.v2f32(<2 x float> %va1, <2 x float> %vb1)
+  %r2 = call <2 x float> @llvm.pow.v2f32(<2 x float> %va2, <2 x float> %vb2)
+  %r3 = call <2 x float> @llvm.pow.v2f32(<2 x float> %va3, <2 x float> %vb3)
+  %out0 = getelementptr [4 x <2 x float>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [4 x <2 x float>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [4 x <2 x float>], ptr addrspace(10) %out, i32 0, i32 2
+  %out3 = getelementptr [4 x <2 x float>], ptr addrspace(10) %out, i32 0, i32 3
+  store <2 x float> %r0, ptr addrspace(10) %out0
+  store <2 x float> %r1, ptr addrspace(10) %out1
+  store <2 x float> %r2, ptr addrspace(10) %out2
+  store <2 x float> %r3, ptr addrspace(10) %out3
+  ret void
+}
+
+; 3x4: 3 rows of <4 x float>.
+define internal void @pow_float3x4(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-3: OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [3 x <4 x float>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [3 x <4 x float>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [3 x <4 x float>], ptr addrspace(10) %a, i32 0, i32 2
+  %b0 = getelementptr [3 x <4 x float>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [3 x <4 x float>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [3 x <4 x float>], ptr addrspace(10) %b, i32 0, i32 2
+  %va0 = load <4 x float>, ptr addrspace(10) %a0
+  %va1 = load <4 x float>, ptr addrspace(10) %a1
+  %va2 = load <4 x float>, ptr addrspace(10) %a2
+  %vb0 = load <4 x float>, ptr addrspace(10) %b0
+  %vb1 = load <4 x float>, ptr addrspace(10) %b1
+  %vb2 = load <4 x float>, ptr addrspace(10) %b2
+  %r0 = call <4 x float> @llvm.pow.v4f32(<4 x float> %va0, <4 x float> %vb0)
+  %r1 = call <4 x float> @llvm.pow.v4f32(<4 x float> %va1, <4 x float> %vb1)
+  %r2 = call <4 x float> @llvm.pow.v4f32(<4 x float> %va2, <4 x float> %vb2)
+  %out0 = getelementptr [3 x <4 x float>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [3 x <4 x float>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [3 x <4 x float>], ptr addrspace(10) %out, i32 0, i32 2
+  store <4 x float> %r0, ptr addrspace(10) %out0
+  store <4 x float> %r1, ptr addrspace(10) %out1
+  store <4 x float> %r2, ptr addrspace(10) %out2
+  ret void
+}
+
+define internal void @pow_half3x4(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-3: OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [3 x <4 x half>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [3 x <4 x half>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [3 x <4 x half>], ptr addrspace(10) %a, i32 0, i32 2
+  %b0 = getelementptr [3 x <4 x half>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [3 x <4 x half>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [3 x <4 x half>], ptr addrspace(10) %b, i32 0, i32 2
+  %va0 = load <4 x half>, ptr addrspace(10) %a0
+  %va1 = load <4 x half>, ptr addrspace(10) %a1
+  %va2 = load <4 x half>, ptr addrspace(10) %a2
+  %vb0 = load <4 x half>, ptr addrspace(10) %b0
+  %vb1 = load <4 x half>, ptr addrspace(10) %b1
+  %vb2 = load <4 x half>, ptr addrspace(10) %b2
+  %r0 = call <4 x half> @llvm.pow.v4f16(<4 x half> %va0, <4 x half> %vb0)
+  %r1 = call <4 x half> @llvm.pow.v4f16(<4 x half> %va1, <4 x half> %vb1)
+  %r2 = call <4 x half> @llvm.pow.v4f16(<4 x half> %va2, <4 x half> %vb2)
+  %out0 = getelementptr [3 x <4 x half>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [3 x <4 x half>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [3 x <4 x half>], ptr addrspace(10) %out, i32 0, i32 2
+  store <4 x half> %r0, ptr addrspace(10) %out0
+  store <4 x half> %r1, ptr addrspace(10) %out1
+  store <4 x half> %r2, ptr addrspace(10) %out2
+  ret void
+}
+
+; 4x3: 4 rows of <3 x float> — non-power-of-2 vector width.
+define internal void @pow_float4x3(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-4: OpExtInst %[[#vec3_float_32]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [4 x <3 x float>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [4 x <3 x float>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [4 x <3 x float>], ptr addrspace(10) %a, i32 0, i32 2
+  %a3 = getelementptr [4 x <3 x float>], ptr addrspace(10) %a, i32 0, i32 3
+  %b0 = getelementptr [4 x <3 x float>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [4 x <3 x float>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [4 x <3 x float>], ptr addrspace(10) %b, i32 0, i32 2
+  %b3 = getelementptr [4 x <3 x float>], ptr addrspace(10) %b, i32 0, i32 3
+  %va0 = load <3 x float>, ptr addrspace(10) %a0
+  %va1 = load <3 x float>, ptr addrspace(10) %a1
+  %va2 = load <3 x float>, ptr addrspace(10) %a2
+  %va3 = load <3 x float>, ptr addrspace(10) %a3
+  %vb0 = load <3 x float>, ptr addrspace(10) %b0
+  %vb1 = load <3 x float>, ptr addrspace(10) %b1
+  %vb2 = load <3 x float>, ptr addrspace(10) %b2
+  %vb3 = load <3 x float>, ptr addrspace(10) %b3
+  %r0 = call <3 x float> @llvm.pow.v3f32(<3 x float> %va0, <3 x float> %vb0)
+  %r1 = call <3 x float> @llvm.pow.v3f32(<3 x float> %va1, <3 x float> %vb1)
+  %r2 = call <3 x float> @llvm.pow.v3f32(<3 x float> %va2, <3 x float> %vb2)
+  %r3 = call <3 x float> @llvm.pow.v3f32(<3 x float> %va3, <3 x float> %vb3)
+  %out0 = getelementptr [4 x <3 x float>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [4 x <3 x float>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [4 x <3 x float>], ptr addrspace(10) %out, i32 0, i32 2
+  %out3 = getelementptr [4 x <3 x float>], ptr addrspace(10) %out, i32 0, i32 3
+  store <3 x float> %r0, ptr addrspace(10) %out0
+  store <3 x float> %r1, ptr addrspace(10) %out1
+  store <3 x float> %r2, ptr addrspace(10) %out2
+  store <3 x float> %r3, ptr addrspace(10) %out3
+  ret void
+}
+
+define internal void @pow_half4x3(ptr addrspace(10) %out, ptr addrspace(10) %a, ptr addrspace(10) %b) {
+entry:
+  ; CHECK: OpFunction %[[#void]] None
+  ; CHECK-COUNT-4: OpExtInst %[[#vec3_float_16]] %[[#op_ext_glsl]] Pow
+  %a0 = getelementptr [4 x <3 x half>], ptr addrspace(10) %a, i32 0, i32 0
+  %a1 = getelementptr [4 x <3 x half>], ptr addrspace(10) %a, i32 0, i32 1
+  %a2 = getelementptr [4 x <3 x half>], ptr addrspace(10) %a, i32 0, i32 2
+  %a3 = getelementptr [4 x <3 x half>], ptr addrspace(10) %a, i32 0, i32 3
+  %b0 = getelementptr [4 x <3 x half>], ptr addrspace(10) %b, i32 0, i32 0
+  %b1 = getelementptr [4 x <3 x half>], ptr addrspace(10) %b, i32 0, i32 1
+  %b2 = getelementptr [4 x <3 x half>], ptr addrspace(10) %b, i32 0, i32 2
+  %b3 = getelementptr [4 x <3 x half>], ptr addrspace(10) %b, i32 0, i32 3
+  %va0 = load <3 x half>, ptr addrspace(10) %a0
+  %va1 = load <3 x half>, ptr addrspace(10) %a1
+  %va2 = load <3 x half>, ptr addrspace(10) %a2
+  %va3 = load <3 x half>, ptr addrspace(10) %a3
+  %vb0 = load <3 x half>, ptr addrspace(10) %b0
+  %vb1 = load <3 x half>, ptr addrspace(10) %b1
+  %vb2 = load <3 x half>, ptr addrspace(10) %b2
+  %vb3 = load <3 x half>, ptr addrspace(10) %b3
+  %r0 = call <3 x half> @llvm.pow.v3f16(<3 x half> %va0, <3 x half> %vb0)
+  %r1 = call <3 x half> @llvm.pow.v3f16(<3 x half> %va1, <3 x half> %vb1)
+  %r2 = call <3 x half> @llvm.pow.v3f16(<3 x half> %va2, <3 x half> %vb2)
+  %r3 = call <3 x half> @llvm.pow.v3f16(<3 x half> %va3, <3 x half> %vb3)
+  %out0 = getelementptr [4 x <3 x half>], ptr addrspace(10) %out, i32 0, i32 0
+  %out1 = getelementptr [4 x <3 x half>], ptr addrspace(10) %out, i32 0, i32 1
+  %out2 = getelementptr [4 x <3 x half>], ptr addrspace(10) %out, i32 0, i32 2
+  %out3 = getelementptr [4 x <3 x half>], ptr addrspace(10) %out, i32 0, i32 3
+  store <3 x half> %r0, ptr addrspace(10) %out0
+  store <3 x half> %r1, ptr addrspace(10) %out1
+  store <3 x half> %r2, ptr addrspace(10) %out2
+  store <3 x half> %r3, ptr addrspace(10) %out3
+  ret void
+}
+
+declare <4 x float> @llvm.pow.v4f32(<4 x float>, <4 x float>)
+declare <4 x half> @llvm.pow.v4f16(<4 x half>, <4 x half>)
+declare <3 x float> @llvm.pow.v3f32(<3 x float>, <3 x float>)
+declare <3 x half> @llvm.pow.v3f16(<3 x half>, <3 x half>)
+declare <2 x float> @llvm.pow.v2f32(<2 x float>, <2 x float>)
+declare <2 x half> @llvm.pow.v2f16(<2 x half>, <2 x half>)



More information about the cfe-commits mailing list