Skip to content

Commit 018e797

Browse files
author
Joe Shajrawi
committed
Large loadable types pass: resolves a case wherein a tuple’s extracted type is a function signature
1 parent 0db10e9 commit 018e797

File tree

3 files changed

+110
-20
lines changed

3 files changed

+110
-20
lines changed

lib/IRGen/LoadableByAddress.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,8 @@ struct StructLoweringState {
307307
SmallVector<SwitchEnumInst *, 16> switchEnumInstsToMod;
308308
// All struct_extract instrs that should be converted to struct_element_addr
309309
SmallVector<StructExtractInst *, 16> structExtractInstsToMod;
310+
// All tuple instructions for which the return type is a function type
311+
SmallVector<SILInstruction *, 8> tupleInstsToMod;
310312
// All Retain and release instrs should be replaced with _addr version
311313
SmallVector<RetainValueInst *, 16> retainInstsToMod;
312314
SmallVector<ReleaseValueInst *, 16> releaseInstsToMod;
@@ -350,6 +352,7 @@ class LargeValueVisitor {
350352
void visitReleaseInst(ReleaseValueInst *instr);
351353
void visitResultTyInst(SILInstruction *instr);
352354
void visitDebugValueInst(DebugValueInst *instr);
355+
void visitTupleInst(SILInstruction *instr);
353356
void visitInstr(SILInstruction *instr);
354357
};
355358
} // end anonymous namespace
@@ -411,6 +414,11 @@ void LargeValueVisitor::mapValueStorage() {
411414
visitSwitchEnumInst(SEI);
412415
break;
413416
}
417+
case ValueKind::TupleElementAddrInst:
418+
case ValueKind::TupleExtractInst: {
419+
visitTupleInst(currIns);
420+
break;
421+
}
414422
default: {
415423
assert(!ApplySite::isa(currIns) && "Did not expect an ApplySite");
416424
assert(!dyn_cast<MethodInst>(currIns) && "Unhandled Method Inst");
@@ -607,6 +615,24 @@ void LargeValueVisitor::visitResultTyInst(SILInstruction *instr) {
607615
}
608616
}
609617

618+
void LargeValueVisitor::visitTupleInst(SILInstruction *instr) {
619+
SILType currSILType = instr->getType().getObjectType();
620+
CanType currCanType = currSILType.getSwiftRValueType();
621+
if (auto funcType = dyn_cast<SILFunctionType>(currCanType)) {
622+
CanSILFunctionType canFuncType = CanSILFunctionType(funcType);
623+
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
624+
if (!genEnv && canFuncType->isPolymorphic()) {
625+
genEnv = getGenericEnvironment(instr->getModule(), canFuncType);
626+
}
627+
SILFunctionType *newSILFunctionType =
628+
getNewSILFunctionTypePtr(genEnv, funcType, pass.Mod);
629+
if (funcType != newSILFunctionType) {
630+
pass.tupleInstsToMod.push_back(instr);
631+
}
632+
}
633+
visitInstr(instr);
634+
}
635+
610636
void LargeValueVisitor::visitInstr(SILInstruction *instr) {
611637
for (Operand &operand : instr->getAllOperands()) {
612638
if (std::find(pass.largeLoadableArgs.begin(), pass.largeLoadableArgs.end(),
@@ -1208,6 +1234,40 @@ static bool allUsesAreReplaceable(SILInstruction *instr,
12081234
return allUsesAreReplaceable;
12091235
}
12101236

1237+
static void castTupleInstr(SILInstruction *instr, IRGenModule &Mod) {
1238+
SILType currSILType = instr->getType().getObjectType();
1239+
CanType currCanType = currSILType.getSwiftRValueType();
1240+
SILFunctionType *funcType = dyn_cast<SILFunctionType>(currCanType);
1241+
assert(funcType && "Expcted SILFunctionType as tuple's return");
1242+
CanSILFunctionType canFuncType = CanSILFunctionType(funcType);
1243+
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
1244+
if (!genEnv && canFuncType->isPolymorphic()) {
1245+
genEnv = getGenericEnvironment(instr->getModule(), canFuncType);
1246+
}
1247+
SILType newSILType = getNewSILFunctionType(genEnv, funcType, Mod);
1248+
auto II = instr->getIterator();
1249+
++II;
1250+
SILBuilder castBuilder(II);
1251+
SILInstruction *castInstr = nullptr;
1252+
switch (instr->getKind()) {
1253+
// Add cast to the new sil function type:
1254+
case ValueKind::TupleExtractInst: {
1255+
castInstr = castBuilder.createUncheckedBitCast(instr->getLoc(), instr,
1256+
newSILType.getObjectType());
1257+
break;
1258+
}
1259+
case ValueKind::TupleElementAddrInst: {
1260+
castInstr = castBuilder.createUncheckedAddrCast(
1261+
instr->getLoc(), instr, newSILType.getAddressType());
1262+
break;
1263+
}
1264+
default:
1265+
llvm_unreachable("Unexpected instruction inside tupleInstsToMod");
1266+
}
1267+
instr->replaceAllUsesWith(castInstr);
1268+
castInstr->setOperand(0, instr);
1269+
}
1270+
12111271
static void rewriteFunction(StructLoweringState &pass,
12121272
LoadableStorageAllocation &allocator) {
12131273

@@ -1350,6 +1410,10 @@ static void rewriteFunction(StructLoweringState &pass,
13501410
}
13511411
}
13521412

1413+
for (SILInstruction *instr : pass.tupleInstsToMod) {
1414+
castTupleInstr(instr, pass.Mod);
1415+
}
1416+
13531417
for (SILInstruction *instr : pass.debugInstsToMod) {
13541418
assert(instr->getAllOperands().size() == 1 &&
13551419
"Debug instructions have one operand");

lib/SIL/SILVerifier.cpp

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,8 +1681,10 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
16811681
"member variables of struct");
16821682

16831683
SILType loweredType = structTy.getFieldType(field, F.getModule());
1684-
require((*opi)->getType() == loweredType,
1685-
"struct operand type does not match field type");
1684+
if (SI->getModule().getStage() != SILStage::Lowered) {
1685+
require((*opi)->getType() == loweredType,
1686+
"struct operand type does not match field type");
1687+
}
16861688
++opi;
16871689
}
16881690
}
@@ -1781,10 +1783,12 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
17811783
require(TI->getElements().size() == ResTy->getNumElements(),
17821784
"Tuple field count mismatch!");
17831785

1784-
for (size_t i = 0, size = TI->getElements().size(); i < size; ++i) {
1785-
require(TI->getElement(i)->getType().getSwiftRValueType()
1786-
== ResTy.getElementType(i),
1787-
"Tuple element arguments do not match tuple type!");
1786+
if (TI->getModule().getStage() != SILStage::Lowered) {
1787+
for (size_t i = 0, size = TI->getElements().size(); i < size; ++i) {
1788+
require(TI->getElement(i)->getType().getSwiftRValueType() ==
1789+
ResTy.getElementType(i),
1790+
"Tuple element arguments do not match tuple type!");
1791+
}
17881792
}
17891793
}
17901794

@@ -2009,9 +2013,11 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
20092013

20102014
require(EI->getFieldNo() < operandTy->getNumElements(),
20112015
"invalid field index for tuple_extract instruction");
2012-
require(EI->getType().getSwiftRValueType()
2013-
== operandTy.getElementType(EI->getFieldNo()),
2014-
"type of tuple_extract does not match type of element");
2016+
if (EI->getModule().getStage() != SILStage::Lowered) {
2017+
require(EI->getType().getSwiftRValueType() ==
2018+
operandTy.getElementType(EI->getFieldNo()),
2019+
"type of tuple_extract does not match type of element");
2020+
}
20152021
}
20162022

20172023
void checkStructExtractInst(StructExtractInst *EI) {
@@ -2030,10 +2036,12 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
20302036
require(EI->getField()->getDeclContext() == sd,
20312037
"struct_extract field is not a member of the struct");
20322038

2033-
SILType loweredFieldTy = operandTy.getFieldType(EI->getField(),
2034-
F.getModule());
2035-
require(loweredFieldTy == EI->getType(),
2036-
"result of struct_extract does not match type of field");
2039+
if (EI->getModule().getStage() != SILStage::Lowered) {
2040+
SILType loweredFieldTy =
2041+
operandTy.getFieldType(EI->getField(), F.getModule());
2042+
require(loweredFieldTy == EI->getType(),
2043+
"result of struct_extract does not match type of field");
2044+
}
20372045
}
20382046

20392047
void checkTupleElementAddrInst(TupleElementAddrInst *EI) {
@@ -2048,9 +2056,11 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
20482056
ArrayRef<TupleTypeElt> fields = operandTy.castTo<TupleType>()->getElements();
20492057
require(EI->getFieldNo() < fields.size(),
20502058
"invalid field index for element_addr instruction");
2051-
require(EI->getType().getSwiftRValueType()
2052-
== CanType(fields[EI->getFieldNo()].getType()),
2053-
"type of tuple_element_addr does not match type of element");
2059+
if (EI->getModule().getStage() != SILStage::Lowered) {
2060+
require(EI->getType().getSwiftRValueType() ==
2061+
CanType(fields[EI->getFieldNo()].getType()),
2062+
"type of tuple_element_addr does not match type of element");
2063+
}
20542064
}
20552065

20562066
void checkStructElementAddrInst(StructElementAddrInst *EI) {
@@ -2069,10 +2079,12 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
20692079
require(EI->getField()->getDeclContext() == sd,
20702080
"struct_element_addr field is not a member of the struct");
20712081

2072-
SILType loweredFieldTy = operandTy.getFieldType(EI->getField(),
2073-
F.getModule());
2074-
require(loweredFieldTy == EI->getType(),
2075-
"result of struct_element_addr does not match type of field");
2082+
if (EI->getModule().getStage() != SILStage::Lowered) {
2083+
SILType loweredFieldTy =
2084+
operandTy.getFieldType(EI->getField(), F.getModule());
2085+
require(loweredFieldTy == EI->getType(),
2086+
"result of struct_element_addr does not match type of field");
2087+
}
20762088
}
20772089

20782090
void checkRefElementAddrInst(RefElementAddrInst *EI) {

test/IRGen/big_types_corner_cases.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ public func f3_uses_f2() {
3232
// CHECK: call swiftcc void %16(%T22big_types_corner_cases9BigStructV* noalias nocapture sret %call.aggresult1, %T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable
3333
// CHECK: ret void
3434

35+
public func f4_tuple_use_of_f2() {
36+
let x = BigStruct()
37+
let tupleWithFunc = (f2_returns_f1(), x)
38+
let useOfF2 = tupleWithFunc.0
39+
let _ = useOfF2(x)
40+
}
41+
42+
// CHECK-LABEL: define{{( protected)?}} swiftcc void @_T022big_types_corner_cases18f4_tuple_use_of_f2yyF()
43+
// CHECK: [[TUPLE:%.*]] = call swiftcc { i8*, %swift.refcounted* } @_T022big_types_corner_cases13f2_returns_f1AA9BigStructVADcyF()
44+
// CHECK: [[TUPLE_EXTRACT:%.*]] = extractvalue { i8*, %swift.refcounted* } [[TUPLE]], 0
45+
// CHECK: [[CAST_EXTRACT:%.*]] = bitcast i8* [[TUPLE_EXTRACT]] to void (%T22big_types_corner_cases9BigStructV*, %T22big_types_corner_cases9BigStructV*, %swift.refcounted*)*
46+
// CHECK: call swiftcc void [[CAST_EXTRACT]](%T22big_types_corner_cases9BigStructV* noalias nocapture sret %call.aggresult1, %T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable
47+
// CHECK: ret void
48+
3549
public struct MyStruct {
3650
public let a: Int
3751
public let b: String?

0 commit comments

Comments
 (0)