314 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes=licm -S < %s | FileCheck %s3; RUN: opt -passes='loop-mssa(licm)' -S %s | FileCheck %s4 5; If we can prove a local is thread local, we can insert stores during6; promotion which wouldn't be legal otherwise.7 8target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"9target triple = "x86_64-linux-generic"10 11@p = external global ptr12 13declare ptr @malloc(i64)14 15; Exercise the TLS case16define ptr @test(i32 %n) {17; CHECK-LABEL: @test(18; CHECK-NEXT: entry:19; CHECK-NEXT: [[MEM:%.*]] = call noalias dereferenceable(16) ptr @malloc(i64 16)20; CHECK-NEXT: br label [[FOR_BODY_LR_PH:%.*]]21; CHECK: for.body.lr.ph:22; CHECK-NEXT: [[ADDR_PROMOTED:%.*]] = load i32, ptr [[MEM]], align 423; CHECK-NEXT: br label [[FOR_HEADER:%.*]]24; CHECK: for.header:25; CHECK-NEXT: [[NEW1:%.*]] = phi i32 [ [[ADDR_PROMOTED]], [[FOR_BODY_LR_PH]] ], [ [[NEW:%.*]], [[FOR_BODY:%.*]] ]26; CHECK-NEXT: [[I_02:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[FOR_BODY]] ]27; CHECK-NEXT: [[GUARD:%.*]] = load atomic ptr, ptr @p monotonic, align 828; CHECK-NEXT: [[EXITCMP:%.*]] = icmp eq ptr [[GUARD]], null29; CHECK-NEXT: br i1 [[EXITCMP]], label [[FOR_BODY]], label [[EARLY_EXIT:%.*]]30; CHECK: early-exit:31; CHECK-NEXT: [[NEW1_LCSSA:%.*]] = phi i32 [ [[NEW1]], [[FOR_HEADER]] ]32; CHECK-NEXT: store i32 [[NEW1_LCSSA]], ptr [[MEM]], align 433; CHECK-NEXT: ret ptr null34; CHECK: for.body:35; CHECK-NEXT: [[NEW]] = add i32 [[NEW1]], 136; CHECK-NEXT: [[INC]] = add nsw i32 [[I_02]], 137; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[N:%.*]]38; CHECK-NEXT: br i1 [[CMP]], label [[FOR_HEADER]], label [[FOR_COND_FOR_END_CRIT_EDGE:%.*]]39; CHECK: for.cond.for.end_crit_edge:40; CHECK-NEXT: [[NEW_LCSSA:%.*]] = phi i32 [ [[NEW]], [[FOR_BODY]] ]41; CHECK-NEXT: [[SPLIT:%.*]] = phi ptr [ [[MEM]], [[FOR_BODY]] ]42; CHECK-NEXT: store i32 [[NEW_LCSSA]], ptr [[MEM]], align 443; CHECK-NEXT: ret ptr null44;45entry:46 ;; ignore the required null check for simplicity47 %mem = call dereferenceable(16) noalias ptr @malloc(i64 16)48 br label %for.body.lr.ph49 50for.body.lr.ph: ; preds = %entry51 br label %for.header52 53for.header:54 %i.02 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]55 %old = load i32, ptr %mem, align 456 ; deliberate impossible to analyze branch57 %guard = load atomic ptr, ptr @p monotonic, align 858 %exitcmp = icmp eq ptr %guard, null59 br i1 %exitcmp, label %for.body, label %early-exit60 61early-exit:62 ret ptr null63 64for.body:65 %new = add i32 %old, 166 store i32 %new, ptr %mem, align 467 %inc = add nsw i32 %i.02, 168 %cmp = icmp slt i32 %inc, %n69 br i1 %cmp, label %for.header, label %for.cond.for.end_crit_edge70 71for.cond.for.end_crit_edge: ; preds = %for.body72 %split = phi ptr [ %mem, %for.body ]73 ret ptr null74}75 76; Stack allocations can also be thread-local77define ptr @test2(i32 %n) {78; CHECK-LABEL: @test2(79; CHECK-NEXT: entry:80; CHECK-NEXT: [[MEM:%.*]] = alloca i8, i32 16, align 181; CHECK-NEXT: br label [[FOR_BODY_LR_PH:%.*]]82; CHECK: for.body.lr.ph:83; CHECK-NEXT: [[ADDR_PROMOTED:%.*]] = load i32, ptr [[MEM]], align 484; CHECK-NEXT: br label [[FOR_HEADER:%.*]]85; CHECK: for.header:86; CHECK-NEXT: [[NEW1:%.*]] = phi i32 [ [[ADDR_PROMOTED]], [[FOR_BODY_LR_PH]] ], [ [[NEW:%.*]], [[FOR_BODY:%.*]] ]87; CHECK-NEXT: [[I_02:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[FOR_BODY]] ]88; CHECK-NEXT: [[GUARD:%.*]] = load atomic ptr, ptr @p monotonic, align 889; CHECK-NEXT: [[EXITCMP:%.*]] = icmp eq ptr [[GUARD]], null90; CHECK-NEXT: br i1 [[EXITCMP]], label [[FOR_BODY]], label [[EARLY_EXIT:%.*]]91; CHECK: early-exit:92; CHECK-NEXT: [[NEW1_LCSSA:%.*]] = phi i32 [ [[NEW1]], [[FOR_HEADER]] ]93; CHECK-NEXT: store i32 [[NEW1_LCSSA]], ptr [[MEM]], align 494; CHECK-NEXT: ret ptr null95; CHECK: for.body:96; CHECK-NEXT: [[NEW]] = add i32 [[NEW1]], 197; CHECK-NEXT: [[INC]] = add nsw i32 [[I_02]], 198; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[N:%.*]]99; CHECK-NEXT: br i1 [[CMP]], label [[FOR_HEADER]], label [[FOR_COND_FOR_END_CRIT_EDGE:%.*]]100; CHECK: for.cond.for.end_crit_edge:101; CHECK-NEXT: [[NEW_LCSSA:%.*]] = phi i32 [ [[NEW]], [[FOR_BODY]] ]102; CHECK-NEXT: [[SPLIT:%.*]] = phi ptr [ [[MEM]], [[FOR_BODY]] ]103; CHECK-NEXT: store i32 [[NEW_LCSSA]], ptr [[MEM]], align 4104; CHECK-NEXT: ret ptr null105;106entry:107 %mem = alloca i8, i32 16108 br label %for.body.lr.ph109 110for.body.lr.ph: ; preds = %entry111 br label %for.header112 113for.header:114 %i.02 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]115 %old = load i32, ptr %mem, align 4116 ; deliberate impossible to analyze branch117 %guard = load atomic ptr, ptr @p monotonic, align 8118 %exitcmp = icmp eq ptr %guard, null119 br i1 %exitcmp, label %for.body, label %early-exit120 121early-exit:122 ret ptr null123 124for.body:125 %new = add i32 %old, 1126 store i32 %new, ptr %mem, align 4127 %inc = add nsw i32 %i.02, 1128 %cmp = icmp slt i32 %inc, %n129 br i1 %cmp, label %for.header, label %for.cond.for.end_crit_edge130 131for.cond.for.end_crit_edge: ; preds = %for.body132 %split = phi ptr [ %mem, %for.body ]133 ret ptr null134}135 136declare noalias ptr @custom_malloc(i64)137 138; Custom allocation function marked via noalias.139define ptr @test_custom_malloc(i32 %n) {140; CHECK-LABEL: @test_custom_malloc(141; CHECK-NEXT: entry:142; CHECK-NEXT: [[MEM:%.*]] = call noalias dereferenceable(16) ptr @custom_malloc(i64 16)143; CHECK-NEXT: br label [[FOR_BODY_LR_PH:%.*]]144; CHECK: for.body.lr.ph:145; CHECK-NEXT: [[ADDR_PROMOTED:%.*]] = load i32, ptr [[MEM]], align 4146; CHECK-NEXT: br label [[FOR_HEADER:%.*]]147; CHECK: for.header:148; CHECK-NEXT: [[NEW1:%.*]] = phi i32 [ [[ADDR_PROMOTED]], [[FOR_BODY_LR_PH]] ], [ [[NEW:%.*]], [[FOR_BODY:%.*]] ]149; CHECK-NEXT: [[I_02:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[FOR_BODY]] ]150; CHECK-NEXT: [[GUARD:%.*]] = load volatile ptr, ptr @p, align 8151; CHECK-NEXT: [[EXITCMP:%.*]] = icmp eq ptr [[GUARD]], null152; CHECK-NEXT: br i1 [[EXITCMP]], label [[FOR_BODY]], label [[EARLY_EXIT:%.*]]153; CHECK: early-exit:154; CHECK-NEXT: [[NEW1_LCSSA:%.*]] = phi i32 [ [[NEW1]], [[FOR_HEADER]] ]155; CHECK-NEXT: store i32 [[NEW1_LCSSA]], ptr [[MEM]], align 4156; CHECK-NEXT: ret ptr null157; CHECK: for.body:158; CHECK-NEXT: [[NEW]] = add i32 [[NEW1]], 1159; CHECK-NEXT: [[INC]] = add nsw i32 [[I_02]], 1160; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[N:%.*]]161; CHECK-NEXT: br i1 [[CMP]], label [[FOR_HEADER]], label [[FOR_COND_FOR_END_CRIT_EDGE:%.*]]162; CHECK: for.cond.for.end_crit_edge:163; CHECK-NEXT: [[NEW_LCSSA:%.*]] = phi i32 [ [[NEW]], [[FOR_BODY]] ]164; CHECK-NEXT: [[SPLIT:%.*]] = phi ptr [ [[MEM]], [[FOR_BODY]] ]165; CHECK-NEXT: store i32 [[NEW_LCSSA]], ptr [[MEM]], align 4166; CHECK-NEXT: ret ptr null167;168entry:169 %mem = call dereferenceable(16) noalias ptr @custom_malloc(i64 16)170 br label %for.body.lr.ph171 172for.body.lr.ph: ; preds = %entry173 br label %for.header174 175for.header:176 %i.02 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]177 %old = load i32, ptr %mem, align 4178 ; deliberate impossible to analyze branch179 %guard = load volatile ptr, ptr @p180 %exitcmp = icmp eq ptr %guard, null181 br i1 %exitcmp, label %for.body, label %early-exit182 183early-exit:184 ret ptr null185 186for.body:187 %new = add i32 %old, 1188 store i32 %new, ptr %mem, align 4189 %inc = add nsw i32 %i.02, 1190 %cmp = icmp slt i32 %inc, %n191 br i1 %cmp, label %for.header, label %for.cond.for.end_crit_edge192 193for.cond.for.end_crit_edge: ; preds = %for.body194 %split = phi ptr [ %mem, %for.body ]195 ret ptr null196}197 198declare ptr @not_malloc(i64)199 200; Negative test - not an allocation function.201define ptr @test_neg_not_malloc(i32 %n) {202; CHECK-LABEL: @test_neg_not_malloc(203; CHECK-NEXT: entry:204; CHECK-NEXT: [[MEM:%.*]] = call dereferenceable(16) ptr @not_malloc(i64 16)205; CHECK-NEXT: br label [[FOR_BODY_LR_PH:%.*]]206; CHECK: for.body.lr.ph:207; CHECK-NEXT: br label [[FOR_HEADER:%.*]]208; CHECK: for.header:209; CHECK-NEXT: [[I_02:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]210; CHECK-NEXT: [[OLD:%.*]] = load i32, ptr [[MEM]], align 4211; CHECK-NEXT: [[GUARD:%.*]] = load volatile ptr, ptr @p, align 8212; CHECK-NEXT: [[EXITCMP:%.*]] = icmp eq ptr [[GUARD]], null213; CHECK-NEXT: br i1 [[EXITCMP]], label [[FOR_BODY]], label [[EARLY_EXIT:%.*]]214; CHECK: early-exit:215; CHECK-NEXT: ret ptr null216; CHECK: for.body:217; CHECK-NEXT: [[NEW:%.*]] = add i32 [[OLD]], 1218; CHECK-NEXT: store i32 [[NEW]], ptr [[MEM]], align 4219; CHECK-NEXT: [[INC]] = add nsw i32 [[I_02]], 1220; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[N:%.*]]221; CHECK-NEXT: br i1 [[CMP]], label [[FOR_HEADER]], label [[FOR_COND_FOR_END_CRIT_EDGE:%.*]]222; CHECK: for.cond.for.end_crit_edge:223; CHECK-NEXT: [[SPLIT:%.*]] = phi ptr [ [[MEM]], [[FOR_BODY]] ]224; CHECK-NEXT: ret ptr null225;226entry:227 ;; ignore the required null check for simplicity228 %mem = call dereferenceable(16) ptr @not_malloc(i64 16)229 br label %for.body.lr.ph230 231for.body.lr.ph: ; preds = %entry232 br label %for.header233 234for.header:235 %i.02 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]236 %old = load i32, ptr %mem, align 4237 ; deliberate impossible to analyze branch238 %guard = load volatile ptr, ptr @p239 %exitcmp = icmp eq ptr %guard, null240 br i1 %exitcmp, label %for.body, label %early-exit241 242early-exit:243 ret ptr null244 245for.body:246 %new = add i32 %old, 1247 store i32 %new, ptr %mem, align 4248 %inc = add nsw i32 %i.02, 1249 %cmp = icmp slt i32 %inc, %n250 br i1 %cmp, label %for.header, label %for.cond.for.end_crit_edge251 252for.cond.for.end_crit_edge: ; preds = %for.body253 %split = phi ptr [ %mem, %for.body ]254 ret ptr null255}256 257; Negative test - can't speculate load since branch258; may control alignment259define ptr @test_neg2(i32 %n) {260; CHECK-LABEL: @test_neg2(261; CHECK-NEXT: entry:262; CHECK-NEXT: [[MEM:%.*]] = call noalias dereferenceable(16) ptr @malloc(i64 16)263; CHECK-NEXT: br label [[FOR_BODY_LR_PH:%.*]]264; CHECK: for.body.lr.ph:265; CHECK-NEXT: br label [[FOR_HEADER:%.*]]266; CHECK: for.header:267; CHECK-NEXT: [[I_02:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ]268; CHECK-NEXT: [[GUARD:%.*]] = load volatile ptr, ptr @p, align 8269; CHECK-NEXT: [[EXITCMP:%.*]] = icmp eq ptr [[GUARD]], null270; CHECK-NEXT: br i1 [[EXITCMP]], label [[FOR_BODY]], label [[EARLY_EXIT:%.*]]271; CHECK: early-exit:272; CHECK-NEXT: ret ptr null273; CHECK: for.body:274; CHECK-NEXT: [[OLD:%.*]] = load i32, ptr [[MEM]], align 4275; CHECK-NEXT: [[NEW:%.*]] = add i32 [[OLD]], 1276; CHECK-NEXT: store i32 [[NEW]], ptr [[MEM]], align 4277; CHECK-NEXT: [[INC]] = add nsw i32 [[I_02]], 1278; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[N:%.*]]279; CHECK-NEXT: br i1 [[CMP]], label [[FOR_HEADER]], label [[FOR_COND_FOR_END_CRIT_EDGE:%.*]]280; CHECK: for.cond.for.end_crit_edge:281; CHECK-NEXT: [[SPLIT:%.*]] = phi ptr [ [[MEM]], [[FOR_BODY]] ]282; CHECK-NEXT: ret ptr null283;284entry:285 ;; ignore the required null check for simplicity286 %mem = call dereferenceable(16) noalias ptr @malloc(i64 16)287 br label %for.body.lr.ph288 289for.body.lr.ph: ; preds = %entry290 br label %for.header291 292for.header:293 %i.02 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]294 ; deliberate impossible to analyze branch295 %guard = load volatile ptr, ptr @p296 %exitcmp = icmp eq ptr %guard, null297 br i1 %exitcmp, label %for.body, label %early-exit298 299early-exit:300 ret ptr null301 302for.body:303 %old = load i32, ptr %mem, align 4304 %new = add i32 %old, 1305 store i32 %new, ptr %mem, align 4306 %inc = add nsw i32 %i.02, 1307 %cmp = icmp slt i32 %inc, %n308 br i1 %cmp, label %for.header, label %for.cond.for.end_crit_edge309 310for.cond.for.end_crit_edge: ; preds = %for.body311 %split = phi ptr [ %mem, %for.body ]312 ret ptr null313}314