Skip to content

Commit 650eeb8

Browse files
authored
[ShrinkWrap] Modify shrink wrapping to accommodate functions terminated by no-return blocks (#167548)
At present, the shrink wrapping pass misses opportunities to shrink wrap in the presence of machine basic blocks which exit the function without returning. Such cases arise from C++ functions like the following: ```cxx int foo(int err, void* ptr) { if (err == -1) { if (ptr == nullptr) { throw MyException("Received `nullptr`!", __FILE__, __LINE__); } handle(ptr); } return STATUS_OK; } ``` In particular, assuming `MyException`'s constructor is not marked `noexcept`, the above code will generate a trivial EH landing pad calling `__cxa_free_exception()` and rethrowing the unhandled internal exception, exiting the function without returning. As such, the shrink wrapping pass refuses to touch the above function, spilling to the stack on every call, even though no CSRs are clobbered on the hot path. This patch tweaks the shrink wrapping logic to enable the pass to fire in this and similar cases.
1 parent c28c99f commit 650eeb8

File tree

3 files changed

+191
-7
lines changed

3 files changed

+191
-7
lines changed

llvm/include/llvm/CodeGen/MachineBasicBlock.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,13 @@ class MachineBasicBlock
988988
return !empty() && back().isEHScopeReturn();
989989
}
990990

991+
/// Convenience function that returns true if the block exits the function
992+
/// without returning.
993+
bool isNoReturnBlock() const {
994+
return !empty() && succ_empty() && !back().isReturn() &&
995+
!back().isIndirectBranch();
996+
}
997+
991998
/// Split a basic block into 2 pieces at \p SplitPoint. A new block will be
992999
/// inserted after this block, and all instructions after \p SplitInst moved
9931000
/// to it (\p SplitInst will be in the original block). If \p LIS is provided,

llvm/lib/CodeGen/ShrinkWrap.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -697,14 +697,12 @@ void ShrinkWrapImpl::updateSaveRestorePoints(MachineBasicBlock &MBB,
697697

698698
if (!Restore)
699699
Restore = &MBB;
700-
else if (MPDT->getNode(&MBB)) // If the block is not in the post dom tree, it
701-
// means the block never returns. If that's the
702-
// case, we don't want to call
703-
// `findNearestCommonDominator`, which will
704-
// return `Restore`.
700+
else if (MBB.isNoReturnBlock()) {
701+
// MBB exits the function without returning, so we don't need an epilogue
702+
// here. This is common for things like cleanup landing pads etc. In these
703+
// cases, we can skip updating `Restore`.
704+
} else
705705
Restore = MPDT->findNearestCommonDominator(Restore, &MBB);
706-
else
707-
Restore = nullptr; // Abort, we can't find a restore point in this case.
708706

709707
// Make sure we would be able to insert the restore code before the
710708
// terminator.

llvm/test/CodeGen/AArch64/arm64-shrink-wrapping.ll

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,3 +1192,182 @@ false:
11921192

11931193
ret void
11941194
}
1195+
1196+
@exception = external hidden constant { ptr, ptr, ptr }
1197+
1198+
define noundef i32 @call_with_no_ret(i32 %in) personality ptr @__gxx_personality_v0 {
1199+
; ENABLE-LABEL: call_with_no_ret:
1200+
; ENABLE: Lfunc_begin0:
1201+
; ENABLE-NEXT: .cfi_startproc
1202+
; ENABLE-NEXT: .cfi_personality 155, ___gxx_personality_v0
1203+
; ENABLE-NEXT: .cfi_lsda 16, Lexception0
1204+
; ENABLE-NEXT: ; %bb.0: ; %entry
1205+
; ENABLE-NEXT: cmp w0, #1
1206+
; ENABLE-NEXT: b.eq LBB15_2
1207+
; ENABLE-NEXT: ; %bb.1: ; %exit
1208+
; ENABLE-NEXT: mov w0, wzr
1209+
; ENABLE-NEXT: ret
1210+
; ENABLE-NEXT: LBB15_2: ; %setup
1211+
; ENABLE-NEXT: stp x20, x19, [sp, #-32]! ; 16-byte Folded Spill
1212+
; ENABLE-NEXT: stp x29, x30, [sp, #16] ; 16-byte Folded Spill
1213+
; ENABLE-NEXT: add x29, sp, #16
1214+
; ENABLE-NEXT: .cfi_def_cfa w29, 16
1215+
; ENABLE-NEXT: .cfi_offset w30, -8
1216+
; ENABLE-NEXT: .cfi_offset w29, -16
1217+
; ENABLE-NEXT: .cfi_offset w19, -24
1218+
; ENABLE-NEXT: .cfi_offset w20, -32
1219+
; ENABLE-NEXT: mov w0, #32 ; =0x20
1220+
; ENABLE-NEXT: bl ___cxa_allocate_exception
1221+
; ENABLE-NEXT: Ltmp0: ; EH_LABEL
1222+
; ENABLE-NEXT: bl _construct_exception
1223+
; ENABLE-NEXT: Ltmp1: ; EH_LABEL
1224+
; ENABLE-NEXT: ldp x29, x30, [sp, #16] ; 16-byte Folded Reload
1225+
; ENABLE-NEXT: ldp x20, x19, [sp], #32 ; 16-byte Folded Reload
1226+
; ENABLE-NEXT: ; %bb.3: ; %throw
1227+
; ENABLE-NEXT: Lloh0:
1228+
; ENABLE-NEXT: adrp x2, _destruct_exception@GOTPAGE
1229+
; ENABLE-NEXT: Lloh1:
1230+
; ENABLE-NEXT: ldr x2, [x2, _destruct_exception@GOTPAGEOFF]
1231+
; ENABLE-NEXT: Lloh2:
1232+
; ENABLE-NEXT: adrp x1, _exception@PAGE
1233+
; ENABLE-NEXT: Lloh3:
1234+
; ENABLE-NEXT: add x1, x1, _exception@PAGEOFF
1235+
; ENABLE-NEXT: mov x0, x19
1236+
; ENABLE-NEXT: bl ___cxa_throw
1237+
; ENABLE-NEXT: LBB15_4: ; %teardown
1238+
; ENABLE-NEXT: Ltmp2: ; EH_LABEL
1239+
; ENABLE-NEXT: mov x20, x0
1240+
; ENABLE-NEXT: mov x0, x19
1241+
; ENABLE-NEXT: bl ___cxa_free_exception
1242+
; ENABLE-NEXT: mov x0, x20
1243+
; ENABLE-NEXT: bl __Unwind_Resume
1244+
; ENABLE-NEXT: .loh AdrpAdd Lloh2, Lloh3
1245+
; ENABLE-NEXT: .loh AdrpLdrGot Lloh0, Lloh1
1246+
; ENABLE-NEXT: Lfunc_end0:
1247+
; ENABLE-NEXT: .cfi_endproc
1248+
; ENABLE-NEXT: .section __TEXT,__gcc_except_tab
1249+
; ENABLE-NEXT: .p2align 2, 0x0
1250+
; ENABLE-NEXT: GCC_except_table15:
1251+
; ENABLE-NEXT: Lexception0:
1252+
; ENABLE-NEXT: .byte 255 ; @LPStart Encoding = omit
1253+
; ENABLE-NEXT: .byte 255 ; @TType Encoding = omit
1254+
; ENABLE-NEXT: .byte 1 ; Call site Encoding = uleb128
1255+
; ENABLE-NEXT: .uleb128 Lcst_end0-Lcst_begin0
1256+
; ENABLE-NEXT: Lcst_begin0:
1257+
; ENABLE-NEXT: .uleb128 Lfunc_begin0-Lfunc_begin0 ; >> Call Site 1 <<
1258+
; ENABLE-NEXT: .uleb128 Ltmp0-Lfunc_begin0 ; Call between Lfunc_begin0 and Ltmp0
1259+
; ENABLE-NEXT: .byte 0 ; has no landing pad
1260+
; ENABLE-NEXT: .byte 0 ; On action: cleanup
1261+
; ENABLE-NEXT: .uleb128 Ltmp0-Lfunc_begin0 ; >> Call Site 2 <<
1262+
; ENABLE-NEXT: .uleb128 Ltmp1-Ltmp0 ; Call between Ltmp0 and Ltmp1
1263+
; ENABLE-NEXT: .uleb128 Ltmp2-Lfunc_begin0 ; jumps to Ltmp2
1264+
; ENABLE-NEXT: .byte 0 ; On action: cleanup
1265+
; ENABLE-NEXT: .uleb128 Ltmp1-Lfunc_begin0 ; >> Call Site 3 <<
1266+
; ENABLE-NEXT: .uleb128 Lfunc_end0-Ltmp1 ; Call between Ltmp1 and Lfunc_end0
1267+
; ENABLE-NEXT: .byte 0 ; has no landing pad
1268+
; ENABLE-NEXT: .byte 0 ; On action: cleanup
1269+
; ENABLE-NEXT: Lcst_end0:
1270+
; ENABLE-NEXT: .p2align 2, 0x0
1271+
;
1272+
; DISABLE-LABEL: call_with_no_ret:
1273+
; DISABLE: Lfunc_begin0:
1274+
; DISABLE-NEXT: .cfi_startproc
1275+
; DISABLE-NEXT: .cfi_personality 155, ___gxx_personality_v0
1276+
; DISABLE-NEXT: .cfi_lsda 16, Lexception0
1277+
; DISABLE-NEXT: ; %bb.0: ; %entry
1278+
; DISABLE-NEXT: stp x20, x19, [sp, #-32]! ; 16-byte Folded Spill
1279+
; DISABLE-NEXT: stp x29, x30, [sp, #16] ; 16-byte Folded Spill
1280+
; DISABLE-NEXT: add x29, sp, #16
1281+
; DISABLE-NEXT: .cfi_def_cfa w29, 16
1282+
; DISABLE-NEXT: .cfi_offset w30, -8
1283+
; DISABLE-NEXT: .cfi_offset w29, -16
1284+
; DISABLE-NEXT: .cfi_offset w19, -24
1285+
; DISABLE-NEXT: .cfi_offset w20, -32
1286+
; DISABLE-NEXT: cmp w0, #1
1287+
; DISABLE-NEXT: b.eq LBB15_2
1288+
; DISABLE-NEXT: ; %bb.1: ; %exit
1289+
; DISABLE-NEXT: mov w0, wzr
1290+
; DISABLE-NEXT: ldp x29, x30, [sp, #16] ; 16-byte Folded Reload
1291+
; DISABLE-NEXT: ldp x20, x19, [sp], #32 ; 16-byte Folded Reload
1292+
; DISABLE-NEXT: ret
1293+
; DISABLE-NEXT: LBB15_2: ; %setup
1294+
; DISABLE-NEXT: mov w0, #32 ; =0x20
1295+
; DISABLE-NEXT: bl ___cxa_allocate_exception
1296+
; DISABLE-NEXT: mov x19, x0
1297+
; DISABLE-NEXT: Ltmp0: ; EH_LABEL
1298+
; DISABLE-NEXT: bl _construct_exception
1299+
; DISABLE-NEXT: Ltmp1: ; EH_LABEL
1300+
; DISABLE-NEXT: ; %bb.3: ; %throw
1301+
; DISABLE-NEXT: Lloh0:
1302+
; DISABLE-NEXT: adrp x2, _destruct_exception@GOTPAGE
1303+
; DISABLE-NEXT: Lloh1:
1304+
; DISABLE-NEXT: ldr x2, [x2, _destruct_exception@GOTPAGEOFF]
1305+
; DISABLE-NEXT: Lloh2:
1306+
; DISABLE-NEXT: adrp x1, _exception@PAGE
1307+
; DISABLE-NEXT: Lloh3:
1308+
; DISABLE-NEXT: add x1, x1, _exception@PAGEOFF
1309+
; DISABLE-NEXT: mov x0, x19
1310+
; DISABLE-NEXT: bl ___cxa_throw
1311+
; DISABLE-NEXT: LBB15_4: ; %teardown
1312+
; DISABLE-NEXT: Ltmp2: ; EH_LABEL
1313+
; DISABLE-NEXT: mov x20, x0
1314+
; DISABLE-NEXT: mov x0, x19
1315+
; DISABLE-NEXT: bl ___cxa_free_exception
1316+
; DISABLE-NEXT: mov x0, x20
1317+
; DISABLE-NEXT: bl __Unwind_Resume
1318+
; DISABLE-NEXT: .loh AdrpAdd Lloh2, Lloh3
1319+
; DISABLE-NEXT: .loh AdrpLdrGot Lloh0, Lloh1
1320+
; DISABLE-NEXT: Lfunc_end0:
1321+
; DISABLE-NEXT: .cfi_endproc
1322+
; DISABLE-NEXT: .section __TEXT,__gcc_except_tab
1323+
; DISABLE-NEXT: .p2align 2, 0x0
1324+
; DISABLE-NEXT: GCC_except_table15:
1325+
; DISABLE-NEXT: Lexception0:
1326+
; DISABLE-NEXT: .byte 255 ; @LPStart Encoding = omit
1327+
; DISABLE-NEXT: .byte 255 ; @TType Encoding = omit
1328+
; DISABLE-NEXT: .byte 1 ; Call site Encoding = uleb128
1329+
; DISABLE-NEXT: .uleb128 Lcst_end0-Lcst_begin0
1330+
; DISABLE-NEXT: Lcst_begin0:
1331+
; DISABLE-NEXT: .uleb128 Lfunc_begin0-Lfunc_begin0 ; >> Call Site 1 <<
1332+
; DISABLE-NEXT: .uleb128 Ltmp0-Lfunc_begin0 ; Call between Lfunc_begin0 and Ltmp0
1333+
; DISABLE-NEXT: .byte 0 ; has no landing pad
1334+
; DISABLE-NEXT: .byte 0 ; On action: cleanup
1335+
; DISABLE-NEXT: .uleb128 Ltmp0-Lfunc_begin0 ; >> Call Site 2 <<
1336+
; DISABLE-NEXT: .uleb128 Ltmp1-Ltmp0 ; Call between Ltmp0 and Ltmp1
1337+
; DISABLE-NEXT: .uleb128 Ltmp2-Lfunc_begin0 ; jumps to Ltmp2
1338+
; DISABLE-NEXT: .byte 0 ; On action: cleanup
1339+
; DISABLE-NEXT: .uleb128 Ltmp1-Lfunc_begin0 ; >> Call Site 3 <<
1340+
; DISABLE-NEXT: .uleb128 Lfunc_end0-Ltmp1 ; Call between Ltmp1 and Lfunc_end0
1341+
; DISABLE-NEXT: .byte 0 ; has no landing pad
1342+
; DISABLE-NEXT: .byte 0 ; On action: cleanup
1343+
; DISABLE-NEXT: Lcst_end0:
1344+
; DISABLE-NEXT: .p2align 2, 0x0
1345+
entry:
1346+
%cmp = icmp eq i32 %in, 1
1347+
br i1 %cmp, label %setup, label %exit
1348+
1349+
setup:
1350+
%exception = tail call ptr @__cxa_allocate_exception(i64 32) nounwind
1351+
%call = invoke noundef ptr @construct_exception(ptr noundef nonnull %exception) to label %throw unwind label %teardown
1352+
1353+
throw:
1354+
tail call void @__cxa_throw(ptr nonnull %exception, ptr nonnull @exception, ptr nonnull @destruct_exception) noreturn
1355+
unreachable
1356+
1357+
teardown:
1358+
%caught = landingpad { ptr, i32 } cleanup
1359+
tail call void @__cxa_free_exception(ptr nonnull %exception) nounwind
1360+
resume { ptr, i32 } %caught
1361+
1362+
exit:
1363+
ret i32 0
1364+
}
1365+
1366+
declare i32 @__gxx_personality_v0(...)
1367+
1368+
declare ptr @__cxa_allocate_exception(i64) local_unnamed_addr
1369+
declare void @__cxa_free_exception(ptr) local_unnamed_addr
1370+
declare void @__cxa_throw(ptr, ptr, ptr) local_unnamed_addr cold noreturn
1371+
1372+
declare noundef ptr @construct_exception(ptr noundef nonnull returned) unnamed_addr
1373+
declare noundef ptr @destruct_exception(ptr noundef nonnull returned) unnamed_addr mustprogress nounwind ssp uwtable(sync)

0 commit comments

Comments
 (0)