Skip to content

IRGen: Large types reg2mem - Fix visitUncheckedTrivialBitCastInst #73626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions lib/IRGen/LoadableByAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3799,17 +3799,23 @@ class AssignAddressToDef : SILInstructionVisitor<AssignAddressToDef> {

void visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *bc) {
auto builder = assignment.getBuilder(bc->getIterator());

if (assignment.isLargeLoadableType(bc->getType()) &&
!assignment.isLargeLoadableType(bc->getOperand()->getType())) {
// Curious case of an imported C union.
// The union is imported as a struct that has no fields.
// When we access union members we instead bitcast to the union member
// type.
auto addr = assignment.createAllocStack(bc->getType());
auto opdAddr = builder.createUncheckedAddrCast(
bc->getLoc(), addr, bc->getOperand()->getType().getAddressType());

// We expect the "in" type to be larger or equal in size to the "out"
// type. See IRGenSILFunction::visitUncheckedTrivialBitCastInst.
// We therefore must use the bigger type, i.e the operand type, to create
// a stack allocation.
auto opdAddr = assignment.createAllocStack(bc->getOperand()->getType());
builder.createStore(bc->getLoc(), bc->getOperand(), opdAddr,
StoreOwnershipQualifier::Unqualified);
auto addr = builder.createUncheckedAddrCast(
bc->getLoc(), opdAddr, bc->getType().getAddressType());
assignment.mapValueToAddress(origValue, addr);
assignment.markForDeletion(bc);
return;
Expand Down
37 changes: 37 additions & 0 deletions test/IRGen/Inputs/large_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,40 @@ typedef struct _ContainerType {
char x1;
ContainedType l[10];
} __attribute__((packed)) ContainerType;

typedef unsigned char arr_t[32];

typedef enum : unsigned int {
entry_0 = 0,
entry_1 = 1,
entry_2 = 2,
entry_3 = 3,
entry_4 = 4,
entry_5 = 5,
entry_6 = 6,
entry_7 = 7,
entry_8 = 8,
entry_9 = 9,
entry_10 = 10,
entry_11 = 11,
entry_12 = 12,
entry_13 = 13,
entry_14 = 14,
entry_15 = 15,
entry_16 = 16,
entry_17 = 17,
entry_18 = 18,
entry_invalid = 255,
} enum_t;

typedef union {
struct {
enum_t slot;
arr_t buf;
} in;
struct {
int result;
arr_t buff;
unsigned char cnt;
} out;
} union_t;
4 changes: 2 additions & 2 deletions test/IRGen/large_union.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ public func test1(_ s: some_struct) -> some_struct {
}
// CHECK: sil @$s1t5test1ySo11some_structaADF : $@convention(thin) (@in_guaranteed some_struct) -> @out some_struct {
// CHECK-NOT: unchecked_trivial_bitcast
// CHECK: unchecked_addr_cast {{.*}} : $*some_struct.__Unnamed_struct_out to $*some_struct
// CHECK: unchecked_addr_cast {{.*}} : $*some_struct to $*some_struct.__Unnamed_struct_out
// CHECK-NOT: unchecked_trivial_bitcast
// CHECK: } // end sil function '$s1t5test1ySo11some_structaADF'

// CHECK: sil @$s1t5test2yySo11some_structazF : $@convention(thin) (@inout some_struct) -> () {
// CHECK-NOT: unchecked_trivial_bitcast
// CHECK: unchecked_addr_cast {{.*}} : $*some_struct.__Unnamed_struct_out to $*some_struct
// CHECK: unchecked_addr_cast {{.*}} : $*some_struct to $*some_struct.__Unnamed_struct_out
// CHECK-NOT: unchecked_trivial_bitcast
// CHECK: } // end sil function '$s1t5test2yySo11some_structazF'

Expand Down
27 changes: 27 additions & 0 deletions test/IRGen/loadable_by_address_reg2mem.sil
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,30 @@ bb0(%0 : $*C1, %1 : $*Small):
%t = tuple ()
return %t : $()
}

sil @use : $@convention(thin) (UInt32) -> ()

// We need to make sure we use the bigger alloc_stack for the address of
// unchecked_trivial_bit_cast. A bitcast can go from bigger to smaller type.

// CHECK: sil @test11 : $@convention(thin) (@in union_t) -> () {
// CHECK-NOT: unchecked_addr_cast %1 : $*union_t.__Unnamed_struct_in to $*union_t
// CHECK: unchecked_addr_cast {{.*}} : $*union_t to $*union_t.__Unnamed_struct_in
// CHECK: } // end sil function 'test11'

sil @test11 : $@convention(thin) (@in union_t) -> () {
bb0(%0 : $*union_t):
%1 = alloc_stack $union_t
%2 = alloc_stack $union_t
copy_addr [take] %0 to [init] %2 : $*union_t
%4 = load %2 : $*union_t
%7 = unchecked_trivial_bit_cast %4 : $union_t to $union_t.__Unnamed_struct_in
%8 = struct_extract %7 : $union_t.__Unnamed_struct_in, #union_t.__Unnamed_struct_in.slot
%10 = struct_extract %8 : $enum_t, #enum_t.rawValue
%11 = function_ref @use : $@convention(thin) (UInt32) -> ()
%12 = apply %11(%10) : $@convention(thin) (UInt32) -> ()
%13 = tuple ()
dealloc_stack %2 : $*union_t
dealloc_stack %1 : $*union_t
return %13 : $()
}