# RUN: llc -O0 -run-pass=regbankselect %s -o - -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix=FAST # RUN: llc -O0 -run-pass=regbankselect %s -regbankselect-greedy -o - -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix=GREEDY --- | ; ModuleID = 'generic-virtual-registers-type-error.mir' target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" target triple = "aarch64--" define void @defaultMapping() { entry: ret void } define void @defaultMappingVector() { entry: ret void } define void @defaultMapping1Repair() { entry: ret void } define void @defaultMapping2Repairs() { entry: ret void } define void @defaultMappingDefRepair() { entry: ret void } define void @phiPropagation(i32* %src, i32* %dst, i1 %cond) { entry: %srcVal = load i32, i32* %src br i1 %cond, label %end, label %then then: %res = add i32 %srcVal, 36 br label %end end: %toStore = phi i32 [ %srcVal, %entry ], [ %res, %then ] store i32 %toStore, i32* %dst ret void } define void @defaultMappingUseRepairPhysReg() { entry: ret void } define void @defaultMappingDefRepairPhysReg() { entry: ret void } define void @greedyMappingOr() { entry: ret void } define void @greedyMappingOrWithConstraints() { entry: ret void } define void @ignoreTargetSpecificInst() { ret void } define void @regBankSelected_property() { ret void } define void @bitcast_s32_gpr() { ret void } define void @bitcast_s32_fpr() { ret void } define void @bitcast_s32_gpr_fpr() { ret void } define void @bitcast_s32_fpr_gpr() { ret void } define void @bitcast_s64_gpr() { ret void } define void @bitcast_s64_fpr() { ret void } define void @bitcast_s64_gpr_fpr() { ret void } define void @bitcast_s64_fpr_gpr() { ret void } define void @bitcast_s128() { ret void } define void @copy_s128() { ret void } define void @copy_s128_from_load() { ret void } define void @copy_fp16() { ret void } define i64 @greedyWithChainOfComputation(i64 %arg1, <2 x i32>* %addr) { %varg1 = bitcast i64 %arg1 to <2 x i32> %varg2 = load <2 x i32>, <2 x i32>* %addr %vres = or <2 x i32> %varg1, %varg2 %res = bitcast <2 x i32> %vres to i64 ret i64 %res } define i64 @floatingPointLoad(i64 %arg1, double* %addr) { %varg1 = bitcast i64 %arg1 to double %varg2 = load double, double* %addr %vres = fadd double %varg1, %varg2 %res = bitcast double %vres to i64 ret i64 %res } define void @floatingPointStore(i64 %arg1, double* %addr) { %varg1 = bitcast i64 %arg1 to double %vres = fadd double %varg1, %varg1 store double %vres, double* %addr ret void } define void @fp16Ext32() { ret void } define void @fp16Ext64() { ret void } define void @fp32Ext64() { ret void } define half @passFp16(half %p) { entry: ret half %p } define half @passFp16ViaAllocas(half %p) { entry: %p.addr = alloca half, align 2 store half %p, half* %p.addr, align 2 %0 = load half, half* %p.addr, align 2 ret half %0 } ... --- # Check that we assign a relevant register bank for %0. # Based on the type i32, this should be gpr. name: defaultMapping legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } body: | bb.0.entry: liveins: $x0 ; CHECK-LABEL: name: defaultMapping ; CHECK: %1:gpr(s32) = G_ADD %0 %0(s32) = COPY $w0 %1(s32) = G_ADD %0, %0 ... --- # Check that we assign a relevant register bank for %0. # Based on the type <2 x i32>, this should be fpr. # FPR is used for both floating point and vector registers. name: defaultMappingVector legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } body: | bb.0.entry: liveins: $d0 ; CHECK-LABEL: name: defaultMappingVector ; CHECK: %0:fpr(<2 x s32>) = COPY $d0 ; CHECK: %1:fpr(<2 x s32>) = G_ADD %0 %0(<2 x s32>) = COPY $d0 %1(<2 x s32>) = G_ADD %0, %0 ... --- # Check that we repair the assignment for %0. # Indeed based on the source of the copy it should live # in FPR, but at the use, it should be GPR. name: defaultMapping1Repair legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: _ } body: | bb.0.entry: liveins: $s0, $x0 ; CHECK-LABEL: name: defaultMapping1Repair ; CHECK: %0:fpr(s32) = COPY $s0 ; CHECK-NEXT: %1:gpr(s32) = COPY $w0 ; CHECK-NEXT: %3:gpr(s32) = COPY %0 ; CHECK-NEXT: %2:gpr(s32) = G_ADD %3, %1 %0(s32) = COPY $s0 %1(s32) = COPY $w0 %2(s32) = G_ADD %0, %1 ... # Check that we repair the assignment for %0 differently for both uses. name: defaultMapping2Repairs legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } body: | bb.0.entry: liveins: $s0, $x0 ; CHECK-LABEL: name: defaultMapping2Repairs ; CHECK: %0:fpr(s32) = COPY $s0 ; CHECK-NEXT: %2:gpr(s32) = COPY %0 ; CHECK-NEXT: %3:gpr(s32) = COPY %0 ; CHECK-NEXT: %1:gpr(s32) = G_ADD %2, %3 %0(s32) = COPY $s0 %1(s32) = G_ADD %0, %0 ... --- # Check that we repair the definition of %1. # %1 is forced to be into FPR, but its definition actually # requires that it lives in GPR. Make sure regbankselect # fixes that. name: defaultMappingDefRepair legalized: true registers: - { id: 0, class: _ } - { id: 1, class: fpr } body: | bb.0.entry: liveins: $w0 ; CHECK-LABEL: name: defaultMappingDefRepair ; CHECK: %0:gpr(s32) = COPY $w0 ; CHECK-NEXT: %2:gpr(s32) = G_ADD %0, %0 ; CHECK-NEXT: %1:fpr(s32) = COPY %2 %0(s32) = COPY $w0 %1(s32) = G_ADD %0, %0 ... --- # Check that we are able to propagate register banks from phis. name: phiPropagation legalized: true tracksRegLiveness: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: gpr32, preferred-register: '' } # CHECK-NEXT: - { id: 1, class: gpr64sp, preferred-register: '' } # CHECK-NEXT: - { id: 2, class: gpr32, preferred-register: '' } # CHECK-NEXT: - { id: 3, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 4, class: gpr, preferred-register: '' } registers: - { id: 0, class: gpr32 } - { id: 1, class: gpr64sp } - { id: 2, class: gpr32 } - { id: 3, class: _ } - { id: 4, class: _ } - { id: 5, class: _ } body: | bb.0.entry: successors: %bb.2.end, %bb.1.then liveins: $x0, $x1, $w2 %0 = LDRWui killed $x0, 0 :: (load 4 from %ir.src) %5(s32) = COPY %0 %1(p0) = COPY $x1 %2 = COPY $w2 TBNZW killed %2, 0, %bb.2.end bb.1.then: successors: %bb.2.end %3(s32) = G_ADD %5, %5 bb.2.end: %4(s32) = PHI %0, %bb.0.entry, %3, %bb.1.then G_STORE killed %4, killed %1 :: (store 4 into %ir.dst) RET_ReallyLR ... --- # Make sure we can repair physical register uses as well. name: defaultMappingUseRepairPhysReg legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: _ } body: | bb.0.entry: liveins: $w0, $s0 ; CHECK-LABEL: name: defaultMappingUseRepairPhysReg ; CHECK: %0:gpr(s32) = COPY $w0 ; CHECK-NEXT: %1:fpr(s32) = COPY $s0 ; CHECK-NEXT: %3:gpr(s32) = COPY %1 ; CHECK-NEXT: %2:gpr(s32) = G_ADD %0, %3 %0(s32) = COPY $w0 %1(s32) = COPY $s0 %2(s32) = G_ADD %0, %1 ... --- # Make sure we can repair physical register defs. name: defaultMappingDefRepairPhysReg legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } body: | bb.0.entry: liveins: $w0 ; CHECK-LABEL: name: defaultMappingDefRepairPhysReg ; CHECK: %0:gpr(s32) = COPY $w0 ; CHECK-NEXT: %1:gpr(s32) = G_ADD %0, %0 ; CHECK-NEXT: $s0 = COPY %1 %0(s32) = COPY $w0 %1(s32) = G_ADD %0, %0 $s0 = COPY %1 ... --- # Check that the greedy mode is able to switch the # G_OR instruction from fpr to gpr. name: greedyMappingOr legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: _ } body: | bb.0.entry: liveins: $x0, $x1 ; CHECK: %0:gpr(<2 x s32>) = COPY $x0 ; CHECK-NEXT: %1:gpr(<2 x s32>) = COPY $x1 ; Fast mode tries to reuse the source of the copy for the destination. ; Now, the default mapping says that %0 and %1 need to be in FPR. ; The repairing code insert two copies to materialize that. ; FAST-NEXT: %3:fpr(<2 x s32>) = COPY %0 ; FAST-NEXT: %4:fpr(<2 x s32>) = COPY %1 ; The mapping of G_OR is on FPR. ; FAST-NEXT: %2:fpr(<2 x s32>) = G_OR %3, %4 ; Greedy mode remapped the instruction on the GPR bank. ; GREEDY-NEXT: %2:gpr(<2 x s32>) = G_OR %0, %1 %0(<2 x s32>) = COPY $x0 %1(<2 x s32>) = COPY $x1 %2(<2 x s32>) = G_OR %0, %1 ... --- # Check that the greedy mode is able to switch the # G_OR instruction from fpr to gpr, while still honoring # %2 constraint. name: greedyMappingOrWithConstraints legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: fpr } body: | bb.0.entry: liveins: $x0, $x1 ; CHECK-LABEL: name: greedyMappingOrWithConstraints ; CHECK: %0:gpr(<2 x s32>) = COPY $x0 ; CHECK-NEXT: %1:gpr(<2 x s32>) = COPY $x1 ; Fast mode tries to reuse the source of the copy for the destination. ; Now, the default mapping says that %0 and %1 need to be in FPR. ; The repairing code insert two copies to materialize that. ; FAST-NEXT: %3:fpr(<2 x s32>) = COPY %0 ; FAST-NEXT: %4:fpr(<2 x s32>) = COPY %1 ; The mapping of G_OR is on FPR. ; FAST-NEXT: %2:fpr(<2 x s32>) = G_OR %3, %4 ; Greedy mode remapped the instruction on the GPR bank. ; GREEDY-NEXT: %3:gpr(<2 x s32>) = G_OR %0, %1 ; We need to keep %2 into FPR because we do not know anything about it. ; GREEDY-NEXT: %2:fpr(<2 x s32>) = COPY %3 %0(<2 x s32>) = COPY $x0 %1(<2 x s32>) = COPY $x1 %2(<2 x s32>) = G_OR %0, %1 ... --- # CHECK-LABEL: name: ignoreTargetSpecificInst name: ignoreTargetSpecificInst legalized: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: gpr64, preferred-register: '' } # CHECK-NEXT: - { id: 1, class: gpr64, preferred-register: '' } registers: - { id: 0, class: gpr64 } - { id: 1, class: gpr64 } body: | bb.0: liveins: $x0 ; CHECK: %0:gpr64 = COPY $x0 ; CHECK-NEXT: %1:gpr64 = ADDXrr %0, %0 ; CHECK-NEXT: $x0 = COPY %1 ; CHECK-NEXT: RET_ReallyLR implicit $x0 %0 = COPY $x0 %1 = ADDXrr %0, %0 $x0 = COPY %1 RET_ReallyLR implicit $x0 ... --- # Check that we set the "regBankSelected" property. # CHECK-LABEL: name: regBankSelected_property # CHECK: legalized: true # CHECK: regBankSelected: true name: regBankSelected_property legalized: true regBankSelected: false body: | bb.0: ... --- # CHECK-LABEL: name: bitcast_s32_gpr name: bitcast_s32_gpr legalized: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 1, class: gpr, preferred-register: '' } registers: - { id: 0, class: _ } - { id: 1, class: _ } # CHECK: body: # CHECK: %0:gpr(s32) = COPY $w0 # CHECK: %1:gpr(s32) = G_BITCAST %0 body: | bb.0: liveins: $w0 %0(s32) = COPY $w0 %1(s32) = G_BITCAST %0 ... --- # CHECK-LABEL: name: bitcast_s32_fpr name: bitcast_s32_fpr legalized: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: fpr, preferred-register: '' } # CHECK-NEXT: - { id: 1, class: fpr, preferred-register: '' } registers: - { id: 0, class: _ } - { id: 1, class: _ } # CHECK: body: # CHECK: %0:fpr(<2 x s16>) = COPY $s0 # CHECK: %1:fpr(<2 x s16>) = G_BITCAST %0 body: | bb.0: liveins: $s0 %0(<2 x s16>) = COPY $s0 %1(<2 x s16>) = G_BITCAST %0 ... --- # CHECK-LABEL: name: bitcast_s32_gpr_fpr name: bitcast_s32_gpr_fpr legalized: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' } # FAST-NEXT: - { id: 1, class: fpr, preferred-register: '' } # GREEDY-NEXT: - { id: 1, class: gpr, preferred-register: '' } registers: - { id: 0, class: _ } - { id: 1, class: _ } # CHECK: body: # CHECK: %0:gpr(s32) = COPY $w0 # FAST: %1:fpr(<2 x s16>) = G_BITCAST %0 # GREEDY: %1:gpr(<2 x s16>) = G_BITCAST %0 body: | bb.0: liveins: $w0 %0(s32) = COPY $w0 %1(<2 x s16>) = G_BITCAST %0 ... --- # CHECK-LABEL: name: bitcast_s32_fpr_gpr name: bitcast_s32_fpr_gpr legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } # CHECK: body: # CHECK: %0:fpr(<2 x s16>) = COPY $s0 # FAST: %1:gpr(s32) = G_BITCAST %0 # GREEDY: %1:fpr(s32) = G_BITCAST %0 body: | bb.0: liveins: $s0 %0(<2 x s16>) = COPY $s0 %1(s32) = G_BITCAST %0 ... --- # CHECK-LABEL: name: bitcast_s64_gpr name: bitcast_s64_gpr legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } # CHECK: body: # CHECK: %0:gpr(s64) = COPY $x0 # CHECK: %1:gpr(s64) = G_BITCAST %0 body: | bb.0: liveins: $x0 %0(s64) = COPY $x0 %1(s64) = G_BITCAST %0 ... --- # CHECK-LABEL: name: bitcast_s64_fpr name: bitcast_s64_fpr legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } # CHECK: body: # CHECK: %0:fpr(<2 x s32>) = COPY $d0 # CHECK: %1:fpr(<2 x s32>) = G_BITCAST %0 body: | bb.0: liveins: $d0 %0(<2 x s32>) = COPY $d0 %1(<2 x s32>) = G_BITCAST %0 ... --- # CHECK-LABEL: name: bitcast_s64_gpr_fpr name: bitcast_s64_gpr_fpr legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } # CHECK: body: # CHECK: %0:gpr(s64) = COPY $x0 # FAST: %1:fpr(<2 x s32>) = G_BITCAST %0 # GREEDY: %1:gpr(<2 x s32>) = G_BITCAST %0 body: | bb.0: liveins: $x0 %0(s64) = COPY $x0 %1(<2 x s32>) = G_BITCAST %0 ... --- # CHECK-LABEL: name: bitcast_s64_fpr_gpr name: bitcast_s64_fpr_gpr legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } # CHECK: body: # CHECK: %0:fpr(<2 x s32>) = COPY $d0 # FAST: %1:gpr(s64) = G_BITCAST %0 # GREEDY: %1:fpr(s64) = G_BITCAST %0 body: | bb.0: liveins: $d0 %0(<2 x s32>) = COPY $d0 %1(s64) = G_BITCAST %0 ... --- # CHECK-LABEL: name: bitcast_s128 name: bitcast_s128 legalized: true tracksRegLiveness: true registers: - { id: 0, class: _} - { id: 1, class: _} - { id: 2, class: _} - { id: 3, class: _} # CHECK: %3:fpr(s128) = G_MERGE_VALUES # CHECK: %2:fpr(<2 x s64>) = G_BITCAST %3(s128) body: | bb.1: liveins: $x0, $x1 %0(s64) = COPY $x0 %1(s64) = COPY $x1 %3(s128) = G_MERGE_VALUES %0(s64), %1(s64) %2(<2 x s64>) = G_BITCAST %3(s128) $q0 = COPY %2(<2 x s64>) RET_ReallyLR implicit $q0 ... --- # CHECK-LABEL: name: copy_s128 # This test checks that we issue the proper mapping # for copy of size > 64. # The mapping should be the same as G_BITCAST. name: copy_s128 legalized: true tracksRegLiveness: true registers: - { id: 0, class: _} - { id: 1, class: _} - { id: 2, class: _} - { id: 3, class: _} - { id: 4, class: _} # CHECK: %3:fpr(s128) = G_MERGE_VALUES # CHECK: %4:fpr(s128) = COPY %3(s128) # CHECK-NEXT: %2:fpr(<2 x s64>) = G_BITCAST %4(s128) body: | bb.1: liveins: $x0, $x1 %0(s64) = COPY $x0 %1(s64) = COPY $x1 %3(s128) = G_MERGE_VALUES %0(s64), %1(s64) %4(s128) = COPY %3(s128) %2(<2 x s64>) = G_BITCAST %4(s128) $q0 = COPY %2(<2 x s64>) RET_ReallyLR implicit $q0 ... --- # CHECK-LABEL: name: copy_s128_from_load # This test checks that we issue the proper mapping # for copy of size > 64 when the input is neither # a physcal register nor a generic register. # This used to crash when we moved to the statically # computed mapping, because we were assuming non-physregs # were generic registers and thus have a type, whereas # it is not necessarily the case. name: copy_s128_from_load legalized: true tracksRegLiveness: true registers: - { id: 0, class: fpr128} - { id: 1, class: _} # CHECK: registers: # CHECK: - { id: 0, class: fpr128, preferred-register: '' } # CHECK: - { id: 1, class: fpr, preferred-register: '' } # CHECK: %1:fpr(s128) = COPY %0 body: | bb.1: liveins: $x0 %0 = LDRQui killed $x0, 0 %1(s128) = COPY %0 $q0 = COPY %1(s128) RET_ReallyLR implicit $q0 ... --- # CHECK-LABEL: name: copy_fp16 # This test checks that we issue the proper mapping # for copy of size == 16 when the destination is a fpr # physical register and the source a gpr. # We used to crash because we thought that mapping couldn't # exist in a copy. name: copy_fp16 legalized: true tracksRegLiveness: true registers: - { id: 0, class: _} - { id: 1, class: _} # CHECK: registers: # CHECK: - { id: 0, class: gpr, preferred-register: '' } # CHECK: - { id: 1, class: gpr, preferred-register: '' } # CHECK: %0:gpr(s32) = COPY $w0 # CHECK-NEXT: %1:gpr(s16) = G_TRUNC %0(s32) body: | bb.1: liveins: $w0 %0(s32) = COPY $w0 %1(s16) = G_TRUNC %0(s32) $h0 = COPY %1(s16) RET_ReallyLR implicit $h0 ... --- # Make sure the greedy mode is able to take advantage of the # alternative mappings of G_LOAD to coalesce the whole chain # of computation on GPR. # CHECK-LABEL: name: greedyWithChainOfComputation name: greedyWithChainOfComputation legalized: true registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: _ } - { id: 3, class: _ } - { id: 4, class: _ } - { id: 5, class: _ } # No repairing should be necessary for both modes. # CHECK: %0:gpr(s64) = COPY $x0 # CHECK-NEXT: %1:gpr(p0) = COPY $x1 # FAST-NEXT: %2:fpr(<2 x s32>) = G_BITCAST %0(s64) # FAST-NEXT: %3:fpr(<2 x s32>) = G_LOAD %1(p0) :: (load 8 from %ir.addr) # FAST-NEXT: %4:fpr(<2 x s32>) = G_OR %2, %3 # GREEDY-NEXT: %2:gpr(<2 x s32>) = G_BITCAST %0(s64) # GREEDY-NEXT: %3:gpr(<2 x s32>) = G_LOAD %1(p0) :: (load 8 from %ir.addr) # GREEDY-NEXT: %4:gpr(<2 x s32>) = G_OR %2, %3 # CHECK-NEXT: %5:gpr(s64) = G_BITCAST %4(<2 x s32>) # CHECK-NEXT: $x0 = COPY %5(s64) # CHECK-NEXT: RET_ReallyLR implicit $x0 body: | bb.0: liveins: $x0, $x1 %0(s64) = COPY $x0 %1(p0) = COPY $x1 %2(<2 x s32>) = G_BITCAST %0(s64) %3(<2 x s32>) = G_LOAD %1(p0) :: (load 8 from %ir.addr) %4(<2 x s32>) = G_OR %2, %3 %5(s64) = G_BITCAST %4(<2 x s32>) $x0 = COPY %5(s64) RET_ReallyLR implicit $x0 ... --- # Make sure we map what looks like floating point # loads to floating point register bank. # CHECK-LABEL: name: floatingPointLoad name: floatingPointLoad legalized: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 1, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 2, class: fpr, preferred-register: '' } # CHECK-NEXT: - { id: 3, class: fpr, preferred-register: '' } # CHECK-NEXT: - { id: 4, class: fpr, preferred-register: '' } registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: _ } - { id: 3, class: _ } # No repairing should be necessary for both modes. # CHECK: %0:gpr(s64) = COPY $x0 # CHECK-NEXT: %1:gpr(p0) = COPY $x1 # CHECK-NEXT: %2:fpr(s64) = G_LOAD %1(p0) :: (load 8 from %ir.addr) # %0 has been mapped to GPR, we need to repair to match FPR. # CHECK-NEXT: %4:fpr(s64) = COPY %0 # CHECK-NEXT: %3:fpr(s64) = G_FADD %4, %2 # CHECK-NEXT: $x0 = COPY %3(s64) # CHECK-NEXT: RET_ReallyLR implicit $x0 body: | bb.0: liveins: $x0, $x1 %0(s64) = COPY $x0 %1(p0) = COPY $x1 %2(s64) = G_LOAD %1(p0) :: (load 8 from %ir.addr) %3(s64) = G_FADD %0, %2 $x0 = COPY %3(s64) RET_ReallyLR implicit $x0 ... --- # Make sure we map what looks like floating point # stores to floating point register bank. # CHECK-LABEL: name: floatingPointStore name: floatingPointStore legalized: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 1, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 2, class: fpr, preferred-register: '' } # CHECK-NEXT: - { id: 3, class: fpr, preferred-register: '' } # CHECK-NEXT: - { id: 4, class: fpr, preferred-register: '' } registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: _ } # CHECK: %0:gpr(s64) = COPY $x0 # CHECK-NEXT: %1:gpr(p0) = COPY $x1 # %0 has been mapped to GPR, we need to repair to match FPR. # CHECK-NEXT: %3:fpr(s64) = COPY %0 # CHECK-NEXT: %4:fpr(s64) = COPY %0 # CHECK-NEXT: %2:fpr(s64) = G_FADD %3, %4 # CHECK-NEXT: G_STORE %2(s64), %1(p0) :: (store 8 into %ir.addr) # CHECK-NEXT: RET_ReallyLR body: | bb.0: liveins: $x0, $x1 %0(s64) = COPY $x0 %1(p0) = COPY $x1 %2(s64) = G_FADD %0, %0 G_STORE %2(s64), %1(p0) :: (store 8 into %ir.addr) RET_ReallyLR ... --- # Make sure we map FPEXT on FPR register bank. # CHECK-LABEL: name: fp16Ext32 name: fp16Ext32 alignment: 2 legalized: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 1, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 2, class: fpr, preferred-register: '' } # CHECK-NEXT: - { id: 3, class: fpr, preferred-register: '' } registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: _ } # CHECK: %1:gpr(s32) = COPY $w0 # CHECK-NEXT: %0:gpr(s16) = G_TRUNC %1 # %0 has been mapped to GPR, we need to repair to match FPR. # CHECK-NEXT: %3:fpr(s16) = COPY %0 # CHECK-NEXT: %2:fpr(s32) = G_FPEXT %3 # CHECK-NEXT: $s0 = COPY %2 # CHECK-NEXT: RET_ReallyLR body: | bb.1: liveins: $w0 %1(s32) = COPY $w0 %0(s16) = G_TRUNC %1(s32) %2(s32) = G_FPEXT %0(s16) $s0 = COPY %2(s32) RET_ReallyLR implicit $s0 ... --- # Make sure we map FPEXT on FPR register bank. # CHECK-LABEL: name: fp16Ext64 name: fp16Ext64 alignment: 2 legalized: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 1, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 2, class: fpr, preferred-register: '' } # CHECK-NEXT: - { id: 3, class: fpr, preferred-register: '' } registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: _ } # CHECK: %1:gpr(s32) = COPY $w0 # CHECK-NEXT: %0:gpr(s16) = G_TRUNC %1 # %0 has been mapped to GPR, we need to repair to match FPR. # CHECK-NEXT: %3:fpr(s16) = COPY %0 # CHECK-NEXT: %2:fpr(s64) = G_FPEXT %3 # CHECK-NEXT: $d0 = COPY %2 # CHECK-NEXT: RET_ReallyLR body: | bb.1: liveins: $w0 %1(s32) = COPY $w0 %0(s16) = G_TRUNC %1(s32) %2(s64) = G_FPEXT %0(s16) $d0 = COPY %2(s64) RET_ReallyLR implicit $d0 ... --- # Make sure we map FPEXT on FPR register bank. # CHECK-LABEL: name: fp32Ext64 name: fp32Ext64 alignment: 2 legalized: true # CHECK: registers: # CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' } # CHECK-NEXT: - { id: 1, class: fpr, preferred-register: '' } # CHECK-NEXT: - { id: 2, class: fpr, preferred-register: '' } registers: - { id: 0, class: _ } - { id: 1, class: _ } # CHECK: %0:gpr(s32) = COPY $w0 # %0 has been mapped to GPR, we need to repair to match FPR. # CHECK-NEXT: %2:fpr(s32) = COPY %0 # CHECK-NEXT: %1:fpr(s64) = G_FPEXT %2 # CHECK-NEXT: $d0 = COPY %1 # CHECK-NEXT: RET_ReallyLR body: | bb.1: liveins: $w0 %0(s32) = COPY $w0 %1(s64) = G_FPEXT %0(s32) $d0 = COPY %1(s64) RET_ReallyLR implicit $d0 ... --- # Make sure we map FP16 ABI on FPR register bank. # CHECK-LABEL: name: passFp16 # CHECK: registers: # CHECK: - { id: 0, class: fpr, preferred-register: '' } # CHECK: %0:fpr(s16) = COPY $h0 # CHECK-NEXT: $h0 = COPY %0(s16) name: passFp16 alignment: 2 legalized: true registers: - { id: 0, class: _ } body: | bb.1.entry: liveins: $h0 %0(s16) = COPY $h0 $h0 = COPY %0(s16) RET_ReallyLR implicit $h0 ... --- # Make sure we properly detect fp types through copies. # In that example, the copy comes from an ABI lowering of a fp type. # CHECK-LABEL: name: passFp16ViaAllocas # CHECK: registers: # CHECK: - { id: 0, class: fpr, preferred-register: '' } # CHECK: - { id: 1, class: gpr, preferred-register: '' } # CHECK: - { id: 2, class: fpr, preferred-register: '' } # # CHECK: %0:fpr(s16) = COPY $h0 # CHECK-NEXT: %1:gpr(p0) = G_FRAME_INDEX %stack.0.p.addr # If we didn't look through the copy for %0, the default mapping # would have been on GPR and we would have to insert a copy to move # the value away from FPR (h0). # CHECK-NEXT: G_STORE %0(s16), %1(p0) :: (store 2 into %ir.p.addr) # If we didn't look through the copy for %2, the default mapping # would have been on GPR and we would have to insert a copy to move # the value to FPR (h0). # CHECK-NEXT: %2:fpr(s16) = G_LOAD %1(p0) :: (load 2 from %ir.p.addr) # CHECK-NEXT: $h0 = COPY %2(s16) name: passFp16ViaAllocas alignment: 2 legalized: true tracksRegLiveness: true registers: - { id: 0, class: _ } - { id: 1, class: _ } - { id: 2, class: _ } frameInfo: maxAlignment: 2 stack: - { id: 0, name: p.addr, size: 2, alignment: 2, stack-id: 0 } body: | bb.1.entry: liveins: $h0 %0(s16) = COPY $h0 %1(p0) = G_FRAME_INDEX %stack.0.p.addr G_STORE %0(s16), %1(p0) :: (store 2 into %ir.p.addr) %2(s16) = G_LOAD %1(p0) :: (load 2 from %ir.p.addr) $h0 = COPY %2(s16) RET_ReallyLR implicit $h0 ...