1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -mtriple=riscv64-unknown-elf -passes='separate-const-offset-from-gep,early-cse' \ 3; RUN: -S | FileCheck %s 4 5; Several tests for separate-const-offset-from-gep. The transformation 6; heavily relies on TargetTransformInfo, so we put these tests under 7; target-specific folders. 8 9; Simple case when GEPs should be optimized. 10define i64 @test1(ptr %array, i64 %i, i64 %j) { 11; CHECK-LABEL: @test1( 12; CHECK-NEXT: entry: 13; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[I:%.*]], 5 14; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i64, ptr [[ARRAY:%.*]], i64 [[I]] 15; CHECK-NEXT: [[GEP4:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 40 16; CHECK-NEXT: store i64 [[J:%.*]], ptr [[GEP4]], align 8 17; CHECK-NEXT: [[GEP26:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 48 18; CHECK-NEXT: store i64 [[J]], ptr [[GEP26]], align 8 19; CHECK-NEXT: [[GEP38:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 280 20; CHECK-NEXT: store i64 [[ADD]], ptr [[GEP38]], align 8 21; CHECK-NEXT: ret i64 undef 22; 23entry: 24 %add = add nsw i64 %i, 5 25 %gep = getelementptr inbounds i64, ptr %array, i64 %add 26 store i64 %j, ptr %gep 27 %add2 = add nsw i64 %i, 6 28 %gep2 = getelementptr inbounds i64, ptr %array, i64 %add2 29 store i64 %j, ptr %gep2 30 %add3 = add nsw i64 %i, 35 31 %gep3 = getelementptr inbounds i64, ptr %array, i64 %add3 32 store i64 %add, ptr %gep3 33 ret i64 undef 34} 35 36; Optimize GEPs when there sext instructions are needed to cast index value to expected type. 37define i32 @test2(ptr %array, i32 %i, i32 %j) { 38; CHECK-LABEL: @test2( 39; CHECK-NEXT: entry: 40; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5 41; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[I]] to i64 42; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i64 [[TMP0]] 43; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20 44; CHECK-NEXT: store i32 [[J:%.*]], ptr [[GEP2]], align 4 45; CHECK-NEXT: [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 24 46; CHECK-NEXT: store i32 [[J]], ptr [[GEP54]], align 4 47; CHECK-NEXT: [[GEP86:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 140 48; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP86]], align 4 49; CHECK-NEXT: ret i32 undef 50; 51entry: 52 %add = add nsw i32 %i, 5 53 %sext = sext i32 %add to i64 54 %gep = getelementptr inbounds i32, ptr %array, i64 %sext 55 store i32 %j, ptr %gep 56 %add3 = add nsw i32 %i, 6 57 %sext4 = sext i32 %add3 to i64 58 %gep5 = getelementptr inbounds i32, ptr %array, i64 %sext4 59 store i32 %j, ptr %gep5 60 %add6 = add nsw i32 %i, 35 61 %sext7 = sext i32 %add6 to i64 62 %gep8 = getelementptr inbounds i32, ptr %array, i64 %sext7 63 store i32 %add, ptr %gep8 64 ret i32 undef 65} 66 67; No need to modify because all values are also used in other expressions. 68; Modification doesn't decrease register pressure. 69define i32 @test3(ptr %array, i32 %i) { 70; CHECK-LABEL: @test3( 71; CHECK-NEXT: entry: 72; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5 73; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[I]] to i64 74; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i64 [[TMP0]] 75; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20 76; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP2]], align 4 77; CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[I]], 6 78; CHECK-NEXT: [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 24 79; CHECK-NEXT: store i32 [[ADD3]], ptr [[GEP54]], align 4 80; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[I]], 35 81; CHECK-NEXT: [[GEP86:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 140 82; CHECK-NEXT: store i32 [[ADD6]], ptr [[GEP86]], align 4 83; CHECK-NEXT: ret i32 undef 84; 85entry: 86 %add = add nsw i32 %i, 5 87 %sext = sext i32 %add to i64 88 %gep = getelementptr inbounds i32, ptr %array, i64 %sext 89 store i32 %add, ptr %gep 90 %add3 = add nsw i32 %i, 6 91 %sext4 = sext i32 %add3 to i64 92 %gep5 = getelementptr inbounds i32, ptr %array, i64 %sext4 93 store i32 %add3, ptr %gep5 94 %add6 = add nsw i32 %i, 35 95 %sext7 = sext i32 %add6 to i64 96 %gep8 = getelementptr inbounds i32, ptr %array, i64 %sext7 97 store i32 %add6, ptr %gep8 98 ret i32 undef 99} 100 101; Optimized GEPs for multidimensional array with same base 102define i32 @test4(ptr %array2, i32 %i) { 103; CHECK-LABEL: @test4( 104; CHECK-NEXT: entry: 105; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5 106; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[I]] to i64 107; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [50 x i32], ptr [[ARRAY2:%.*]], i64 [[TMP0]], i64 [[TMP0]] 108; CHECK-NEXT: [[GEP3:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 1020 109; CHECK-NEXT: store i32 [[I]], ptr [[GEP3]], align 4 110; CHECK-NEXT: [[GEP56:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 1024 111; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP56]], align 4 112; CHECK-NEXT: [[GEP89:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 1140 113; CHECK-NEXT: store i32 [[I]], ptr [[GEP89]], align 4 114; CHECK-NEXT: ret i32 undef 115; 116entry: 117 %add = add nsw i32 %i, 5 118 %sext = sext i32 %add to i64 119 %gep = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext, i64 %sext 120 store i32 %i, ptr %gep 121 %add3 = add nsw i32 %i, 6 122 %sext4 = sext i32 %add3 to i64 123 %gep5 = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext, i64 %sext4 124 store i32 %add, ptr %gep5 125 %add6 = add nsw i32 %i, 35 126 %sext7 = sext i32 %add6 to i64 127 %gep8 = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext, i64 %sext7 128 store i32 %i, ptr %gep8 129 ret i32 undef 130} 131 132; Don't optimize GEPs for multidimensional array with same base because RISC-V doesn't support the addressing mode 133define i32 @test5(ptr %array2, i32 %i, i64 %j) { 134; CHECK-LABEL: @test5( 135; CHECK-NEXT: entry: 136; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5 137; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[I]] to i64 138; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [50 x i32], ptr [[ARRAY2:%.*]], i64 [[TMP0]], i64 [[TMP0]] 139; CHECK-NEXT: [[GEP3:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 1020 140; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP3]], align 4 141; CHECK-NEXT: [[TMP2:%.*]] = getelementptr [50 x i32], ptr [[ARRAY2]], i64 [[TMP0]], i64 [[J:%.*]] 142; CHECK-NEXT: [[GEP55:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 1200 143; CHECK-NEXT: store i32 [[I]], ptr [[GEP55]], align 4 144; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[I]], 35 145; CHECK-NEXT: [[SEXT7:%.*]] = sext i32 [[ADD6]] to i64 146; CHECK-NEXT: [[GEP8:%.*]] = getelementptr inbounds [50 x i32], ptr [[ARRAY2]], i64 [[SEXT7]], i64 [[J]] 147; CHECK-NEXT: store i32 [[I]], ptr [[GEP8]], align 4 148; CHECK-NEXT: ret i32 undef 149; 150entry: 151 %add = add nsw i32 %i, 5 152 %sext = sext i32 %add to i64 153 %gep = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext, i64 %sext 154 store i32 %add, ptr %gep 155 %add3 = add nsw i32 %i, 6 156 %sext4 = sext i32 %add3 to i64 157 %gep5 = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext4, i64 %j 158 store i32 %i, ptr %gep5 159 %add6 = add nsw i32 %i, 35 160 %sext7 = sext i32 %add6 to i64 161 %gep8 = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext7, i64 %j 162 store i32 %i, ptr %gep8 163 ret i32 undef 164} 165 166; No need to optimize GEPs, because there is critical amount with non-constant offsets. 167define i64 @test6(ptr %array, i64 %i, i64 %j) { 168; CHECK-LABEL: @test6( 169; CHECK-NEXT: entry: 170; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[I:%.*]], 5 171; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i64, ptr [[ARRAY:%.*]], i64 [[J:%.*]] 172; CHECK-NEXT: store i64 [[ADD]], ptr [[GEP]], align 8 173; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i64, ptr [[ARRAY]], i64 [[I]] 174; CHECK-NEXT: [[GEP52:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 48 175; CHECK-NEXT: store i64 [[I]], ptr [[GEP52]], align 8 176; CHECK-NEXT: store i64 [[I]], ptr [[TMP0]], align 8 177; CHECK-NEXT: ret i64 undef 178; 179entry: 180 %add = add nsw i64 %i, 5 181 %gep = getelementptr inbounds i64, ptr %array, i64 %j 182 store i64 %add, ptr %gep 183 %add3 = add nsw i64 %i, 6 184 %gep5 = getelementptr inbounds i64, ptr %array, i64 %add3 185 store i64 %i, ptr %gep5 186 %add6 = add nsw i64 %i, 35 187 %gep8 = getelementptr inbounds i64, ptr %array, i64 %i 188 store i64 %i, ptr %gep8 189 ret i64 undef 190} 191 192; No need to optimize GEPs, because the base variable is different. 193define i32 @test7(ptr %array, i32 %i, i32 %j, i32 %k) { 194; CHECK-LABEL: @test7( 195; CHECK-NEXT: entry: 196; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5 197; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[I]] to i64 198; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i64 [[TMP0]] 199; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20 200; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP2]], align 4 201; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[K:%.*]] to i64 202; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i32, ptr [[ARRAY]], i64 [[TMP2]] 203; CHECK-NEXT: [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i64 24 204; CHECK-NEXT: store i32 [[I]], ptr [[GEP54]], align 4 205; CHECK-NEXT: [[TMP4:%.*]] = sext i32 [[J:%.*]] to i64 206; CHECK-NEXT: [[TMP5:%.*]] = getelementptr i32, ptr [[ARRAY]], i64 [[TMP4]] 207; CHECK-NEXT: [[GEP86:%.*]] = getelementptr inbounds i8, ptr [[TMP5]], i64 140 208; CHECK-NEXT: store i32 [[I]], ptr [[GEP86]], align 4 209; CHECK-NEXT: ret i32 undef 210; 211entry: 212 %add = add nsw i32 %i, 5 213 %sext = sext i32 %add to i64 214 %gep = getelementptr inbounds i32, ptr %array, i64 %sext 215 store i32 %add, ptr %gep 216 %add3 = add nsw i32 %k, 6 217 %sext4 = sext i32 %add3 to i64 218 %gep5 = getelementptr inbounds i32, ptr %array, i64 %sext4 219 store i32 %i, ptr %gep5 220 %add6 = add nsw i32 %j, 35 221 %sext7 = sext i32 %add6 to i64 222 %gep8 = getelementptr inbounds i32, ptr %array, i64 %sext7 223 store i32 %i, ptr %gep8 224 ret i32 undef 225} 226 227; No need to optimize GEPs, because the base of GEP instructions is different. 228define i32 @test8(ptr %array, ptr %array2, ptr %array3, i32 %i) { 229; CHECK-LABEL: @test8( 230; CHECK-NEXT: entry: 231; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5 232; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[I]] to i64 233; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i64 [[TMP0]] 234; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20 235; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP2]], align 4 236; CHECK-NEXT: [[TMP2:%.*]] = getelementptr i32, ptr [[ARRAY2:%.*]], i64 [[TMP0]] 237; CHECK-NEXT: [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 24 238; CHECK-NEXT: store i32 [[I]], ptr [[GEP54]], align 4 239; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i32, ptr [[ARRAY3:%.*]], i64 [[TMP0]] 240; CHECK-NEXT: [[GEP86:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i64 140 241; CHECK-NEXT: store i32 [[I]], ptr [[GEP86]], align 4 242; CHECK-NEXT: ret i32 undef 243; 244entry: 245 %add = add nsw i32 %i, 5 246 %sext = sext i32 %add to i64 247 %gep = getelementptr inbounds i32, ptr %array, i64 %sext 248 store i32 %add, ptr %gep 249 %add3 = add nsw i32 %i, 6 250 %sext4 = sext i32 %add3 to i64 251 %gep5 = getelementptr inbounds i32, ptr %array2, i64 %sext4 252 store i32 %i, ptr %gep5 253 %add6 = add nsw i32 %i, 35 254 %sext7 = sext i32 %add6 to i64 255 %gep8 = getelementptr inbounds i32, ptr %array3, i64 %sext7 256 store i32 %i, ptr %gep8 257 ret i32 undef 258} 259 260; No need to optimize GEPs of multidimensional array, because the base of GEP instructions is different. 261define i32 @test9(ptr %array, i32 %i) { 262; CHECK-LABEL: @test9( 263; CHECK-NEXT: entry: 264; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5 265; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[I]] to i64 266; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [50 x i32], ptr [[ARRAY:%.*]], i64 0, i64 [[TMP0]] 267; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20 268; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP2]], align 4 269; CHECK-NEXT: [[TMP2:%.*]] = getelementptr [50 x i32], ptr [[ARRAY]], i64 [[TMP0]], i64 [[TMP0]] 270; CHECK-NEXT: [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 24 271; CHECK-NEXT: store i32 [[I]], ptr [[GEP54]], align 4 272; CHECK-NEXT: [[GEP87:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 1340 273; CHECK-NEXT: store i32 [[I]], ptr [[GEP87]], align 4 274; CHECK-NEXT: ret i32 undef 275; 276entry: 277 %add = add nsw i32 %i, 5 278 %sext = sext i32 %add to i64 279 %gep = getelementptr inbounds [50 x i32], ptr %array, i64 0, i64 %sext 280 store i32 %add, ptr %gep 281 %add3 = add nsw i32 %i, 6 282 %sext4 = sext i32 %add3 to i64 283 %int = sext i32 %i to i64 284 %gep5 = getelementptr inbounds [50 x i32], ptr %array, i64 %int, i64 %sext4 285 store i32 %i, ptr %gep5 286 %add6 = add nsw i32 %i, 35 287 %sext7 = sext i32 %add6 to i64 288 %gep8 = getelementptr inbounds [50 x i32], ptr %array, i64 %sext4, i64 %sext7 289 store i32 %i, ptr %gep8 290 ret i32 undef 291} 292