Index: llvm/lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- llvm/lib/CodeGen/CodeGenPrepare.cpp +++ llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -215,6 +215,10 @@ "addr-sink-combine-scaled-reg", cl::Hidden, cl::init(true), cl::desc("Allow combining of ScaledReg field in Address sinking.")); +static cl::opt BasicBlockMaxSize( + "bb-max-size", cl::Hidden, cl::init(1000), + cl::desc("Split basic blocks bigger than this size when compiling for Os")); + namespace { using SetOfInstrs = SmallPtrSet; @@ -472,6 +476,41 @@ EverMadeChange |= MadeChange; } + // Split big basic blocks. We're doing it to save compile time, which is not + // a concern on O3. + if (OptSize && BasicBlockMaxSize != 0) { + SmallVector Worklist; + for (BasicBlock &BB : F) + Worklist.push_back(&BB); + + MadeChange = false; + while (!Worklist.empty()) { + BasicBlock *BB = Worklist.pop_back_val(); + unsigned n = 0; + for (auto It = BB->begin(); It != BB->end(); It++, n++) { + Instruction &I = *It; + // Skip instructions that we can not split the block on. + if (isa(&I) || I.isEHPad()) + continue; + + // If we've reached terminator, break so that we don't split the block + // on it. + if (I.isTerminator()) + break; + + // If the block is too big, split it and put the remainder to the + // worklist. + if (n >= BasicBlockMaxSize) { + BB = SplitBlock(BB, &I); + Worklist.push_back(BB); + MadeChange = true; + break; + } + } + } + EverMadeChange |= MadeChange; + } + if (!DisableGCOpts) { SmallVector Statepoints; for (BasicBlock &BB : F) Index: llvm/test/CodeGen/X86/codegen-prepare-split.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/codegen-prepare-split.ll @@ -0,0 +1,116 @@ +; RUN: opt < %s -S -codegenprepare -bb-max-size=5 | FileCheck %s +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +; CHECK-LABEL: @foo1 +define void @foo1(i64 *%base) optsize { +bb: + %a0 = getelementptr inbounds i64, i64* %base, i64 8 + %a1 = getelementptr inbounds i64, i64* %base, i64 16 + %a2 = getelementptr inbounds i64, i64* %base, i64 24 + %a3 = getelementptr inbounds i64, i64* %base, i64 32 + %a4 = getelementptr inbounds i64, i64* %base, i64 40 +; CHECK: %a4 = getelementptr +; CHECK-NEXT: br label + store i64 0, i64* %a0, align 4 + store i64 1, i64* %a1, align 4 + store i64 2, i64* %a2, align 4 + store i64 3, i64* %a3, align 4 + store i64 4, i64* %a4, align 4 + ret void +} + +; CHECK-LABEL: @foo2 +define i64 @foo2(i64 *%base, i1 %p) optsize { +bb: + br i1 %p, label %bb_true, label %bb_false + +bb_true: + br label %bb1 + +bb_false: + br label %bb1 + +bb1: + %b0 = phi i64 [0, %bb_true], [1, %bb_false] + %b1 = phi i64 [2, %bb_true], [1, %bb_false] + %b2 = phi i64 [4, %bb_true], [2, %bb_false] + %b3 = phi i64 [9, %bb_true], [3, %bb_false] + %b4 = phi i64 [8, %bb_true], [5, %bb_false] +; CHECK: %b4 = phi i64 +; CHECK-NOT: br label +; CHECK-NEXT: ret i64 + ret i64 %b0 +} + +; CHECK-LABEL: @foo3 +define i64 @foo3(i64 *%base, i1 %p) optsize { +bb: + br i1 %p, label %bb_true, label %bb_false + +bb_true: + br label %bb1 + +bb_false: + br label %bb1 + +bb1: + %b0 = phi i64 [0, %bb_true], [1, %bb_false] + %b1 = phi i64 [2, %bb_true], [1, %bb_false] + %b2 = phi i64 [4, %bb_true], [2, %bb_false] + %b3 = phi i64 [9, %bb_true], [3, %bb_false] + %b4 = phi i64 [8, %bb_true], [5, %bb_false] +; CHECK: %b4 = phi i64 +; CHECK-NEXT: br label + %a = getelementptr inbounds i64, i64* %base, i64 100 + store i64 %b0, i64* %a, align 4 + ret i64 %b0 +} + +; CHECK-LABEL: @foo4 +define void @foo4() optsize { +bb: + %a0 = alloca i32, align 4 + %a1 = alloca i32, align 4 + %a2 = alloca i32, align 4 + %a3 = alloca i32, align 4 + %a4 = alloca i32, align 4 +; CHECK: %a4 = alloca +; CHECK-NEXT: br label + %a5 = alloca i32, align 4 + %a6 = alloca i32, align 4 + %a7 = alloca i32, align 4 + %a8 = alloca i32, align 4 + %a9 = alloca i32, align 4 +; CHECK: %a9 = alloca +; CHECK-NEXT: br label + call void @llvm.dbg.declare(metadata i32* %a0, metadata !6, metadata !DIExpression()), !dbg !2 + call void @llvm.dbg.declare(metadata i32* %a1, metadata !6, metadata !DIExpression()), !dbg !2 + call void @llvm.dbg.declare(metadata i32* %a2, metadata !6, metadata !DIExpression()), !dbg !2 + call void @llvm.dbg.declare(metadata i32* %a3, metadata !6, metadata !DIExpression()), !dbg !2 + call void @llvm.dbg.declare(metadata i32* %a4, metadata !6, metadata !DIExpression()), !dbg !2 +; CHECK: call void @llvm.dbg.declare(metadata i32* %a4 +; CHECK-NEXT: br label + call void @llvm.dbg.declare(metadata i32* %a5, metadata !6, metadata !DIExpression()), !dbg !2 + call void @llvm.dbg.declare(metadata i32* %a6, metadata !6, metadata !DIExpression()), !dbg !2 + call void @llvm.dbg.declare(metadata i32* %a7, metadata !6, metadata !DIExpression()), !dbg !2 + call void @llvm.dbg.declare(metadata i32* %a8, metadata !6, metadata !DIExpression()), !dbg !2 + call void @llvm.dbg.declare(metadata i32* %a9, metadata !6, metadata !DIExpression()), !dbg !2 +; CHECK: call void @llvm.dbg.declare(metadata i32* %a9 +; CHECK-NEXT: ret void + ret void +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) #0 + +attributes #0 = { nounwind readnone speculatable } + +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 2, !"Dwarf Version", i32 4} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = !DILocation(line: 1, column: 1, scope: !3) +!3 = distinct !DISubprogram(scope: null, isLocal: false, isDefinition: true, isOptimized: false, unit: !4) +!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !5, isOptimized: false) +!5 = !DIFile(filename: "foo.c", directory: "/path/to/file") +!6 = !DILocalVariable(name: "a", arg: 1, scope: !3, file: !5, line: 1, type: !7) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)