Skip to content

Commit 6dc5bf3

Browse files
committed
[6.1] LargeLoadable types: propagate large type property along projections
Explanation: Back propagate the isLargeType property along projections. This is neccessary because c union types can "hide" largeness. Without this change the compiler would crash because an operand of a projection (struct_extract, tuple_extract) would be deemed small but the projected element would be deemed large. The stack location for the operand would therefore be missing when lowering to addresses. Scope: Corner case involving large c type lowering. Risk: Medium. Should only affect c union types. Original PR: #78321 rdar://141775951
1 parent 12fb6cb commit 6dc5bf3

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

lib/IRGen/LoadableByAddress.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3500,6 +3500,8 @@ class LargeLoadableHeuristic {
35003500
bool isLargeLoadableType(SILType ty);
35013501
bool isPotentiallyCArray(SILType ty);
35023502

3503+
void propagate(PostOrderFunctionInfo &po);
3504+
35033505
private:
35043506
bool isLargeLoadableTypeOld(SILType ty);
35053507

@@ -3541,6 +3543,32 @@ class LargeLoadableHeuristic {
35413543
};
35423544
}
35433545

3546+
void LargeLoadableHeuristic::propagate(PostOrderFunctionInfo &po) {
3547+
if (!UseAggressiveHeuristic)
3548+
return;
3549+
3550+
for (auto *BB : po.getPostOrder()) {
3551+
for (auto &I : llvm::reverse(*BB)) {
3552+
switch (I.getKind()) {
3553+
case SILInstructionKind::TupleExtractInst:
3554+
case SILInstructionKind::StructExtractInst: {
3555+
auto &proj = cast<SingleValueInstruction>(I);
3556+
if (isLargeLoadableType(proj.getType())) {
3557+
auto opdTy = proj.getOperand(0)->getType();
3558+
auto entry = largeTypeProperties[opdTy];
3559+
entry.setNumRegisters(65535);
3560+
largeTypeProperties[opdTy] = entry;
3561+
}
3562+
}
3563+
break;
3564+
3565+
default:
3566+
continue;
3567+
}
3568+
}
3569+
}
3570+
}
3571+
35443572
void LargeLoadableHeuristic::visit(SILArgument *arg) {
35453573
auto objType = arg->getType().getObjectType();
35463574
if (numRegisters(objType) < NumRegistersLargeType)
@@ -4655,6 +4683,9 @@ static void runPeepholesAndReg2Mem(SILPassManager *pm, SILModule *silMod,
46554683
// Delete replaced instructions.
46564684
opts.deleteInstructions();
46574685

4686+
PostOrderFunctionInfo postorderInfo(&currF);
4687+
heuristic.propagate(postorderInfo);
4688+
46584689
AddressAssignment assignment(heuristic, irgenModule, currF);
46594690

46604691
// Assign addresses to basic block arguments.
@@ -4725,7 +4756,6 @@ static void runPeepholesAndReg2Mem(SILPassManager *pm, SILModule *silMod,
47254756
}
47264757

47274758
// Asign addresses to non-address SSA values.
4728-
PostOrderFunctionInfo postorderInfo(&currF);
47294759
for (auto *BB : postorderInfo.getReversePostOrder()) {
47304760
SmallVector<SILInstruction *, 32> origInsts;
47314761
for (SILInstruction &i : *BB) {

test/IRGen/Inputs/large_c.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,19 @@ typedef union {
7878
unsigned char cnt;
7979
} out;
8080
} union_t;
81+
82+
83+
typedef enum {
84+
TYPE1,
85+
TYPE2,
86+
TYPE3
87+
} member_type_t;
88+
89+
typedef unsigned char uuid_t[16];
90+
typedef struct {
91+
member_type_t member_type;
92+
union {
93+
uuid_t uuid;
94+
unsigned x;
95+
} member_value;
96+
} member_id_t;

test/IRGen/loadable_by_address_reg2mem.sil

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
// RUN: %target-swift-frontend %s -Xllvm -sil-print-after=loadable-address -import-objc-header %S/Inputs/large_c.h -c -o %t/t.o 2>&1 | %FileCheck %s
22

3+
// wasm currently disables aggressive reg2mem
4+
// UNSUPPORTED: wasm
5+
// UNSUPPORTED: OS=wasi
6+
// UNSUPPORTED: CPU=wasm32
7+
38
sil_stage canonical
49

510
import Builtin
@@ -397,3 +402,25 @@ bb3(%4 : $X):
397402
%t = tuple ()
398403
return %t : $()
399404
}
405+
406+
sil @usei8 : $@convention(thin) (UInt8) -> ()
407+
408+
// CHECK: sil @test16
409+
// CHECK: bb0(%0 : $member_id_t):
410+
// CHECK: [[T0:%.*]] = alloc_stack $member_id_t
411+
// CHECK: store %0 to [[T0]] : $*member_id_t
412+
// CHECK: struct_element_addr [[T0]]
413+
// CHECK:} // end sil function 'test16'
414+
415+
sil @test16 : $@convention(thin) (member_id_t) -> () {
416+
bb0(%0 : $member_id_t):
417+
%2 = alloc_stack $X
418+
%44 = struct_extract %0 : $member_id_t, #member_id_t.member_value // user: %45
419+
%45 = unchecked_trivial_bit_cast %44 : $member_id_t.__Unnamed_union_member_value to $(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)
420+
%46 = tuple_extract %45 : $(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8), 0
421+
%11 = function_ref @usei8 : $@convention(thin) (UInt8) -> ()
422+
%12 = apply %11(%46) : $@convention(thin) (UInt8) -> ()
423+
dealloc_stack %2 : $*X
424+
%13 = tuple ()
425+
return %13 : $()
426+
}

0 commit comments

Comments
 (0)