# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -mtriple=aarch64-unknown-unknown -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s ... --- name: shl_gep_sext_ldrwrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.0: liveins: $w1, $x0 ; We should be able to fold a shift + extend into the pattern. ; In this case, we should get a roW load with two 1s, representing a shift ; plus sign extend. ; CHECK-LABEL: name: shl_gep_sext_ldrwrow ; CHECK: liveins: $w1, $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %foo:gpr32 = COPY $w1 ; CHECK: %load:gpr32 = LDRWroW %base, %foo, 1, 1 :: (load 4) ; CHECK: $w0 = COPY %load ; CHECK: RET_ReallyLR implicit $w0 %base:gpr(p0) = COPY $x0 %foo:gpr(s32) = COPY $w1 %ext:gpr(s64) = G_SEXT %foo(s32) %c:gpr(s64) = G_CONSTANT i64 2 %offset:gpr(s64) = G_SHL %ext, %c %ptr:gpr(p0) = G_PTR_ADD %base, %offset(s64) %load:gpr(s32) = G_LOAD %ptr(p0) :: (load 4) $w0 = COPY %load(s32) RET_ReallyLR implicit $w0 ... --- name: shl_gep_zext_ldrwrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.0: liveins: $w1, $x0 ; We should be able to fold a shift + extend into the pattern. ; In this case, we should get a roW load with a 0 representing a zero-extend ; and a 1 representing a shift. ; CHECK-LABEL: name: shl_gep_zext_ldrwrow ; CHECK: liveins: $w1, $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %foo:gpr32 = COPY $w1 ; CHECK: %load:gpr32 = LDRWroW %base, %foo, 0, 1 :: (load 4) ; CHECK: $w0 = COPY %load ; CHECK: RET_ReallyLR implicit $w0 %base:gpr(p0) = COPY $x0 %foo:gpr(s32) = COPY $w1 %ext:gpr(s64) = G_ZEXT %foo(s32) %c:gpr(s64) = G_CONSTANT i64 2 %offset:gpr(s64) = G_SHL %ext, %c %ptr:gpr(p0) = G_PTR_ADD %base, %offset(s64) %load:gpr(s32) = G_LOAD %ptr(p0) :: (load 4) $w0 = COPY %load(s32) RET_ReallyLR implicit $w0 ... --- name: shl_gep_anyext_ldrwrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.0: liveins: $w1, $x0 ; We should be able to fold a shift + extend into the pattern. ; In this case, we should get a roW load with a 0 representing a zero-extend ; and a 1 representing a shift. ; CHECK-LABEL: name: shl_gep_anyext_ldrwrow ; CHECK: liveins: $w1, $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %foo:gpr32 = COPY $w1 ; CHECK: %load:gpr32 = LDRWroW %base, %foo, 0, 1 :: (load 4) ; CHECK: $w0 = COPY %load ; CHECK: RET_ReallyLR implicit $w0 %base:gpr(p0) = COPY $x0 %foo:gpr(s32) = COPY $w1 %ext:gpr(s64) = G_ANYEXT %foo(s32) %c:gpr(s64) = G_CONSTANT i64 2 %offset:gpr(s64) = G_SHL %ext, %c %ptr:gpr(p0) = G_PTR_ADD %base, %offset(s64) %load:gpr(s32) = G_LOAD %ptr(p0) :: (load 4) $w0 = COPY %load(s32) RET_ReallyLR implicit $w0 ... --- name: mul_gep_sext_ldrwrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.0: ; We should be able to do the same with multiplies as with shifts. liveins: $w1, $x0 ; CHECK-LABEL: name: mul_gep_sext_ldrwrow ; CHECK: liveins: $w1, $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %foo:gpr32 = COPY $w1 ; CHECK: %load:gpr32 = LDRWroW %base, %foo, 1, 1 :: (load 4) ; CHECK: $w0 = COPY %load ; CHECK: RET_ReallyLR implicit $w0 %base:gpr(p0) = COPY $x0 %foo:gpr(s32) = COPY $w1 %ext:gpr(s64) = G_SEXT %foo(s32) %c:gpr(s64) = G_CONSTANT i64 4 %offset:gpr(s64) = G_MUL %c, %ext %ptr:gpr(p0) = G_PTR_ADD %base, %offset(s64) %load:gpr(s32) = G_LOAD %ptr(p0) :: (load 4) $w0 = COPY %load(s32) RET_ReallyLR implicit $w0 ... --- name: mul_gep_zext_ldrwrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.0: liveins: $w1, $x0 ; We should be able to do the same with multiplies as with shifts. ; CHECK-LABEL: name: mul_gep_zext_ldrwrow ; CHECK: liveins: $w1, $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %foo:gpr32 = COPY $w1 ; CHECK: %load:gpr32 = LDRWroW %base, %foo, 0, 1 :: (load 4) ; CHECK: $w0 = COPY %load ; CHECK: RET_ReallyLR implicit $w0 %base:gpr(p0) = COPY $x0 %foo:gpr(s32) = COPY $w1 %ext:gpr(s64) = G_ZEXT %foo(s32) %c:gpr(s64) = G_CONSTANT i64 4 %offset:gpr(s64) = G_MUL %c, %ext %ptr:gpr(p0) = G_PTR_ADD %base, %offset(s64) %load:gpr(s32) = G_LOAD %ptr(p0) :: (load 4) $w0 = COPY %load(s32) RET_ReallyLR implicit $w0 ... --- name: mul_gep_anyext_ldrwrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.0: liveins: $w1, $x0 ; We should be able to do the same with multiplies as with shifts. ; CHECK-LABEL: name: mul_gep_anyext_ldrwrow ; CHECK: liveins: $w1, $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %foo:gpr32 = COPY $w1 ; CHECK: %load:gpr32 = LDRWroW %base, %foo, 0, 1 :: (load 4) ; CHECK: $w0 = COPY %load ; CHECK: RET_ReallyLR implicit $w0 %base:gpr(p0) = COPY $x0 %foo:gpr(s32) = COPY $w1 %ext:gpr(s64) = G_ANYEXT %foo(s32) %c:gpr(s64) = G_CONSTANT i64 4 %offset:gpr(s64) = G_MUL %c, %ext %ptr:gpr(p0) = G_PTR_ADD %base, %offset(s64) %load:gpr(s32) = G_LOAD %ptr(p0) :: (load 4) $w0 = COPY %load(s32) RET_ReallyLR implicit $w0 ... --- name: ldrdrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.0: liveins: $w1, $x0, $d0 ; Verify that we can select LDRDroW. ; CHECK-LABEL: name: ldrdrow ; CHECK: liveins: $w1, $x0, $d0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %foo:gpr32 = COPY $w1 ; CHECK: %load:fpr64 = LDRDroW %base, %foo, 1, 1 :: (load 8) ; CHECK: $x0 = COPY %load ; CHECK: RET_ReallyLR implicit $x0 %base:gpr(p0) = COPY $x0 %foo:gpr(s32) = COPY $w1 %ext:gpr(s64) = G_SEXT %foo(s32) %c:gpr(s64) = G_CONSTANT i64 8 %offset:gpr(s64) = G_MUL %c, %ext %ptr:gpr(p0) = G_PTR_ADD %base, %offset(s64) %load:fpr(<2 x s32>) = G_LOAD %ptr(p0) :: (load 8) $x0 = COPY %load(<2 x s32>) RET_ReallyLR implicit $x0 ... --- name: ldrxrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.0: liveins: $w1, $x0, $d0 ; Verify that we can select LDRXroW. ; CHECK-LABEL: name: ldrxrow ; CHECK: liveins: $w1, $x0, $d0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %foo:gpr32 = COPY $w1 ; CHECK: %load:gpr64 = LDRXroW %base, %foo, 1, 1 :: (load 8) ; CHECK: $x0 = COPY %load ; CHECK: RET_ReallyLR implicit $x0 %base:gpr(p0) = COPY $x0 %foo:gpr(s32) = COPY $w1 %ext:gpr(s64) = G_SEXT %foo(s32) %c:gpr(s64) = G_CONSTANT i64 8 %offset:gpr(s64) = G_MUL %c, %ext %ptr:gpr(p0) = G_PTR_ADD %base, %offset(s64) %load:gpr(s64) = G_LOAD %ptr(p0) :: (load 8) $x0 = COPY %load(s64) RET_ReallyLR implicit $x0 ... --- name: ldrbbrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.1.entry: liveins: $x0, $w0, $w1 ; Verify that we can select LDRBBroW. Note that there is no shift here, ; but we still fold the extend into the addressing mode. ; CHECK-LABEL: name: ldrbbrow ; CHECK: liveins: $x0, $w0, $w1 ; CHECK: %val:gpr32 = COPY $w1 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %load:gpr32 = LDRBBroW %base, %val, 1, 0 :: (load 1) ; CHECK: $w0 = COPY %load ; CHECK: RET_ReallyLR implicit $w0 %val:gpr(s32) = COPY $w1 %base:gpr(p0) = COPY $x0 %ext:gpr(s64) = G_SEXT %val(s32) %ptr:gpr(p0) = G_PTR_ADD %base, %ext(s64) %load:gpr(s32) = G_LOAD %ptr(p0) :: (load 1) $w0 = COPY %load(s32) RET_ReallyLR implicit $w0 ... --- name: ldrhrow alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 machineFunctionInfo: {} body: | bb.1.entry: liveins: $w1, $x0 ; Verify that we can select ldrhrow. ; CHECK-LABEL: name: ldrhrow ; CHECK: liveins: $w1, $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %foo:gpr32 = COPY $w1 ; CHECK: %load:fpr16 = LDRHroW %base, %foo, 1, 1 :: (load 2) ; CHECK: $h0 = COPY %load ; CHECK: RET_ReallyLR implicit $h0 %base:gpr(p0) = COPY $x0 %foo:gpr(s32) = COPY $w1 %ext:gpr(s64) = G_SEXT %foo(s32) %c:gpr(s64) = G_CONSTANT i64 2 %offset:gpr(s64) = G_MUL %c, %ext %ptr:gpr(p0) = G_PTR_ADD %base, %offset(s64) %load:fpr(s16) = G_LOAD %ptr(p0) :: (load 2) $h0 = COPY %load(s16) RET_ReallyLR implicit $h0 ... --- name: bad_and_mask_1 alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 body: | bb.0: liveins: $x0 ; We should get a roX load here, not a roW load. We can't use the mask in ; this test for an extend. ; CHECK-LABEL: name: bad_and_mask_1 ; CHECK: liveins: $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %imp:gpr64 = IMPLICIT_DEF ; CHECK: %and:gpr64common = ANDXri %imp, 4103 ; CHECK: %load:gpr64 = LDRXroX %base, %and, 0, 1 :: (load 8) ; CHECK: $x1 = COPY %load ; CHECK: RET_ReallyLR implicit $x1 %base:gpr(p0) = COPY $x0 %imp:gpr(s64) = G_IMPLICIT_DEF %bad_mask:gpr(s64) = G_CONSTANT i64 255 %and:gpr(s64) = G_AND %imp, %bad_mask %c:gpr(s64) = G_CONSTANT i64 8 %mul:gpr(s64) = G_MUL %c, %and %ptr:gpr(p0) = G_PTR_ADD %base, %mul(s64) %load:gpr(s64) = G_LOAD %ptr(p0) :: (load 8) $x1 = COPY %load(s64) RET_ReallyLR implicit $x1 ... --- name: bad_and_mask_2 alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 body: | bb.0: liveins: $x0 ; We should get a roX load here, not a roW load. We can't use the mask in ; this test for an extend. ; CHECK-LABEL: name: bad_and_mask_2 ; CHECK: liveins: $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %imp:gpr64 = IMPLICIT_DEF ; CHECK: %and:gpr64common = ANDXri %imp, 4111 ; CHECK: %load:gpr64 = LDRXroX %base, %and, 0, 1 :: (load 8) ; CHECK: $x1 = COPY %load ; CHECK: RET_ReallyLR implicit $x1 %base:gpr(p0) = COPY $x0 %imp:gpr(s64) = G_IMPLICIT_DEF %bad_mask:gpr(s64) = G_CONSTANT i64 65535 %and:gpr(s64) = G_AND %imp, %bad_mask %c:gpr(s64) = G_CONSTANT i64 8 %mul:gpr(s64) = G_MUL %c, %and %ptr:gpr(p0) = G_PTR_ADD %base, %mul(s64) %load:gpr(s64) = G_LOAD %ptr(p0) :: (load 8) $x1 = COPY %load(s64) RET_ReallyLR implicit $x1 ... --- name: and_uxtw alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true frameInfo: maxAlignment: 1 body: | bb.0: liveins: $x0 ; The mask used for the AND here is legal for producing a roW load. ; CHECK-LABEL: name: and_uxtw ; CHECK: liveins: $x0 ; CHECK: %base:gpr64sp = COPY $x0 ; CHECK: %imp:gpr64 = IMPLICIT_DEF ; CHECK: [[COPY:%[0-9]+]]:gpr32all = COPY %imp.sub_32 ; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY [[COPY]] ; CHECK: %load:gpr64 = LDRXroW %base, [[COPY1]], 0, 1 :: (load 8) ; CHECK: $x1 = COPY %load ; CHECK: RET_ReallyLR implicit $x1 %base:gpr(p0) = COPY $x0 %imp:gpr(s64) = G_IMPLICIT_DEF %mask:gpr(s64) = G_CONSTANT i64 4294967295 %and:gpr(s64) = G_AND %imp, %mask %c:gpr(s64) = G_CONSTANT i64 8 %mul:gpr(s64) = G_MUL %c, %and %ptr:gpr(p0) = G_PTR_ADD %base, %mul(s64) %load:gpr(s64) = G_LOAD %ptr(p0) :: (load 8) $x1 = COPY %load(s64) RET_ReallyLR implicit $x1 ... --- name: zext_shl_LDRWroW alignment: 4 legalized: true regBankSelected: true tracksRegLiveness: true liveins: - { reg: '$w0' } - { reg: '$x1' } body: | bb.1: liveins: $w0, $x1 ; We try to look through the G_ZEXT of the SHL here. ; CHECK-LABEL: name: zext_shl_LDRWroW ; CHECK: liveins: $w0, $x1 ; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0 ; CHECK: [[COPY1:%[0-9]+]]:gpr64sp = COPY $x1 ; CHECK: [[ANDWri:%[0-9]+]]:gpr32common = ANDWri [[COPY]], 7 ; CHECK: [[LDRWroW:%[0-9]+]]:gpr32 = LDRWroW [[COPY1]], [[ANDWri]], 0, 1 :: (load 4) ; CHECK: $w0 = COPY [[LDRWroW]] ; CHECK: RET_ReallyLR implicit $w0 %0:gpr(s32) = COPY $w0 %1:gpr(p0) = COPY $x1 %2:gpr(s32) = G_CONSTANT i32 255 %3:gpr(s32) = G_AND %0, %2 %13:gpr(s64) = G_CONSTANT i64 2 %12:gpr(s32) = G_SHL %3, %13(s64) %6:gpr(s64) = G_ZEXT %12(s32) %7:gpr(p0) = G_PTR_ADD %1, %6(s64) %9:gpr(s32) = G_LOAD %7(p0) :: (load 4) $w0 = COPY %9(s32) RET_ReallyLR implicit $w0 ...