aboutsummaryrefslogtreecommitdiff
path: root/clang/test/CodeGenHLSL/BasicFeatures/StructElementwiseCast.hlsl
blob: 81b9f5b28cc7e199f43a4f545866824cf1f33f52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s

struct S {
  int X;
  float Y;
};

// struct truncation to a scalar
// CHECK-LABEL: define void {{.*}}call0
// CHECK: [[s:%.*]] = alloca %struct.S, align 1
// CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[Tmp:%.*]] = alloca %struct.S, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[s]], ptr align 1 {{.*}}, i32 8, i1 false)
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[Tmp]], ptr align 1 [[s]], i32 8, i1 false)
// CHECK-NEXT: [[G1:%.*]] = getelementptr inbounds %struct.S, ptr [[Tmp]], i32 0, i32 0
// CHECK-NEXT: [[G2:%.*]] = getelementptr inbounds %struct.S, ptr [[Tmp]], i32 0, i32 1
// CHECK-NEXT: [[L:%.*]] = load i32, ptr [[G1]], align 4
// CHECK-NEXT: store i32 [[L]], ptr [[A]], align 4
export void call0() {
  S s = {1,2};
  int A = (int)s;
}

// struct from vector
// CHECK-LABEL: define void {{.*}}call1
// CHECK: [[A:%.*]] = alloca <2 x i32>, align 8
// CHECK-NEXT: [[s:%.*]] = alloca %struct.S, align 1
// CHECK-NEXT: store <2 x i32> <i32 1, i32 2>, ptr [[A]], align 8
// CHECK-NEXT: [[L:%.*]] = load <2 x i32>, ptr [[A]], align 8
// CHECK-NEXT: [[G1:%.*]] = getelementptr inbounds %struct.S, ptr [[s]], i32 0, i32 0
// CHECK-NEXT: [[G2:%.*]] = getelementptr inbounds %struct.S, ptr [[s]], i32 0, i32 1
// CHECK-NEXT: [[VL:%.*]] = extractelement <2 x i32> [[L]], i64 0
// CHECK-NEXT: store i32 [[VL]], ptr [[G1]], align 4
// CHECK-NEXT: [[VL2:%.*]] = extractelement <2 x i32> [[L]], i64 1
// CHECK-NEXT: [[C:%.*]] = sitofp i32 [[VL2]] to float
// CHECK-NEXT: store float [[C]], ptr [[G2]], align 4
export void call1() {
  int2 A = {1,2};
  S s = (S)A;
}


// struct from array
// CHECK-LABEL: define void {{.*}}call2
// CHECK: [[A:%.*]] = alloca [2 x i32], align 4
// CHECK-NEXT: [[s:%.*]] = alloca %struct.S, align 1
// CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 {{.*}}, i32 8, i1 false)
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false)
// CHECK-NEXT: [[G1:%.*]] = getelementptr inbounds %struct.S, ptr [[s]], i32 0, i32 0
// CHECK-NEXT: [[G2:%.*]] = getelementptr inbounds %struct.S, ptr [[s]], i32 0, i32 1
// CHECK-NEXT: [[G3:%.*]] = getelementptr inbounds [2 x i32], ptr [[Tmp]], i32 0, i32 0
// CHECK-NEXT: [[G4:%.*]] = getelementptr inbounds [2 x i32], ptr [[Tmp]], i32 0, i32 1
// CHECK-NEXT: [[L:%.*]] = load i32, ptr [[G3]], align 4
// CHECK-NEXT: store i32 [[L]], ptr [[G1]], align 4
// CHECK-NEXT: [[L4:%.*]] = load i32, ptr [[G4]], align 4
// CHECK-NEXT: [[C:%.*]] = sitofp i32 [[L4]] to float
// CHECK-NEXT: store float [[C]], ptr [[G2]], align 4
export void call2() {
  int A[2] = {1,2};
  S s = (S)A;
}

struct Q {
  int Z;
};

struct R {
  Q q;
  float F;
};

// struct from nested struct?
// CHECK-LABEL: define void {{.*}}call6
// CHECK: [[r:%.*]] = alloca %struct.R, align 1
// CHECK-NEXT: [[s:%.*]] = alloca %struct.S, align 1
// CHECK-NEXT: [[Tmp:%.*]] = alloca %struct.R, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[r]], ptr align 1 {{.*}}, i32 8, i1 false)
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[Tmp]], ptr align 1 [[r]], i32 8, i1 false)
// CHECK-NEXT: [[G1:%.*]] = getelementptr inbounds %struct.S, ptr [[s]], i32 0, i32 0
// CHECK-NEXT: [[G2:%.*]] = getelementptr inbounds %struct.S, ptr [[s]], i32 0, i32 1
// CHECK-NEXT: [[G3:%.*]] = getelementptr inbounds %struct.R, ptr [[Tmp]], i32 0, i32 0
// CHECK-NEXT: [[G4:%.*]] = getelementptr inbounds %struct.R, ptr [[Tmp]], i32 0, i32 1
// CHECK-NEXT: [[L:%.*]] = load i32, ptr [[G3]], align 4
// CHECK-NEXT: store i32 [[L]], ptr [[G1]], align 4
// CHECK-NEXT: [[L4:%.*]] = load float, ptr [[G4]], align 4
// CHECK-NEXT: store float [[L4]], ptr [[G2]], align 4
export void call6() {
  R r = {{1}, 2.0};
  S s = (S)r;
}

// nested struct from array?
// CHECK-LABEL: define void {{.*}}call7
// CHECK: [[A:%.*]] = alloca [2 x i32], align 4
// CHECK-NEXT: [[r:%.*]] = alloca %struct.R, align 1
// CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[A]], ptr align 4 {{.*}}, i32 8, i1 false)
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[A]], i32 8, i1 false)
// CHECK-NEXT: [[G1:%.*]] = getelementptr inbounds %struct.R, ptr [[r]], i32 0, i32 0
// CHECK-NEXT: [[G2:%.*]] = getelementptr inbounds %struct.R, ptr [[r]], i32 0, i32 1
// CHECK-NEXT: [[G3:%.*]] = getelementptr inbounds [2 x i32], ptr [[Tmp]], i32 0, i32 0
// CHECK-NEXT: [[G4:%.*]] = getelementptr inbounds [2 x i32], ptr [[Tmp]], i32 0, i32 1
// CHECK-NEXT: [[L:%.*]] = load i32, ptr [[G3]], align 4
// CHECK-NEXT: store i32 [[L]], ptr [[G1]], align 4
// CHECK-NEXT: [[L4:%.*]] = load i32, ptr [[G4]], align 4
// CHECK-NEXT: [[C:%.*]] = sitofp i32 [[L4]] to float
// CHECK-NEXT: store float [[C]], ptr [[G2]], align 4
export void call7() {
  int A[2] = {1,2};
  R r = (R)A;
}

struct T {
  int A;
  int B;
  int C;
};

// struct truncation
// CHECK-LABEL: define void {{.*}}call8
// CHECK: [[t:%.*]] = alloca %struct.T, align 1
// CHECK-NEXT: [[s:%.*]] = alloca %struct.S, align 1
// CHECK-NEXT: [[Tmp:%.*]] = alloca %struct.T, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[t]], ptr align 1 {{.*}}, i32 12, i1 false)
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[Tmp]], ptr align 1 [[t]], i32 12, i1 false)
// CHECK-NEXT: [[G1:%.*]] = getelementptr inbounds %struct.S, ptr [[s]], i32 0, i32 0
// CHECK-NEXT: [[G2:%.*]] = getelementptr inbounds %struct.S, ptr [[s]], i32 0, i32 1
// CHECK-NEXT: [[G3:%.*]] = getelementptr inbounds %struct.T, ptr [[Tmp]], i32 0, i32 0
// CHECK-NEXT: %gep3 = getelementptr inbounds %struct.T, ptr %agg-temp, i32 0, i32 1
// CHECK-NEXT: %gep4 = getelementptr inbounds %struct.T, ptr %agg-temp, i32 0, i32 2
// CHECK-NEXT: %load = load i32, ptr %gep2, align 4
// CHECK-NEXT: store i32 %load, ptr %gep, align 4
// CHECK-NEXT: %load5 = load i32, ptr %gep3, align 4
// CHECK-NEXT: %conv = sitofp i32 %load5 to float
// CHECK-NEXT: store float %conv, ptr %gep1, align 4
export void call8() {
  T t = {1,2,3};
  S s = (S)t;
}