Skip to content

Commit

Permalink
addressing comments
Browse files Browse the repository at this point in the history
  • Loading branch information
joaosaffran-zz committed Oct 28, 2024
1 parent a676944 commit 104479d
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 138 deletions.
88 changes: 19 additions & 69 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,23 +132,6 @@ static Value *handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF) {

} else {
// For Non DXIL targets we generate the instructions.
// TODO: This code accounts for known limitations in
// SPIR-V and splitdouble. Such should be handled,
// in a later compilation stage. After
// https://github.com/llvm/llvm-project/issues/113597 is fixed, this shall
// be refactored.

// casts `<2 x double>` to `<4 x i32>`, then shuffles into high and low
// `<2 x i32>` vectors.
auto EmitDouble2Cast =
[](CodeGenFunction &CGF,
Value *DoubleVec2) -> std::pair<Value *, Value *> {
Value *BC = CGF.Builder.CreateBitCast(
DoubleVec2, FixedVectorType::get(CGF.Int32Ty, 4));
Value *LB = CGF.Builder.CreateShuffleVector(BC, {0, 2});
Value *HB = CGF.Builder.CreateShuffleVector(BC, {1, 3});
return std::make_pair(LB, HB);
};

if (!Op0->getType()->isVectorTy()) {
FixedVectorType *DestTy = FixedVectorType::get(CGF->Int32Ty, 2);
Expand All @@ -157,58 +140,25 @@ static Value *handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF) {
LowBits = CGF->Builder.CreateExtractElement(Bitcast, (uint64_t)0);
HighBits = CGF->Builder.CreateExtractElement(Bitcast, 1);
} else {

const auto *TargTy = E->getArg(0)->getType()->getAs<clang::VectorType>();

int NumElements = TargTy->getNumElements();

FixedVectorType *UintVec2 = FixedVectorType::get(CGF->Int32Ty, 2);

switch (NumElements) {
case 1: {
auto *Bitcast = CGF->Builder.CreateBitCast(Op0, UintVec2);

LowBits = CGF->Builder.CreateExtractElement(Bitcast, (uint64_t)0);
HighBits = CGF->Builder.CreateExtractElement(Bitcast, 1);
break;
}
case 2: {
auto [LB, HB] = EmitDouble2Cast(*CGF, Op0);
LowBits = LB;
HighBits = HB;
break;
}

case 3: {
auto *Shuff = CGF->Builder.CreateShuffleVector(Op0, {0, 1});
auto [LB, HB] = EmitDouble2Cast(*CGF, Shuff);

auto *EV = CGF->Builder.CreateExtractElement(Op0, 2);
auto *ScalarBitcast = CGF->Builder.CreateBitCast(EV, UintVec2);

LowBits =
CGF->Builder.CreateShuffleVector(LB, ScalarBitcast, {0, 1, 2});
HighBits =
CGF->Builder.CreateShuffleVector(HB, ScalarBitcast, {0, 1, 3});
break;
}
case 4: {

auto *Shuff1 = CGF->Builder.CreateShuffleVector(Op0, {0, 1});
auto [LB1, HB1] = EmitDouble2Cast(*CGF, Shuff1);

auto *Shuff2 = CGF->Builder.CreateShuffleVector(Op0, {2, 3});
auto [LB2, HB2] = EmitDouble2Cast(*CGF, Shuff2);

LowBits = CGF->Builder.CreateShuffleVector(LB1, LB2, {0, 1, 2, 3});
HighBits = CGF->Builder.CreateShuffleVector(HB1, HB2, {0, 1, 3, 3});
break;
}
default: {
CGF->CGM.Error(E->getExprLoc(),
"splitdouble doesn't support vectors larger than 4.");
return nullptr;
}
int NumElements = 1;
if (const auto *VecTy =
E->getArg(0)->getType()->getAs<clang::VectorType>())
NumElements = VecTy->getNumElements();

FixedVectorType *Uint32VecTy =
FixedVectorType::get(CGF->Int32Ty, NumElements * 2);
Value *Uint32Vec = CGF->Builder.CreateBitCast(Op0, Uint32VecTy);
if (NumElements == 1) {
LowBits = CGF->Builder.CreateExtractElement(Uint32Vec, (uint64_t)0);
HighBits = CGF->Builder.CreateExtractElement(Uint32Vec, 1);
} else {
SmallVector<int> EvenMask, OddMask;
for (int I = 0, E = NumElements; I != E; ++I) {
EvenMask.push_back(I * 2);
OddMask.push_back(I * 2 + 1);
}
LowBits = CGF->Builder.CreateShuffleVector(Uint32Vec, EvenMask);
HighBits = CGF->Builder.CreateShuffleVector(Uint32Vec, OddMask);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5897,7 +5897,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Emit any call-associated writebacks immediately. Arguably this
// should happen after any return-value munging.
if (CallArgs.hasWritebacks())
CodeGenFunction::EmitWritebacks(CallArgs);
EmitWritebacks(CallArgs);

// The stack cleanup for inalloca arguments has to run out of the normal
// lexical order, so deactivate it and run it manually here.
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1748,9 +1748,11 @@ static bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) {
static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall,
unsigned ArgIndex) {
auto *Arg = TheCall->getArg(ArgIndex);
if (Arg->isModifiableLvalue(S->getASTContext()) == Expr::MLV_Valid)
SourceLocation OrigLoc = Arg->getExprLoc();
if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) ==
Expr::MLV_Valid)
return false;
S->Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue) << Arg << 0;
S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0;
return true;
}

Expand Down Expand Up @@ -2102,10 +2104,10 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy,
2))
return true;

if (CheckModifiableLValue(&SemaRef, TheCall, 1) ||
CheckModifiableLValue(&SemaRef, TheCall, 2))
return true;

break;
}
case Builtin::BI__builtin_elementwise_acos:
Expand Down
64 changes: 28 additions & 36 deletions clang/test/CodeGenHLSL/builtins/splitdouble.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@


// CHECK: define {{.*}} i32 {{.*}}test_scalar{{.*}}(double {{.*}} [[VALD:%.*]])
// CHECK: [[VALRET:%.*]] = {{.*}} call { i32, i32 } @llvm.dx.splitdouble.i32(double [[VALD]])
// CHECK: [[VALRET:%.*]] = {{.*}} call { i32, i32 } @llvm.dx.splitdouble.i32(double [[VALD]])
// CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 0
// CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 1
//
// SPIRV: define spir_func {{.*}} i32 {{.*}}test_scalar{{.*}}(double {{.*}} [[VALD:%.*]])
// SPIRV-NOT: @llvm.dx.splitdouble.i32
// SPIRV: [[REG:%.*]] = load double, ptr [[VALD]].addr, align 8
// SPIRV-NEXT: [[CAST:%.*]] = bitcast double [[REG]] to <2 x i32>
// SPIRV-NOT: @llvm.dx.splitdouble.i32
// SPIRV: [[LOAD:%.*]] = load double, ptr [[VALD]].addr, align 8
// SPIRV-NEXT: [[CAST:%.*]] = bitcast double [[LOAD]] to <2 x i32>
// SPIRV-NEXT: extractelement <2 x i32> [[CAST]], i64 0
// SPIRV-NEXT: extractelement <2 x i32> [[CAST]], i64 1
uint test_scalar(double D) {
Expand All @@ -20,14 +21,15 @@ uint test_scalar(double D) {
}

// CHECK: define {{.*}} <1 x i32> {{.*}}test_double1{{.*}}(<1 x double> {{.*}} [[VALD:%.*]])
// CHECK: [[TRUNC:%.*]] = extractelement <1 x double> %D, i64 0
// CHECK: [[TRUNC:%.*]] = extractelement <1 x double> %D, i64 0
// CHECK-NEXT: [[VALRET:%.*]] = {{.*}} call { i32, i32 } @llvm.dx.splitdouble.i32(double [[TRUNC]])
// CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 0
// CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 1
//
// SPIRV: define spir_func {{.*}} <1 x i32> {{.*}}test_double1{{.*}}(<1 x double> {{.*}} [[VALD:%.*]])
// SPIRV-NOT: @llvm.dx.splitdouble.i32
// SPIRV: [[REG:%.*]] = load <1 x double>, ptr [[VALD]].addr, align 8
// SPIRV-NEXT: [[TRUNC:%.*]] = extractelement <1 x double> %1, i64 0
// SPIRV-NOT: @llvm.dx.splitdouble.i32
// SPIRV: [[LOAD:%.*]] = load <1 x double>, ptr [[VALD]].addr, align 8
// SPIRV-NEXT: [[TRUNC:%.*]] = extractelement <1 x double> [[LOAD]], i64 0
// SPIRV-NEXT: [[CAST:%.*]] = bitcast double [[TRUNC]] to <2 x i32>
// SPIRV-NEXT: extractelement <2 x i32> [[CAST]], i64 0
// SPIRV-NEXT: extractelement <2 x i32> [[CAST]], i64 1
Expand All @@ -38,13 +40,14 @@ uint1 test_double1(double1 D) {
}

// CHECK: define {{.*}} <2 x i32> {{.*}}test_vector2{{.*}}(<2 x double> {{.*}} [[VALD:%.*]])
// CHECK: [[VALRET:%.*]] = {{.*}} call { <2 x i32>, <2 x i32> } @llvm.dx.splitdouble.v2i32(<2 x double> [[VALD]])
// CHECK: [[VALRET:%.*]] = {{.*}} call { <2 x i32>, <2 x i32> } @llvm.dx.splitdouble.v2i32(<2 x double> [[VALD]])
// CHECK-NEXT: extractvalue { <2 x i32>, <2 x i32> } [[VALRET]], 0
// CHECK-NEXT: extractvalue { <2 x i32>, <2 x i32> } [[VALRET]], 1
//
// SPIRV: define spir_func {{.*}} <2 x i32> {{.*}}test_vector2{{.*}}(<2 x double> {{.*}} [[VALD:%.*]])
// SPIRV-NOT: @llvm.dx.splitdouble.i32
// SPIRV: [[REG:%.*]] = load <2 x double>, ptr [[VALD]].addr, align 16
// SPIRV-NEXT: [[CAST1:%.*]] = bitcast <2 x double> [[REG]] to <4 x i32>
// SPIRV-NOT: @llvm.dx.splitdouble.i32
// SPIRV: [[LOAD:%.*]] = load <2 x double>, ptr [[VALD]].addr, align 16
// SPIRV-NEXT: [[CAST1:%.*]] = bitcast <2 x double> [[LOAD]] to <4 x i32>
// SPIRV-NEXT: [[SHUF1:%.*]] = shufflevector <4 x i32> [[CAST1]], <4 x i32> poison, <2 x i32> <i32 0, i32 2>
// SPIRV-NEXT: [[SHUF2:%.*]] = shufflevector <4 x i32> [[CAST1]], <4 x i32> poison, <2 x i32> <i32 1, i32 3>
uint2 test_vector2(double2 D) {
Expand All @@ -54,44 +57,33 @@ uint2 test_vector2(double2 D) {
}

// CHECK: define {{.*}} <3 x i32> {{.*}}test_vector3{{.*}}(<3 x double> {{.*}} [[VALD:%.*]])
// CHECK: [[VALRET:%.*]] = {{.*}} call { <3 x i32>, <3 x i32> } @llvm.dx.splitdouble.v3i32(<3 x double> [[VALD]])
// CHECK: [[VALRET:%.*]] = {{.*}} call { <3 x i32>, <3 x i32> } @llvm.dx.splitdouble.v3i32(<3 x double> [[VALD]])
// CHECK-NEXT: extractvalue { <3 x i32>, <3 x i32> } [[VALRET]], 0
// CHECK-NEXT: extractvalue { <3 x i32>, <3 x i32> } [[VALRET]], 1
//
// SPIRV: define spir_func {{.*}} <3 x i32> {{.*}}test_vector3{{.*}}(<3 x double> {{.*}} [[VALD:%.*]])
// SPIRV-NOT: @llvm.dx.splitdouble.i32
// SPIRV: [[REG:%.*]] = load <3 x double>, ptr [[VALD]].addr, align 32
// SPIRV-NEXT: [[VALRET1:%.*]] = shufflevector <3 x double> [[REG]], <3 x double> poison, <2 x i32> <i32 0, i32 1>
// SPIRV-NEXT: [[CAST1:%.*]] = bitcast <2 x double> [[VALRET1]] to <4 x i32>
// SPIRV-NEXT: [[SHUF1:%.*]] = shufflevector <4 x i32> [[CAST1]], <4 x i32> poison, <2 x i32> <i32 0, i32 2>
// SPIRV-NEXT: [[SHUF2:%.*]] = shufflevector <4 x i32> [[CAST1]], <4 x i32> poison, <2 x i32> <i32 1, i32 3>
// SPIRV-NEXT: [[EXTRACT:%.*]] = extractelement <3 x double> [[REG]], i64 2
// SPIRV-NEXT: [[CAST:%.*]] = bitcast double [[EXTRACT]] to <2 x i32>
// SPIRV-NEXT: %[[#]] = shufflevector <2 x i32> [[SHUF1]], <2 x i32> [[CAST]], <3 x i32> <i32 0, i32 1, i32 2>
// SPIRV-NEXT: %[[#]] = shufflevector <2 x i32> [[SHUF2]], <2 x i32> [[CAST]], <3 x i32> <i32 0, i32 1, i32 3>
// SPIRV-NOT: @llvm.dx.splitdouble.i32
// SPIRV: [[LOAD:%.*]] = load <3 x double>, ptr [[VALD]].addr, align 32
// SPIRV-NEXT: [[CAST1:%.*]] = bitcast <3 x double> [[LOAD]] to <6 x i32>
// SPIRV-NEXT: [[SHUF1:%.*]] = shufflevector <6 x i32> [[CAST1]], <6 x i32> poison, <3 x i32> <i32 0, i32 2, i32 4>
// SPIRV-NEXT: [[SHUF2:%.*]] = shufflevector <6 x i32> [[CAST1]], <6 x i32> poison, <3 x i32> <i32 1, i32 3, i32 5>
uint3 test_vector3(double3 D) {
uint3 A, B;
asuint(D, A, B);
return A + B;
}

// CHECK: define {{.*}} <4 x i32> {{.*}}test_vector4{{.*}}(<4 x double> {{.*}} [[VALD:%.*]])
// CHECK: [[VALRET:%.*]] = {{.*}} call { <4 x i32>, <4 x i32> } @llvm.dx.splitdouble.v4i32(<4 x double> [[VALD]])
// CHECK: [[VALRET:%.*]] = {{.*}} call { <4 x i32>, <4 x i32> } @llvm.dx.splitdouble.v4i32(<4 x double> [[VALD]])
// CHECK-NEXT: extractvalue { <4 x i32>, <4 x i32> } [[VALRET]], 0
// CHECK-NEXT: extractvalue { <4 x i32>, <4 x i32> } [[VALRET]], 1
//
// SPIRV: define spir_func {{.*}} <4 x i32> {{.*}}test_vector4{{.*}}(<4 x double> {{.*}} [[VALD:%.*]])
// SPIRV-NOT: @llvm.dx.splitdouble.i32
// SPIRV: [[REG:%.*]] = load <4 x double>, ptr [[VALD]].addr, align 32
// SPIRV-NEXT: [[VALRET1:%.*]] = shufflevector <4 x double> [[REG]], <4 x double> poison, <2 x i32> <i32 0, i32 1>
// SPIRV-NEXT: [[CAST1:%.*]] = bitcast <2 x double> [[VALRET1]] to <4 x i32>
// SPIRV-NEXT: [[SHUF1:%.*]] = shufflevector <4 x i32> [[CAST1]], <4 x i32> poison, <2 x i32> <i32 0, i32 2>
// SPIRV-NEXT: [[SHUF2:%.*]] = shufflevector <4 x i32> [[CAST1]], <4 x i32> poison, <2 x i32> <i32 1, i32 3>
// SPIRV-NEXT: [[VALRET2:%.*]] = shufflevector <4 x double> [[REG]], <4 x double> poison, <2 x i32> <i32 2, i32 3>
// SPIRV-NEXT: [[CAST2:%.*]] = bitcast <2 x double> [[VALRET2]] to <4 x i32>
// SPIRV-NEXT: [[SHUF3:%.*]] = shufflevector <4 x i32> [[CAST2]], <4 x i32> poison, <2 x i32> <i32 0, i32 2>
// SPIRV-NEXT: [[SHUF4:%.*]] = shufflevector <4 x i32> [[CAST2]], <4 x i32> poison, <2 x i32> <i32 1, i32 3>
// SPIRV-NEXT: shufflevector <2 x i32> [[SHUF1]], <2 x i32> [[SHUF3]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
// SPIRV-NEXT: shufflevector <2 x i32> [[SHUF2]], <2 x i32> [[SHUF4]], <4 x i32> <i32 0, i32 1, i32 3, i32 3>

// SPIRV: [[LOAD:%.*]] = load <4 x double>, ptr [[VALD]].addr, align 32
// SPIRV-NEXT: [[CAST1:%.*]] = bitcast <4 x double> [[LOAD]] to <8 x i32>
// SPIRV-NEXT: [[SHUF1:%.*]] = shufflevector <8 x i32> [[CAST1]], <8 x i32> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
// SPIRV-NEXT: [[SHUF2:%.*]] = shufflevector <8 x i32> [[CAST1]], <8 x i32> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
uint4 test_vector4(double4 D) {
uint4 A, B;
asuint(D, A, B);
Expand Down
30 changes: 27 additions & 3 deletions clang/test/SemaHLSL/BuiltIns/splitdouble-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,36 @@ void test_const_second_arg(double D) {
const uint A = 1;
uint B;
__builtin_hlsl_elementwise_splitdouble(D, A, B);
// expected-error@-1 {{cannot bind non-lvalue argument}}
// expected-error@-1 {{cannot bind non-lvalue argument A to out paramemter}}
}

void test_const_third_arg(double D) {
uint A;
const uint B = 2;
const uint B = 1;
__builtin_hlsl_elementwise_splitdouble(D, A, B);
// expected-error@-1 {{cannot bind non-lvalue argument}}
// expected-error@-1 {{cannot bind non-lvalue argument B to out paramemter}}
}

void test_number_second_arg(double D) {
uint B;
__builtin_hlsl_elementwise_splitdouble(D, (uint)1, B);
// expected-error@-1 {{cannot bind non-lvalue argument (uint)1 to out paramemter}}
}

void test_number_third_arg(double D) {
uint B;
__builtin_hlsl_elementwise_splitdouble(D, B, (uint)1);
// expected-error@-1 {{cannot bind non-lvalue argument (uint)1 to out paramemter}}
}

void test_expr_second_arg(double D) {
uint B;
__builtin_hlsl_elementwise_splitdouble(D, B+1, B);
// expected-error@-1 {{cannot bind non-lvalue argument B + 1 to out paramemter}}
}

void test_expr_third_arg(double D) {
uint B;
__builtin_hlsl_elementwise_splitdouble(D, B, B+1);
// expected-error@-1 {{cannot bind non-lvalue argument B + 1 to out paramemter}}
}
1 change: 0 additions & 1 deletion llvm/test/CodeGen/DirectX/splitdouble.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes='function(scalarizer)' -S -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,NOLOWER
; RUN: opt -passes='function(scalarizer),module(dxil-op-lower)' -S -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,WITHLOWER

Expand Down
36 changes: 11 additions & 25 deletions llvm/test/CodeGen/SPIRV/hlsl-intrinsics/splitdouble.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@
; Make sure lowering is correctly generating spirv code.

; CHECK-DAG: %[[#double:]] = OpTypeFloat 64
; CHECK-DAG: %[[#vec_2_double:]] = OpTypeVector %[[#double]] 2
; CHECK-DAG: %[[#int_32:]] = OpTypeInt 32 0
; CHECK-DAG: %[[#scalar_function:]] = OpTypeFunction %[[#int_32]] %[[#double]]
; CHECK-DAG: %[[#vec_2_int_32:]] = OpTypeVector %[[#int_32]] 2
; CHECK-DAG: %[[#vec_4_int_32:]] = OpTypeVector %[[#int_32]] 4
; CHECK-DAG: %[[#vec_3_int_32:]] = OpTypeVector %[[#int_32]] 3
; CHECK-DAG: %[[#vec_3_double:]] = OpTypeVector %[[#double]] 3
; CHECK-DAG: %[[#vector_function:]] = OpTypeFunction %[[#vec_3_int_32]] %[[#vec_3_double]]
; CHECK-DAG: %[[#vec_2_double:]] = OpTypeVector %[[#double]] 2


define spir_func noundef i32 @test_scalar(double noundef %D) local_unnamed_addr {
Expand All @@ -29,26 +25,16 @@ entry:
}


define spir_func noundef <3 x i32> @test_vector(<3 x double> noundef %D) local_unnamed_addr {
define spir_func noundef <2 x i32> @test_vector(<2 x double> noundef %D) local_unnamed_addr {
entry:
; CHECK-LABEL: ; -- Begin function test_vector
; CHECK: %[[#param:]] = OpFunctionParameter %[[#vec_3_double]]
; %[[#SHUFF1:]] = OpVectorShuffle %[[#vec_2_double]] %[[#param]] %[[#]] 0 1
; %[[#CAST1:]] = OpBitcast %[[#vec_4_int_32]] %[[#SHUFF1]]
; %[[#SHUFF2:]] = OpVectorShuffle %[[#vec_2_int_32]] %[[#CAST1]] %[[#]] 0 2
; %[[#SHUFF3:]] = OpVectorShuffle %[[#vec_2_int_32]] %[[#CAST1]] %[[#]] 1 3
; %[[#EXTRACT:]] = OpCompositeExtract %[[#double]] %[[#param]] 2
; %[[#CAST2:]] = OpBitcast %[[#vec_2_int_32]] %[[#EXTRACT]]
; %[[#]] = OpVectorShuffle %7 %[[#SHUFF2]] %[[#CAST2]] 0 1 2
; %[[#]] = OpVectorShuffle %7 %[[#SHUFF3]] %[[#CAST2]] 0 1 3
%0 = shufflevector <3 x double> %D, <3 x double> poison, <2 x i32> <i32 0, i32 1>
%1 = bitcast <2 x double> %0 to <4 x i32>
%2 = shufflevector <4 x i32> %1, <4 x i32> poison, <2 x i32> <i32 0, i32 2>
%3 = shufflevector <4 x i32> %1, <4 x i32> poison, <2 x i32> <i32 1, i32 3>
%4 = extractelement <3 x double> %D, i64 2
%5 = bitcast double %4 to <2 x i32>
%6 = shufflevector <2 x i32> %2, <2 x i32> %5, <3 x i32> <i32 0, i32 1, i32 2>
%7 = shufflevector <2 x i32> %3, <2 x i32> %5, <3 x i32> <i32 0, i32 1, i32 3>
%add = add <3 x i32> %6, %7
ret <3 x i32> %add
; CHECK: %[[#param:]] = OpFunctionParameter %[[#vec_2_double]]
; CHECK: %[[#CAST1:]] = OpBitcast %[[#vec_4_int_32]] %[[#param]]
; CHECK: %[[#SHUFF2:]] = OpVectorShuffle %[[#vec_2_int_32]] %[[#CAST1]] %[[#]] 0 2
; CHECK: %[[#SHUFF3:]] = OpVectorShuffle %[[#vec_2_int_32]] %[[#CAST1]] %[[#]] 1 3
%0 = bitcast <2 x double> %D to <4 x i32>
%1 = shufflevector <4 x i32> %0, <4 x i32> poison, <2 x i32> <i32 0, i32 2>
%2 = shufflevector <4 x i32> %0, <4 x i32> poison, <2 x i32> <i32 1, i32 3>
%add = add <2 x i32> %1, %2
ret <2 x i32> %add
}

0 comments on commit 104479d

Please sign in to comment.