24
24
#include " llvm/ADT/Statistic.h"
25
25
#include " llvm/ADT/StringRef.h"
26
26
#include " llvm/ADT/TinyPtrVector.h"
27
+ #include " llvm/Analysis/TargetTransformInfo.h"
27
28
#include " llvm/Analysis/TypeMetadataUtils.h"
28
29
#include " llvm/Analysis/ValueTracking.h"
29
30
#include " llvm/IR/Attributes.h"
@@ -406,6 +407,15 @@ class LowerTypeTestsModule {
406
407
Triple::OSType OS;
407
408
Triple::ObjectFormatType ObjectFormat;
408
409
410
+ // Determines which kind of Thumb jump table we generate. If arch is
411
+ // either 'arm' or 'thumb' we need to find this out, because
412
+ // selectJumpTableArmEncoding may decide to use Thumb in either case.
413
+ bool CanUseArmJumpTable = false , CanUseThumbBWJumpTable = false ;
414
+
415
+ // The jump table type we ended up deciding on. (Usually the same as
416
+ // Arch, except that 'arm' and 'thumb' are often interchangeable.)
417
+ Triple::ArchType JumpTableArch = Triple::UnknownArch;
418
+
409
419
IntegerType *Int1Ty = Type::getInt1Ty(M.getContext());
410
420
IntegerType *Int8Ty = Type::getInt8Ty(M.getContext());
411
421
PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
@@ -481,6 +491,8 @@ class LowerTypeTestsModule {
481
491
482
492
void buildBitSetsFromGlobalVariables (ArrayRef<Metadata *> TypeIds,
483
493
ArrayRef<GlobalTypeMember *> Globals);
494
+ Triple::ArchType
495
+ selectJumpTableArmEncoding (ArrayRef<GlobalTypeMember *> Functions);
484
496
unsigned getJumpTableEntrySize ();
485
497
Type *getJumpTableEntryType ();
486
498
void createJumpTableEntry (raw_ostream &AsmOS, raw_ostream &ConstraintOS,
@@ -518,15 +530,16 @@ class LowerTypeTestsModule {
518
530
void replaceDirectCalls (Value *Old, Value *New);
519
531
520
532
public:
521
- LowerTypeTestsModule (Module &M, ModuleSummaryIndex *ExportSummary,
533
+ LowerTypeTestsModule (Module &M, ModuleAnalysisManager &AM,
534
+ ModuleSummaryIndex *ExportSummary,
522
535
const ModuleSummaryIndex *ImportSummary,
523
536
bool DropTypeTests);
524
537
525
538
bool lower ();
526
539
527
540
// Lower the module using the action and summary passed as command line
528
541
// arguments. For testing purposes only.
529
- static bool runForTesting (Module &M);
542
+ static bool runForTesting (Module &M, ModuleAnalysisManager &AM );
530
543
};
531
544
} // end anonymous namespace
532
545
@@ -1182,31 +1195,36 @@ static const unsigned kX86JumpTableEntrySize = 8;
1182
1195
static const unsigned kX86IBTJumpTableEntrySize = 16 ;
1183
1196
static const unsigned kARMJumpTableEntrySize = 4 ;
1184
1197
static const unsigned kARMBTIJumpTableEntrySize = 8 ;
1198
+ static const unsigned kARMv6MJumpTableEntrySize = 16 ;
1185
1199
static const unsigned kRISCVJumpTableEntrySize = 8 ;
1186
1200
1187
1201
unsigned LowerTypeTestsModule::getJumpTableEntrySize () {
1188
- switch (Arch ) {
1189
- case Triple::x86:
1190
- case Triple::x86_64:
1191
- if (const auto *MD = mdconst::extract_or_null<ConstantInt>(
1202
+ switch (JumpTableArch ) {
1203
+ case Triple::x86:
1204
+ case Triple::x86_64:
1205
+ if (const auto *MD = mdconst::extract_or_null<ConstantInt>(
1192
1206
M.getModuleFlag (" cf-protection-branch" )))
1193
- if (MD->getZExtValue ())
1194
- return kX86IBTJumpTableEntrySize ;
1195
- return kX86JumpTableEntrySize ;
1196
- case Triple::arm:
1197
- case Triple::thumb:
1207
+ if (MD->getZExtValue ())
1208
+ return kX86IBTJumpTableEntrySize ;
1209
+ return kX86JumpTableEntrySize ;
1210
+ case Triple::arm:
1211
+ return kARMJumpTableEntrySize ;
1212
+ case Triple::thumb:
1213
+ if (CanUseThumbBWJumpTable)
1198
1214
return kARMJumpTableEntrySize ;
1199
- case Triple::aarch64:
1200
- if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
1215
+ else
1216
+ return kARMv6MJumpTableEntrySize ;
1217
+ case Triple::aarch64:
1218
+ if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
1201
1219
M.getModuleFlag (" branch-target-enforcement" )))
1202
- if (BTE->getZExtValue ())
1203
- return kARMBTIJumpTableEntrySize ;
1204
- return kARMJumpTableEntrySize ;
1205
- case Triple::riscv32:
1206
- case Triple::riscv64:
1207
- return kRISCVJumpTableEntrySize ;
1208
- default :
1209
- report_fatal_error (" Unsupported architecture for jump tables" );
1220
+ if (BTE->getZExtValue ())
1221
+ return kARMBTIJumpTableEntrySize ;
1222
+ return kARMJumpTableEntrySize ;
1223
+ case Triple::riscv32:
1224
+ case Triple::riscv64:
1225
+ return kRISCVJumpTableEntrySize ;
1226
+ default :
1227
+ report_fatal_error (" Unsupported architecture for jump tables" );
1210
1228
}
1211
1229
}
1212
1230
@@ -1240,7 +1258,32 @@ void LowerTypeTestsModule::createJumpTableEntry(
1240
1258
AsmOS << " bti c\n " ;
1241
1259
AsmOS << " b $" << ArgIndex << " \n " ;
1242
1260
} else if (JumpTableArch == Triple::thumb) {
1243
- AsmOS << " b.w $" << ArgIndex << " \n " ;
1261
+ if (!CanUseThumbBWJumpTable) {
1262
+ // In Armv6-M, this sequence will generate a branch without corrupting
1263
+ // any registers. We use two stack words; in the second, we construct the
1264
+ // address we'll pop into pc, and the first is used to save and restore
1265
+ // r0 which we use as a temporary register.
1266
+ //
1267
+ // To support position-independent use cases, the offset of the target
1268
+ // function is stored as a relative offset (which will expand into an
1269
+ // R_ARM_REL32 relocation in ELF, and presumably the equivalent in other
1270
+ // object file types), and added to pc after we load it. (The alternative
1271
+ // B.W is automatically pc-relative.)
1272
+ //
1273
+ // There are five 16-bit Thumb instructions here, so the .balign 4 adds a
1274
+ // sixth halfword of padding, and then the offset consumes a further 4
1275
+ // bytes, for a total of 16, which is very convenient since entries in
1276
+ // this jump table need to have power-of-two size.
1277
+ AsmOS << " push {r0,r1}\n "
1278
+ << " ldr r0, 1f\n "
1279
+ << " 0: add r0, r0, pc\n "
1280
+ << " str r0, [sp, #4]\n "
1281
+ << " pop {r0,pc}\n "
1282
+ << " .balign 4\n "
1283
+ << " 1: .word $" << ArgIndex << " - (0b + 4)\n " ;
1284
+ } else {
1285
+ AsmOS << " b.w $" << ArgIndex << " \n " ;
1286
+ }
1244
1287
} else if (JumpTableArch == Triple::riscv32 ||
1245
1288
JumpTableArch == Triple::riscv64) {
1246
1289
AsmOS << " tail $" << ArgIndex << " @plt\n " ;
@@ -1352,12 +1395,19 @@ static bool isThumbFunction(Function *F, Triple::ArchType ModuleArch) {
1352
1395
// Each jump table must be either ARM or Thumb as a whole for the bit-test math
1353
1396
// to work. Pick one that matches the majority of members to minimize interop
1354
1397
// veneers inserted by the linker.
1355
- static Triple::ArchType
1356
- selectJumpTableArmEncoding (ArrayRef<GlobalTypeMember *> Functions,
1357
- Triple::ArchType ModuleArch) {
1358
- if (ModuleArch != Triple::arm && ModuleArch != Triple::thumb)
1359
- return ModuleArch;
1398
+ Triple::ArchType LowerTypeTestsModule::selectJumpTableArmEncoding (
1399
+ ArrayRef<GlobalTypeMember *> Functions) {
1400
+ if (Arch != Triple::arm && Arch != Triple::thumb)
1401
+ return Arch;
1402
+
1403
+ if (!CanUseThumbBWJumpTable && CanUseArmJumpTable) {
1404
+ // In architectures that provide Arm and Thumb-1 but not Thumb-2,
1405
+ // we should always prefer the Arm jump table format, because the
1406
+ // Thumb-1 one is larger and slower.
1407
+ return Triple::arm;
1408
+ }
1360
1409
1410
+ // Otherwise, go with majority vote.
1361
1411
unsigned ArmCount = 0 , ThumbCount = 0 ;
1362
1412
for (const auto GTM : Functions) {
1363
1413
if (!GTM->isJumpTableCanonical ()) {
@@ -1368,7 +1418,7 @@ selectJumpTableArmEncoding(ArrayRef<GlobalTypeMember *> Functions,
1368
1418
}
1369
1419
1370
1420
Function *F = cast<Function>(GTM->getGlobal ());
1371
- ++(isThumbFunction (F, ModuleArch ) ? ThumbCount : ArmCount);
1421
+ ++(isThumbFunction (F, Arch ) ? ThumbCount : ArmCount);
1372
1422
}
1373
1423
1374
1424
return ArmCount > ThumbCount ? Triple::arm : Triple::thumb;
@@ -1381,8 +1431,6 @@ void LowerTypeTestsModule::createJumpTable(
1381
1431
SmallVector<Value *, 16 > AsmArgs;
1382
1432
AsmArgs.reserve (Functions.size () * 2 );
1383
1433
1384
- Triple::ArchType JumpTableArch = selectJumpTableArmEncoding (Functions, Arch);
1385
-
1386
1434
for (GlobalTypeMember *GTM : Functions)
1387
1435
createJumpTableEntry (AsmOS, ConstraintOS, JumpTableArch, AsmArgs,
1388
1436
cast<Function>(GTM->getGlobal ()));
@@ -1399,9 +1447,11 @@ void LowerTypeTestsModule::createJumpTable(
1399
1447
F->addFnAttr (" target-features" , " -thumb-mode" );
1400
1448
if (JumpTableArch == Triple::thumb) {
1401
1449
F->addFnAttr (" target-features" , " +thumb-mode" );
1402
- // Thumb jump table assembly needs Thumb2. The following attribute is added
1403
- // by Clang for -march=armv7.
1404
- F->addFnAttr (" target-cpu" , " cortex-a8" );
1450
+ if (CanUseThumbBWJumpTable) {
1451
+ // Thumb jump table assembly needs Thumb2. The following attribute is
1452
+ // added by Clang for -march=armv7.
1453
+ F->addFnAttr (" target-cpu" , " cortex-a8" );
1454
+ }
1405
1455
}
1406
1456
// When -mbranch-protection= is used, the inline asm adds a BTI. Suppress BTI
1407
1457
// for the function to avoid double BTI. This is a no-op without
@@ -1521,6 +1571,10 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
1521
1571
// FIXME: find a better way to represent the jumptable in the IR.
1522
1572
assert (!Functions.empty ());
1523
1573
1574
+ // Decide on the jump table encoding, so that we know how big the
1575
+ // entries will be.
1576
+ JumpTableArch = selectJumpTableArmEncoding (Functions);
1577
+
1524
1578
// Build a simple layout based on the regular layout of jump tables.
1525
1579
DenseMap<GlobalTypeMember *, uint64_t > GlobalLayout;
1526
1580
unsigned EntrySize = getJumpTableEntrySize ();
@@ -1706,18 +1760,31 @@ void LowerTypeTestsModule::buildBitSetsFromDisjointSet(
1706
1760
1707
1761
// / Lower all type tests in this module.
1708
1762
LowerTypeTestsModule::LowerTypeTestsModule (
1709
- Module &M, ModuleSummaryIndex *ExportSummary,
1763
+ Module &M, ModuleAnalysisManager &AM, ModuleSummaryIndex *ExportSummary,
1710
1764
const ModuleSummaryIndex *ImportSummary, bool DropTypeTests)
1711
1765
: M(M), ExportSummary(ExportSummary), ImportSummary(ImportSummary),
1712
1766
DropTypeTests(DropTypeTests || ClDropTypeTests) {
1713
1767
assert (!(ExportSummary && ImportSummary));
1714
1768
Triple TargetTriple (M.getTargetTriple ());
1715
1769
Arch = TargetTriple.getArch ();
1770
+ if (Arch == Triple::arm)
1771
+ CanUseArmJumpTable = true ;
1772
+ if (Arch == Triple::arm || Arch == Triple::thumb) {
1773
+ auto &FAM =
1774
+ AM.getResult <FunctionAnalysisManagerModuleProxy>(M).getManager ();
1775
+ for (Function &F : M) {
1776
+ auto &TTI = FAM.getResult <TargetIRAnalysis>(F);
1777
+ if (TTI.hasArmWideBranch (false ))
1778
+ CanUseArmJumpTable = true ;
1779
+ if (TTI.hasArmWideBranch (true ))
1780
+ CanUseThumbBWJumpTable = true ;
1781
+ }
1782
+ }
1716
1783
OS = TargetTriple.getOS ();
1717
1784
ObjectFormat = TargetTriple.getObjectFormat ();
1718
1785
}
1719
1786
1720
- bool LowerTypeTestsModule::runForTesting (Module &M) {
1787
+ bool LowerTypeTestsModule::runForTesting (Module &M, ModuleAnalysisManager &AM ) {
1721
1788
ModuleSummaryIndex Summary (/* HaveGVs=*/ false );
1722
1789
1723
1790
// Handle the command-line summary arguments. This code is for testing
@@ -1735,7 +1802,8 @@ bool LowerTypeTestsModule::runForTesting(Module &M) {
1735
1802
1736
1803
bool Changed =
1737
1804
LowerTypeTestsModule (
1738
- M, ClSummaryAction == PassSummaryAction::Export ? &Summary : nullptr ,
1805
+ M, AM,
1806
+ ClSummaryAction == PassSummaryAction::Export ? &Summary : nullptr ,
1739
1807
ClSummaryAction == PassSummaryAction::Import ? &Summary : nullptr ,
1740
1808
/* DropTypeTests*/ false )
1741
1809
.lower ();
@@ -2298,10 +2366,10 @@ PreservedAnalyses LowerTypeTestsPass::run(Module &M,
2298
2366
ModuleAnalysisManager &AM) {
2299
2367
bool Changed;
2300
2368
if (UseCommandLine)
2301
- Changed = LowerTypeTestsModule::runForTesting (M);
2369
+ Changed = LowerTypeTestsModule::runForTesting (M, AM );
2302
2370
else
2303
2371
Changed =
2304
- LowerTypeTestsModule (M, ExportSummary, ImportSummary, DropTypeTests)
2372
+ LowerTypeTestsModule (M, AM, ExportSummary, ImportSummary, DropTypeTests)
2305
2373
.lower ();
2306
2374
if (!Changed)
2307
2375
return PreservedAnalyses::all ();
0 commit comments