Skip to content

Commit 33857b4

Browse files
[CIR][Transforms] Fix CallConv Function Lowering (#979)
Re #958 > Consider the following code snippet `tmp.c`: > ``` > typedef struct { > int a, b; > } S; > > void foo(S s) {} > ``` > Running `bin/clang tmp.c -fclangir -Xclang -emit-llvm -Xclang -fclangir-call-conv-lowering -S -o -`, we get: > ``` > loc(fused["tmp.c":5:1, "tmp.c":5:16]): error: 'llvm.bitcast' op result #0 must be LLVM-compatible non-aggregate type, but got '!llvm.struct<"struct.S", (i32, i32)>' > ``` > We can also produce a similar error from this: > ``` > typedef struct { > int a, b; > } S; > > S init() { S s; return s; } > ``` > gives: > ``` > loc(fused["tmp.c":5:17, "tmp.c":5:24]): error: 'llvm.bitcast' op operand #0 must be LLVM-compatible non-aggregate type, but got '!llvm.struct<"struct.S", (i32, i32)>' > ``` > I've traced the errors back to `lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp` in `LowerFunction::buildAggregateStore`, `castReturnValue`, and `buildAggregateBitcast`. > > `withElementType(SrcTy)` is currently commented out/ignored in `LowerFunction.cpp`, but it is important. > > This PR adds/fixes this and updates one test. I thought [about it](#958 (comment)) and I understand adding `cir.bitcast` to circumvent the CIR checks, but I am not sure how we can ignore/drop the bitcast while lowering. I think we can just make the CIR casts correct. I have added a number of lowering tests to verify that the CIR is lowered properly. cc: @sitio-couto @bcardosolopes.
1 parent cab2b44 commit 33857b4

File tree

3 files changed

+213
-18
lines changed

3 files changed

+213
-18
lines changed

clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerFunction.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ Value buildAddressAtOffset(LowerFunction &LF, Value addr,
4242
return addr;
4343
}
4444

45+
Value createCoercedBitcast(Value Src, Type DestTy, LowerFunction &CGF) {
46+
auto destPtrTy = PointerType::get(CGF.getRewriter().getContext(), DestTy);
47+
48+
if (auto load = dyn_cast<LoadOp>(Src.getDefiningOp()))
49+
return CGF.getRewriter().create<CastOp>(Src.getLoc(), destPtrTy,
50+
CastKind::bitcast, load.getAddr());
51+
52+
return CGF.getRewriter().create<CastOp>(Src.getLoc(), destPtrTy,
53+
CastKind::bitcast, Src);
54+
}
55+
4556
/// Given a struct pointer that we are accessing some number of bytes out of it,
4657
/// try to gep into the struct to get at its inner goodness. Dive as deep as
4758
/// possible without entering an element with an in-memory size smaller than
@@ -112,7 +123,7 @@ void createCoercedStore(Value Src, Value Dst, bool DstIsVolatile,
112123
// If store is legal, just bitcast the src pointer.
113124
cir_cconv_assert(!::cir::MissingFeatures::vectorType());
114125
if (SrcSize.getFixedValue() <= DstSize.getFixedValue()) {
115-
// Dst = Dst.withElementType(SrcTy);
126+
Dst = createCoercedBitcast(Dst, SrcTy, CGF);
116127
CGF.buildAggregateStore(Src, Dst, DstIsVolatile);
117128
} else {
118129
cir_cconv_unreachable("NYI");
@@ -174,7 +185,6 @@ Value createCoercedValue(Value Src, Type Ty, LowerFunction &CGF) {
174185
//
175186
// FIXME: Assert that we aren't truncating non-padding bits when have access
176187
// to that information.
177-
// Src = Src.withElementType();
178188
return CGF.buildAggregateBitcast(Src, Ty);
179189
}
180190

@@ -233,8 +243,8 @@ Value castReturnValue(Value Src, Type Ty, LowerFunction &LF) {
233243
//
234244
// FIXME: Assert that we aren't truncating non-padding bits when have access
235245
// to that information.
236-
return LF.getRewriter().create<CastOp>(Src.getLoc(), Ty, CastKind::bitcast,
237-
Src);
246+
auto Cast = createCoercedBitcast(Src, Ty, LF);
247+
return LF.getRewriter().create<LoadOp>(Src.getLoc(), Cast);
238248
}
239249

240250
cir_cconv_unreachable("NYI");
@@ -550,7 +560,8 @@ void LowerFunction::buildAggregateStore(Value Val, Value Dest,
550560
}
551561

552562
Value LowerFunction::buildAggregateBitcast(Value Val, Type DestTy) {
553-
return rewriter.create<CastOp>(Val.getLoc(), DestTy, CastKind::bitcast, Val);
563+
auto Cast = createCoercedBitcast(Val, DestTy, *this);
564+
return rewriter.create<LoadOp>(Val.getLoc(), Cast);
554565
}
555566

556567
/// Rewrite a call operation to abide to the ABI calling convention.
@@ -885,8 +896,15 @@ Value LowerFunction::rewriteCallOp(const LowerFunctionInfo &CallInfo,
885896
// actual data to store.
886897
if (dyn_cast<StructType>(RetTy) &&
887898
cast<StructType>(RetTy).getNumElements() != 0) {
888-
RetVal =
889-
createCoercedValue(newCallOp.getResult(), RetVal.getType(), *this);
899+
RetVal = newCallOp.getResult();
900+
901+
for (auto user : Caller.getOperation()->getUsers()) {
902+
if (auto storeOp = dyn_cast<StoreOp>(user)) {
903+
auto DestPtr = createCoercedBitcast(storeOp.getAddr(),
904+
RetVal.getType(), *this);
905+
rewriter.replaceOpWithNewOp<StoreOp>(storeOp, RetVal, DestPtr);
906+
}
907+
}
890908
}
891909

892910
// NOTE(cir): No need to convert from a temp to an RValue. This is
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fclangir-call-conv-lowering -emit-cir-flat -mmlir --mlir-print-ir-after=cir-call-conv-lowering %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -fclangir-call-conv-lowering
4+
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
5+
6+
typedef struct {
7+
int a, b;
8+
} S;
9+
10+
// CIR: cir.func @init(%arg0: !u64i
11+
// CIR: %[[#V0:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, [""] {alignment = 4 : i64}
12+
// CIR: %[[#V1:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S>), !cir.ptr<!u64i>
13+
// CIR: cir.store %arg0, %[[#V1]] : !u64i, !cir.ptr<!u64i>
14+
// CIR: %[[#V2:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, ["__retval"] {alignment = 4 : i64}
15+
// CIR: %[[#V3:]] = cir.const #cir.int<1> : !s32i
16+
// CIR: %[[#V4:]] = cir.get_member %[[#V0]][0] {name = "a"} : !cir.ptr<!ty_S> -> !cir.ptr<!s32i>
17+
// CIR: cir.store %[[#V3]], %[[#V4]] : !s32i, !cir.ptr<!s32i>
18+
// CIR: %[[#V5:]] = cir.const #cir.int<2> : !s32i
19+
// CIR: %[[#V6:]] = cir.get_member %[[#V0]][1] {name = "b"} : !cir.ptr<!ty_S> -> !cir.ptr<!s32i>
20+
// CIR: cir.store %[[#V5]], %[[#V6]] : !s32i, !cir.ptr<!s32i>
21+
// CIR: cir.copy %[[#V0]] to %[[#V2]] : !cir.ptr<!ty_S>
22+
// CIR: %[[#V7:]] = cir.cast(bitcast, %[[#V2]] : !cir.ptr<!ty_S>), !cir.ptr<!u64i>
23+
// CIR: %[[#V8:]] = cir.load %[[#V7]] : !cir.ptr<!u64i>, !u64i
24+
// CIR: cir.return %[[#V8]] : !u64i
25+
26+
// LLVM: @init(i64 %[[#V0:]])
27+
// LLVM: %[[#V2:]] = alloca %struct.S, i64 1, align 4
28+
// LLVM: store i64 %[[#V0]], ptr %[[#V2]], align 8
29+
// LLVM: %[[#V3:]] = alloca %struct.S, i64 1, align 4
30+
// LLVM: %[[#V4:]] = getelementptr %struct.S, ptr %[[#V2]], i32 0, i32 0
31+
// LLVM: store i32 1, ptr %[[#V4]], align 4
32+
// LLVM: %[[#V5:]] = getelementptr %struct.S, ptr %[[#V2]], i32 0, i32 1
33+
// LLVM: store i32 2, ptr %[[#V5]], align 4
34+
// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[#V3]], ptr %[[#V2]], i32 8, i1 false)
35+
// LLVM: %[[#V6:]] = load i64, ptr %[[#V3]], align 8
36+
// LLVM: ret i64 %[[#V6]]
37+
S init(S s) {
38+
s.a = 1;
39+
s.b = 2;
40+
return s;
41+
}
42+
43+
// CIR: cir.func no_proto @foo1
44+
// CIR: %[[#V0:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, ["s"]
45+
// CIR: %[[#V1:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, ["tmp"] {alignment = 4 : i64}
46+
// CIR: %[[#V2:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S>), !cir.ptr<!u64i>
47+
// CIR: %[[#V3:]] = cir.load %[[#V2]] : !cir.ptr<!u64i>, !u64i
48+
// CIR: %[[#V4:]] = cir.call @init(%[[#V3]]) : (!u64i) -> !u64i
49+
// CIR: %[[#V5:]] = cir.cast(bitcast, %[[#V1]] : !cir.ptr<!ty_S>), !cir.ptr<!u64i>
50+
// CIR: cir.store %[[#V4]], %[[#V5]] : !u64i, !cir.ptr<!u64i>
51+
// CIR: cir.copy %[[#V1]] to %[[#V0]] : !cir.ptr<!ty_S>
52+
// CIR: cir.return
53+
54+
// LLVM: @foo1()
55+
// LLVM: %[[#V1:]] = alloca %struct.S, i64 1, align 4
56+
// LLVM: %[[#V2:]] = alloca %struct.S, i64 1, align 4
57+
// LLVM: %[[#V3:]] = load i64, ptr %[[#V1]], align 8
58+
// LLVM: %[[#V4:]] = call i64 @init(i64 %[[#V3]])
59+
// LLVM: store i64 %[[#V4]], ptr %[[#V2]], align 8
60+
// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[#V1]], ptr %[[#V2]], i32 8, i1 false)
61+
void foo1() {
62+
S s;
63+
s = init(s);
64+
}
65+
66+
// CIR: cir.func @foo2(%arg0: !u64i
67+
// CIR: %[[#V0:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, [""] {alignment = 4 : i64}
68+
// CIR: %[[#V1:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S>), !cir.ptr<!u64i>
69+
// CIR: cir.store %arg0, %[[#V1]] : !u64i, !cir.ptr<!u64i>
70+
// CIR: %[[#V2:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, ["__retval"] {alignment = 4 : i64}
71+
// CIR: %[[#V3:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, ["s2"]
72+
// CIR: %[[#V4:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, ["tmp"] {alignment = 4 : i64}
73+
// CIR: %[[#V5:]] = cir.const #cir.const_struct<{#cir.int<1> : !s32i, #cir.int<2> : !s32i}> : !ty_S
74+
// CIR: cir.store %[[#V5]], %[[#V3]] : !ty_S, !cir.ptr<!ty_S>
75+
// CIR: %[[#V6:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S>), !cir.ptr<!u64i>
76+
// CIR: %[[#V7:]] = cir.load %[[#V6]] : !cir.ptr<!u64i>, !u64i
77+
// CIR: %[[#V8:]] = cir.call @foo2(%[[#V7]]) : (!u64i) -> !u64i
78+
// CIR: %[[#V9:]] = cir.cast(bitcast, %[[#V4]] : !cir.ptr<!ty_S>), !cir.ptr<!u64i>
79+
// CIR: cir.store %[[#V8]], %[[#V9]] : !u64i, !cir.ptr<!u64i>
80+
// CIR: cir.copy %[[#V4]] to %[[#V0]] : !cir.ptr<!ty_S>
81+
// CIR: cir.copy %[[#V0]] to %[[#V2]] : !cir.ptr<!ty_S>
82+
// CIR: %[[#V10:]] = cir.cast(bitcast, %[[#V2]] : !cir.ptr<!ty_S>), !cir.ptr<!u64i>
83+
// CIR: %[[#V11:]] = cir.load %[[#V10]] : !cir.ptr<!u64i>, !u64i
84+
// CIR: cir.return %[[#V11]] : !u64i
85+
86+
// LLVM: @foo2(i64 %[[#V0:]])
87+
// LLVM: %[[#V2:]] = alloca %struct.S, i64 1, align 4
88+
// LLVM: store i64 %[[#V0]], ptr %[[#V2]], align 8
89+
// LLVM: %[[#V3:]] = alloca %struct.S, i64 1, align 4
90+
// LLVM: %[[#V4:]] = alloca %struct.S, i64 1, align 4
91+
// LLVM: %[[#V5:]] = alloca %struct.S, i64 1, align 4
92+
// LLVM: store %struct.S { i32 1, i32 2 }, ptr %[[#V4]], align 4
93+
// LLVM: %[[#V6:]] = load i64, ptr %[[#V2]], align 8
94+
// LLVM: %[[#V7:]] = call i64 @foo2(i64 %[[#V6]])
95+
// LLVM: store i64 %[[#V7]], ptr %[[#V5]], align 8
96+
// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[#V2]], ptr %[[#V5]], i32 8, i1 false)
97+
// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[#V3]], ptr %[[#V2]], i32 8, i1 false)
98+
// LLVM: %[[#V8:]] = load i64, ptr %[[#V3]], align 8
99+
// LLVM: ret i64 %[[#V8]]
100+
S foo2(S s1) {
101+
S s2 = {1, 2};
102+
s1 = foo2(s1);
103+
return s1;
104+
}
105+
106+
typedef struct {
107+
char a;
108+
char b;
109+
} S2;
110+
111+
// CIR: cir.func @init2(%arg0: !u16i
112+
// CIR: %[[#V0:]] = cir.alloca !ty_S2_, !cir.ptr<!ty_S2_>, [""] {alignment = 4 : i64}
113+
// CIR: %[[#V1:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S2_>), !cir.ptr<!u16i>
114+
// CIR: cir.store %arg0, %[[#V1]] : !u16i, !cir.ptr<!u16i>
115+
// CIR: %[[#V2:]] = cir.alloca !ty_S2_, !cir.ptr<!ty_S2_>, ["__retval"] {alignment = 1 : i64}
116+
// CIR: %[[#V3:]] = cir.const #cir.int<1> : !s32i
117+
// CIR: %[[#V4:]] = cir.cast(integral, %[[#V3]] : !s32i), !s8i
118+
// CIR: %[[#V5:]] = cir.get_member %[[#V0]][0] {name = "a"} : !cir.ptr<!ty_S2_> -> !cir.ptr<!s8i>
119+
// CIR: cir.store %[[#V4]], %[[#V5]] : !s8i, !cir.ptr<!s8i>
120+
// CIR: %[[#V6:]] = cir.const #cir.int<2> : !s32i
121+
// CIR: %[[#V7:]] = cir.cast(integral, %[[#V6]] : !s32i), !s8i
122+
// CIR: %[[#V8:]] = cir.get_member %[[#V0]][1] {name = "b"} : !cir.ptr<!ty_S2_> -> !cir.ptr<!s8i>
123+
// CIR: cir.store %[[#V7]], %[[#V8]] : !s8i, !cir.ptr<!s8i>
124+
// CIR: cir.copy %[[#V0]] to %[[#V2]] : !cir.ptr<!ty_S2_>
125+
// CIR: %[[#V9:]] = cir.cast(bitcast, %[[#V2]] : !cir.ptr<!ty_S2_>), !cir.ptr<!u16i>
126+
// CIR: %[[#V10:]] = cir.load %[[#V9]] : !cir.ptr<!u16i>, !u16i
127+
// CIR: cir.return %[[#V10]] : !u16i
128+
129+
// LLVM: @init2(i16 %[[#V0:]])
130+
// LLVM: %[[#V2:]] = alloca %struct.S2, i64 1, align 4
131+
// LLVM: store i16 %[[#V0]], ptr %[[#V2]], align 2
132+
// LLVM: %[[#V3:]] = alloca %struct.S2, i64 1, align 1
133+
// LLVM: %[[#V4:]] = getelementptr %struct.S2, ptr %[[#V2]], i32 0, i32 0
134+
// LLVM: store i8 1, ptr %[[#V4]], align 1
135+
// LLVM: %[[#V5:]] = getelementptr %struct.S2, ptr %[[#V2]], i32 0, i32 1
136+
// LLVM: store i8 2, ptr %[[#V5]], align 1
137+
// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[#V3]], ptr %[[#V2]], i32 2, i1 false)
138+
// LLVM: %[[#V6:]] = load i16, ptr %[[#V3]], align 2
139+
// LLVM: ret i16 %[[#V6]]
140+
S2 init2(S2 s) {
141+
s.a = 1;
142+
s.b = 2;
143+
return s;
144+
}
145+
146+
// CIR: cir.func no_proto @foo3()
147+
// CIR: %[[#V0:]] = cir.alloca !ty_S2_, !cir.ptr<!ty_S2_>, ["s"]
148+
// CIR: %[[#V1:]] = cir.alloca !ty_S2_, !cir.ptr<!ty_S2_>, ["tmp"] {alignment = 1 : i64}
149+
// CIR: %[[#V2:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S2_>), !cir.ptr<!u16i>
150+
// CIR: %[[#V3:]] = cir.load %[[#V2]] : !cir.ptr<!u16i>, !u16i
151+
// CIR: %[[#V4:]] = cir.call @init2(%[[#V3]]) : (!u16i) -> !u16i
152+
// CIR: %[[#V5:]] = cir.cast(bitcast, %[[#V1]] : !cir.ptr<!ty_S2_>), !cir.ptr<!u16i>
153+
// CIR: cir.store %[[#V4]], %[[#V5]] : !u16i, !cir.ptr<!u16i>
154+
// CIR: cir.copy %[[#V1]] to %[[#V0]] : !cir.ptr<!ty_S2_>
155+
// CIR: cir.return
156+
157+
// LLVM: @foo3()
158+
// LLVM: %[[#V1:]] = alloca %struct.S2, i64 1, align 1
159+
// LLVM: %[[#V2:]] = alloca %struct.S2, i64 1, align 1
160+
// LLVM: %[[#V3:]] = load i16, ptr %[[#V1]], align 2
161+
// LLVM: %[[#V4:]] = call i16 @init2(i16 %[[#V3]])
162+
// LLVM: store i16 %[[#V4]], ptr %[[#V2]], align 2
163+
// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[#V1]], ptr %[[#V2]], i32 2, i1 false)
164+
void foo3() {
165+
S2 s;
166+
s = init2(s);
167+
}

clang/test/CIR/CallConvLowering/x86_64/basic.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,20 +99,30 @@ struct S1 {
9999
/// Validate coerced argument and cast it to the expected type.
100100

101101
/// Cast arguments to the expected type.
102-
// CHECK: cir.func @_Z2s12S1(%arg0: !u64i loc({{.+}})) -> !u64i
103-
// CHECK: %[[#V0:]] = cir.alloca !ty_S1_, !cir.ptr<!ty_S1_>
104-
// CHECK: %[[#V1:]] = cir.cast(bitcast, %arg0 : !u64i), !ty_S1_
105-
// CHECK: cir.store %[[#V1]], %[[#V0]] : !ty_S1_, !cir.ptr<!ty_S1_>
102+
// CHECK: %[[#V0:]] = cir.alloca !ty_S1_, !cir.ptr<!ty_S1_>, [""] {alignment = 4 : i64}
103+
// CHECK: %[[#V1:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S1_>), !cir.ptr<!u64i>
104+
// CHECK: cir.store %arg0, %[[#V1]] : !u64i, !cir.ptr<!u64i>
105+
// CHECK: %[[#V2:]] = cir.alloca !ty_S1_, !cir.ptr<!ty_S1_>, ["__retval"] {alignment = 4 : i64}
106+
// CHECK: %[[#V3:]] = cir.alloca !ty_S1_, !cir.ptr<!ty_S1_>, ["agg.tmp0"] {alignment = 4 : i64}
107+
// CHECK: %[[#V4:]] = cir.alloca !ty_S1_, !cir.ptr<!ty_S1_>, ["agg.tmp1"] {alignment = 4 : i64}
106108
S1 s1(S1 arg) {
107109

108110
/// Cast argument and result of the function call to the expected types.
109-
// CHECK: %[[#V9:]] = cir.cast(bitcast, %{{.+}} : !ty_S1_), !u64i
110-
// CHECK: %[[#V10:]] = cir.call @_Z2s12S1(%[[#V9]]) : (!u64i) -> !u64i
111-
// CHECK: %[[#V11:]] = cir.cast(bitcast, %[[#V10]] : !u64i), !ty_S1_
111+
// CHECK: %[[#V9:]] = cir.cast(bitcast, %[[#V3]] : !cir.ptr<!ty_S1_>), !cir.ptr<!u64i>
112+
// CHECK: %[[#V10:]] = cir.load %[[#V9]] : !cir.ptr<!u64i>, !u64i
113+
// CHECK: %[[#V11:]] = cir.call @_Z2s12S1(%[[#V10]]) : (!u64i) -> !u64i
114+
// CHECK: %[[#V12:]] = cir.cast(bitcast, %[[#V4]] : !cir.ptr<!ty_S1_>), !cir.ptr<!u64i>
115+
// CHECK: cir.store %[[#V11]], %[[#V12]] : !u64i, !cir.ptr<!u64i>
112116
s1({1, 2});
113117

114-
// CHECK: %[[#V12:]] = cir.load %{{.+}} : !cir.ptr<!ty_S1_>, !ty_S1_
115-
// CHECK: %[[#V13:]] = cir.cast(bitcast, %[[#V12]] : !ty_S1_), !u64i
116-
// CHECK: cir.return %[[#V13]] : !u64i
118+
// CHECK: %[[#V13:]] = cir.get_member %[[#V2]][0] {name = "a"} : !cir.ptr<!ty_S1_> -> !cir.ptr<!s32i>
119+
// CHECK: %[[#V14:]] = cir.const #cir.int<1> : !s32i
120+
// CHECK: cir.store %[[#V14]], %[[#V13]] : !s32i, !cir.ptr<!s32i>
121+
// CHECK: %[[#V15:]] = cir.get_member %[[#V2]][1] {name = "b"} : !cir.ptr<!ty_S1_> -> !cir.ptr<!s32i>
122+
// CHECK: %[[#V16:]] = cir.const #cir.int<2> : !s32i
123+
// CHECK: cir.store %[[#V16]], %[[#V15]] : !s32i, !cir.ptr<!s32i>
124+
// CHECK: %[[#V17:]] = cir.cast(bitcast, %[[#V2]] : !cir.ptr<!ty_S1_>), !cir.ptr<!u64i>
125+
// CHECK: %[[#V18:]] = cir.load %[[#V17]] : !cir.ptr<!u64i>, !u64i
126+
// CHECK: cir.return %[[#V18]] : !u64i
117127
return {1, 2};
118-
}
128+
}

0 commit comments

Comments
 (0)