Skip to content

Commit 1258563

Browse files
committed
IRGen: Large types reg2mem - Fix visitUncheckedTrivialBitCastInst
An unchecked_trivial_bit_cast can go from a bigger type to a smaller type. Therefore we must allocate stack storage for the operand type rather than the result type. Otherwise, we can end up storing bigger values into smaller storage -- not good. rdar://128086028
1 parent 35cda47 commit 1258563

File tree

3 files changed

+73
-3
lines changed

3 files changed

+73
-3
lines changed

lib/IRGen/LoadableByAddress.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3799,17 +3799,23 @@ class AssignAddressToDef : SILInstructionVisitor<AssignAddressToDef> {
37993799

38003800
void visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *bc) {
38013801
auto builder = assignment.getBuilder(bc->getIterator());
3802+
38023803
if (assignment.isLargeLoadableType(bc->getType()) &&
38033804
!assignment.isLargeLoadableType(bc->getOperand()->getType())) {
38043805
// Curious case of an imported C union.
38053806
// The union is imported as a struct that has no fields.
38063807
// When we access union members we instead bitcast to the union member
38073808
// type.
3808-
auto addr = assignment.createAllocStack(bc->getType());
3809-
auto opdAddr = builder.createUncheckedAddrCast(
3810-
bc->getLoc(), addr, bc->getOperand()->getType().getAddressType());
3809+
3810+
// We expect the "in" type to be larger or equal in size to the "out"
3811+
// type. See IRGenSILFunction::visitUncheckedTrivialBitCastInst.
3812+
// We therefore must use the bigger type, i.e the operand type, to create
3813+
// a stack allocation.
3814+
auto opdAddr = assignment.createAllocStack(bc->getOperand()->getType());
38113815
builder.createStore(bc->getLoc(), bc->getOperand(), opdAddr,
38123816
StoreOwnershipQualifier::Unqualified);
3817+
auto addr = builder.createUncheckedAddrCast(
3818+
bc->getLoc(), opdAddr, bc->getType().getAddressType());
38133819
assignment.mapValueToAddress(origValue, addr);
38143820
assignment.markForDeletion(bc);
38153821
return;

test/IRGen/Inputs/large_c.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,40 @@ typedef struct _ContainerType {
4040
char x1;
4141
ContainedType l[10];
4242
} __attribute__((packed)) ContainerType;
43+
44+
typedef unsigned char arr_t[32];
45+
46+
typedef enum {
47+
entry_0 = 0,
48+
entry_1 = 1,
49+
entry_2 = 2,
50+
entry_3 = 3,
51+
entry_4 = 4,
52+
entry_5 = 5,
53+
entry_6 = 6,
54+
entry_7 = 7,
55+
entry_8 = 8,
56+
entry_9 = 9,
57+
entry_10 = 10,
58+
entry_11 = 11,
59+
entry_12 = 12,
60+
entry_13 = 13,
61+
entry_14 = 14,
62+
entry_15 = 15,
63+
entry_16 = 16,
64+
entry_17 = 17,
65+
entry_18 = 18,
66+
entry_invalid = 255,
67+
} enum_t;
68+
69+
typedef union {
70+
struct {
71+
enum_t slot;
72+
arr_t buf;
73+
} in;
74+
struct {
75+
int result;
76+
arr_t buff;
77+
unsigned char cnt;
78+
} out;
79+
} union_t;

test/IRGen/loadable_by_address_reg2mem.sil

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,30 @@ bb0(%0 : $*C1, %1 : $*Small):
269269
%t = tuple ()
270270
return %t : $()
271271
}
272+
273+
sil @use : $@convention(thin) (UInt32) -> ()
274+
275+
// We need to make sure we use the bigger alloc_stack for the address of
276+
// unchecked_trivial_bit_cast. A bitcast can go from bigger to smaller type.
277+
278+
// CHECK: sil @test11 : $@convention(thin) (@in union_t) -> () {
279+
// CHECK-NOT: unchecked_addr_cast %1 : $*union_t.__Unnamed_struct_in to $*union_t
280+
// CHECK: unchecked_addr_cast {{.*}} : $*union_t to $*union_t.__Unnamed_struct_in
281+
// CHECK: } // end sil function 'test11'
282+
283+
sil @test11 : $@convention(thin) (@in union_t) -> () {
284+
bb0(%0 : $*union_t):
285+
%1 = alloc_stack $union_t
286+
%2 = alloc_stack $union_t
287+
copy_addr [take] %0 to [init] %2 : $*union_t
288+
%4 = load %2 : $*union_t
289+
%7 = unchecked_trivial_bit_cast %4 : $union_t to $union_t.__Unnamed_struct_in
290+
%8 = struct_extract %7 : $union_t.__Unnamed_struct_in, #union_t.__Unnamed_struct_in.slot
291+
%10 = struct_extract %8 : $enum_t, #enum_t.rawValue
292+
%11 = function_ref @use : $@convention(thin) (UInt32) -> ()
293+
%12 = apply %11(%10) : $@convention(thin) (UInt32) -> ()
294+
%13 = tuple ()
295+
dealloc_stack %2 : $*union_t
296+
dealloc_stack %1 : $*union_t
297+
return %13 : $()
298+
}

0 commit comments

Comments
 (0)