[PowerPC][AIX] Enable the default AltiVec ABI on AIX

This patch adds support for the default AltiVec ABI for AIX.

Vector registers 20 through 31 are marked as reserved and cannot
be used in the default ABI. This patch adds handling for this case
and also remove the default AltiVec ABI errors.

Reviewed By: sfertile

Differential Revision: https://reviews.llvm.org/D96351
This commit is contained in:
Zarko Todorovski 2021-03-05 12:36:45 -05:00
parent 232fec941d
commit 2b50ce1524
5 changed files with 264 additions and 27 deletions

View File

@ -6307,11 +6307,6 @@ static bool CC_AIX(unsigned ValNo, MVT ValVT, MVT LocVT,
const Align PtrAlign = IsPPC64 ? Align(8) : Align(4); const Align PtrAlign = IsPPC64 ? Align(8) : Align(4);
const MVT RegVT = IsPPC64 ? MVT::i64 : MVT::i32; const MVT RegVT = IsPPC64 ? MVT::i64 : MVT::i32;
if (ValVT.isVector() && !State.getMachineFunction()
.getTarget()
.Options.EnableAIXExtendedAltivecABI)
report_fatal_error("the default Altivec AIX ABI is not yet supported");
if (ValVT == MVT::f128) if (ValVT == MVT::f128)
report_fatal_error("f128 is unimplemented on AIX."); report_fatal_error("f128 is unimplemented on AIX.");
@ -15327,6 +15322,15 @@ PPCTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
R.first = PPC::CR0; R.first = PPC::CR0;
R.second = &PPC::CRRCRegClass; R.second = &PPC::CRRCRegClass;
} }
// FIXME: This warning should ideally be emitted in the front end.
const auto &TM = getTargetMachine();
if (Subtarget.isAIXABI() && !TM.getAIXExtendedAltivecABI()) {
if (((R.first >= PPC::V20 && R.first <= PPC::V31) ||
(R.first >= PPC::VF20 && R.first <= PPC::VF31)) &&
(R.second == &PPC::VSRCRegClass || R.second == &PPC::VSFRCRegClass))
errs() << "warning: vector registers 20 to 32 are reserved in the "
"default AIX AltiVec ABI and cannot be used\n";
}
return R; return R;
} }

View File

@ -156,10 +156,6 @@ PPCRegisterInfo::getPointerRegClass(const MachineFunction &MF, unsigned Kind)
const MCPhysReg* const MCPhysReg*
PPCRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { PPCRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
const PPCSubtarget &Subtarget = MF->getSubtarget<PPCSubtarget>(); const PPCSubtarget &Subtarget = MF->getSubtarget<PPCSubtarget>();
if (Subtarget.isAIXABI() &&
(Subtarget.hasAltivec() && !TM.getAIXExtendedAltivecABI()))
report_fatal_error("the default AIX Altivec ABI is not yet "
"supported.");
if (MF->getFunction().getCallingConv() == CallingConv::AnyReg) { if (MF->getFunction().getCallingConv() == CallingConv::AnyReg) {
if (!TM.isPPC64() && Subtarget.isAIXABI()) if (!TM.isPPC64() && Subtarget.isAIXABI())
report_fatal_error("AnyReg unimplemented on 32-bit AIX."); report_fatal_error("AnyReg unimplemented on 32-bit AIX.");
@ -200,15 +196,18 @@ PPCRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
} }
// Standard calling convention CSRs. // Standard calling convention CSRs.
if (TM.isPPC64()) { if (TM.isPPC64()) {
if (Subtarget.hasAltivec()) if (Subtarget.hasAltivec() &&
(!Subtarget.isAIXABI() || TM.getAIXExtendedAltivecABI())) {
return SaveR2 ? CSR_PPC64_R2_Altivec_SaveList return SaveR2 ? CSR_PPC64_R2_Altivec_SaveList
: CSR_PPC64_Altivec_SaveList; : CSR_PPC64_Altivec_SaveList;
}
return SaveR2 ? CSR_PPC64_R2_SaveList : CSR_PPC64_SaveList; return SaveR2 ? CSR_PPC64_R2_SaveList : CSR_PPC64_SaveList;
} }
// 32-bit targets. // 32-bit targets.
if (Subtarget.isAIXABI()) { if (Subtarget.isAIXABI()) {
if (Subtarget.hasAltivec()) if (Subtarget.hasAltivec())
return CSR_AIX32_Altivec_SaveList; return TM.getAIXExtendedAltivecABI() ? CSR_AIX32_Altivec_SaveList
: CSR_AIX32_SaveList;
return CSR_AIX32_SaveList; return CSR_AIX32_SaveList;
} }
if (Subtarget.hasAltivec()) if (Subtarget.hasAltivec())
@ -231,10 +230,13 @@ PPCRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
} }
if (Subtarget.isAIXABI()) { if (Subtarget.isAIXABI()) {
return TM.isPPC64() ? (Subtarget.hasAltivec() ? CSR_PPC64_Altivec_RegMask return TM.isPPC64()
: CSR_PPC64_RegMask) ? ((Subtarget.hasAltivec() && TM.getAIXExtendedAltivecABI())
: (Subtarget.hasAltivec() ? CSR_AIX32_Altivec_RegMask ? CSR_PPC64_Altivec_RegMask
: CSR_AIX32_RegMask); : CSR_PPC64_RegMask)
: ((Subtarget.hasAltivec() && TM.getAIXExtendedAltivecABI())
? CSR_AIX32_Altivec_RegMask
: CSR_AIX32_RegMask);
} }
if (CC == CallingConv::Cold) { if (CC == CallingConv::Cold) {
@ -335,6 +337,17 @@ BitVector PPCRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
IE = PPC::VRRCRegClass.end(); I != IE; ++I) IE = PPC::VRRCRegClass.end(); I != IE; ++I)
markSuperRegs(Reserved, *I); markSuperRegs(Reserved, *I);
if (Subtarget.isAIXABI() && Subtarget.hasAltivec() &&
!TM.getAIXExtendedAltivecABI()) {
// In the AIX default Altivec ABI, vector registers VR20-VR31 are reserved
// and cannot be used.
for (auto Reg : CSR_Altivec_SaveList) {
if (Reg == 0)
break;
markSuperRegs(Reserved, Reg);
}
}
assert(checkAllSuperRegsMarked(Reserved)); assert(checkAllSuperRegsMarked(Reserved));
return Reserved; return Reserved;
} }
@ -426,15 +439,28 @@ unsigned PPCRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC,
unsigned FP = TFI->hasFP(MF) ? 1 : 0; unsigned FP = TFI->hasFP(MF) ? 1 : 0;
return 32 - FP - DefaultSafety; return 32 - FP - DefaultSafety;
} }
case PPC::F8RCRegClassID:
case PPC::F4RCRegClassID: case PPC::F4RCRegClassID:
case PPC::VRRCRegClassID: case PPC::F8RCRegClassID:
case PPC::VFRCRegClassID:
case PPC::VSLRCRegClassID: case PPC::VSLRCRegClassID:
return 32 - DefaultSafety; return 32 - DefaultSafety;
case PPC::VSRCRegClassID: case PPC::VFRCRegClassID:
case PPC::VRRCRegClassID: {
const PPCSubtarget &Subtarget = MF.getSubtarget<PPCSubtarget>();
// Vector registers VR20-VR31 are reserved and cannot be used in the default
// Altivec ABI on AIX.
if (!TM.getAIXExtendedAltivecABI() && Subtarget.isAIXABI())
return 20 - DefaultSafety;
}
return 32 - DefaultSafety;
case PPC::VSFRCRegClassID: case PPC::VSFRCRegClassID:
case PPC::VSSRCRegClassID: case PPC::VSSRCRegClassID:
case PPC::VSRCRegClassID: {
const PPCSubtarget &Subtarget = MF.getSubtarget<PPCSubtarget>();
if (!TM.getAIXExtendedAltivecABI() && Subtarget.isAIXABI())
// Vector registers VR20-VR31 are reserved and cannot be used in the
// default Altivec ABI on AIX.
return 52 - DefaultSafety;
}
return 64 - DefaultSafety; return 64 - DefaultSafety;
case PPC::CRRCRegClassID: case PPC::CRRCRegClassID:
return 8 - DefaultSafety; return 8 - DefaultSafety;

View File

@ -0,0 +1,201 @@
; RUN: llc -mtriple=powerpc-unknown-aix-xcoff -verify-machineinstrs -mcpu=pwr7 \
; RUN: -mattr=+altivec -stop-after=prologepilog < %s | \
; RUN: FileCheck --check-prefix=MIR32 %s
; RUN: llc -mtriple=powerpc-unknown-aix-xcoff -verify-machineinstrs \
; RUN: -mcpu=pwr7 -mattr=+altivec < %s | \
; RUN: FileCheck --check-prefix=ASM32 %s
; RUN: llc -mtriple=powerpc64-unknown-aix-xcoff -verify-machineinstrs \
; RUN: -mcpu=pwr7 -mattr=+altivec -stop-after=prologepilog < %s | \
; RUN: FileCheck --check-prefix=MIR64 %s
; RUN: llc -mtriple=powerpc64-unknown-aix-xcoff -verify-machineinstrs \
; RUN: -mcpu=pwr7 -mattr=+altivec < %s | \
; RUN: FileCheck --check-prefix=ASM64 %s
define dso_local void @vec_regs() {
entry:
call void asm sideeffect "", "~{v13},~{v20},~{v26},~{v31}"()
ret void
}
; MIR32-LABEL: name: vec_regs
; MIR32: fixedStack: []
; MIR32-NOT: STXVD2X killed $v20
; MIR32-NOT: STXVD2X killed $v26
; MIR32-NOT: STXVD2X killed $v31
; MIR32-LABEL: INLINEASM
; MIR32-NOT: $v20 = LXVD2X
; MIR32-NOT: $v26 = LXVD2X
; MIR32-NOT: $v31 = LXVD2X
; MIR32: BLR implicit $lr, implicit $rm
; MIR64-LABEL: name: vec_regs
; MIR64: fixedStack: []
; MIR64-NOT: STXVD2X killed $v20
; MIR64-NOT: STXVD2X killed $v26
; MIR64-NOT: STXVD2X killed $v31
; MIR64-LABEL: INLINEASM
; MIR64-NOT: $v20 = LXVD2X
; MIR64-NOT: $v26 = LXVD2X
; MIR64-NOT: $v31 = LXVD2X
; MIR64: BLR8 implicit $lr8, implicit $rm
; ASM32-LABEL: .vec_regs:
; ASM32-NOT: 20
; ASM32-NOT: 26
; ASM32-NOT: 31
; ASM32-DAG: #APP
; ASM32-DAG: #NO_APP
; ASM32: blr
; ASM64-LABEL: .vec_regs:
; ASM64-NOT: 20
; ASM64-NOT: 26
; ASM64-NOT: 31
; ASM64-DAG: #APP
; ASM64-DAG: #NO_APP
; ASM64: blr
define dso_local void @fprs_gprs_vecregs() {
call void asm sideeffect "", "~{r14},~{r25},~{r31},~{f14},~{f21},~{f31},~{v20},~{v26},~{v31}"()
ret void
}
; MIR32-LABEL: name: fprs_gprs_vecregs
; MIR32: fixedStack:
; MIR32: liveins: $r14, $r25, $r31, $f14, $f21, $f31
; MIR32-NOT: STXVD2X killed $v20
; MIR32-NOT: STXVD2X killed $v26
; MIR32-NOT: STXVD2X killed $v31
; MIR32-DAG: STW killed $r14, -216, $r1 :: (store 4 into %fixed-stack.5, align 8)
; MIR32-DAG: STW killed $r25, -172, $r1 :: (store 4 into %fixed-stack.4)
; MIR32-DAG: STW killed $r31, -148, $r1 :: (store 4 into %fixed-stack.3)
; MIR32-DAG: STFD killed $f14, -144, $r1 :: (store 8 into %fixed-stack.2, align 16)
; MIR32-DAG: STFD killed $f21, -88, $r1 :: (store 8 into %fixed-stack.1)
; MIR32-DAG: STFD killed $f31, -8, $r1 :: (store 8 into %fixed-stack.0)
; MIR32-LABEL: INLINEASM
; MIR32-NOT: $v20 = LXVD2X
; MIR32-NOT: $v26 = LXVD2X
; MIR32-NOT: $v31 = LXVD2X
; MIR32-DAG: $r14 = LWZ -216, $r1 :: (load 4 from %fixed-stack.5, align 8)
; MIR32-DAG: $r25 = LWZ -172, $r1 :: (load 4 from %fixed-stack.4)
; MIR32-DAG: $r31 = LWZ -148, $r1 :: (load 4 from %fixed-stack.3)
; MIR32-DAG: $f14 = LFD -144, $r1 :: (load 8 from %fixed-stack.2, align 16)
; MIR32-DAG: $f21 = LFD -88, $r1 :: (load 8 from %fixed-stack.1)
; MIR32-DAG: $f31 = LFD -8, $r1 :: (load 8 from %fixed-stack.0)
; MIR32-DAG: BLR implicit $lr, implicit $rm
; MIR64-LABEL: name: fprs_gprs_vecregs
; MIR64: fixedStack:
; MIR64: liveins: $x14, $x25, $x31, $f14, $f21, $f31
; MIR64-NOT: STXVD2X killed $v20
; MIR64-NOT: STXVD2X killed $v26
; MIR64-NOT: STXVD2X killed $v31
; MIR64-DAG: STD killed $x14, -288, $x1 :: (store 8 into %fixed-stack.5, align 16)
; MIR64-DAG: STD killed $x25, -200, $x1 :: (store 8 into %fixed-stack.4)
; MIR64-DAG: STD killed $x31, -152, $x1 :: (store 8 into %fixed-stack.3)
; MIR64-DAG: STFD killed $f14, -144, $x1 :: (store 8 into %fixed-stack.2, align 16)
; MIR64-DAG: STFD killed $f21, -88, $x1 :: (store 8 into %fixed-stack.1)
; MIR64-DAG: STFD killed $f31, -8, $x1 :: (store 8 into %fixed-stack.0)
; MIR64-LABEL: INLINEASM
; MIR64-NOT: $v20 = LXVD2X
; MIR64-NOT: $v26 = LXVD2X
; MIR64-NOT: $v31 = LXVD2X
; MIR64-DAG: $x14 = LD -288, $x1 :: (load 8 from %fixed-stack.5, align 16)
; MIR64-DAG: $x25 = LD -200, $x1 :: (load 8 from %fixed-stack.4)
; MIR64-DAG: $x31 = LD -152, $x1 :: (load 8 from %fixed-stack.3)
; MIR64-DAG: $f14 = LFD -144, $x1 :: (load 8 from %fixed-stack.2, align 16)
; MIR64-DAG: $f21 = LFD -88, $x1 :: (load 8 from %fixed-stack.1)
; MIR64-DAG: $f31 = LFD -8, $x1 :: (load 8 from %fixed-stack.0)
; MIR64: BLR8 implicit $lr8, implicit $rm
;; We don't have -ppc-full-reg-names on AIX so can't reliably check-not for
;; only vector registers numbers in this case.
; ASM32-LABEL: .fprs_gprs_vecregs:
; ASM32-DAG: stw 14, -216(1) # 4-byte Folded Spill
; ASM32-DAG: stw 25, -172(1) # 4-byte Folded Spill
; ASM32-DAG: stw 31, -148(1) # 4-byte Folded Spill
; ASM32-DAG: stfd 14, -144(1) # 8-byte Folded Spill
; ASM32-DAG: stfd 21, -88(1) # 8-byte Folded Spill
; ASM32-DAG: stfd 31, -8(1) # 8-byte Folded Spill
; ASM32-DAG: #APP
; ASM32-DAG: #NO_APP
; ASM32-DAG: lfd 31, -8(1) # 8-byte Folded Reload
; ASM32-DAG: lfd 21, -88(1) # 8-byte Folded Reload
; ASM32-DAG: lfd 14, -144(1) # 8-byte Folded Reload
; ASM32-DAG: lwz 31, -148(1) # 4-byte Folded Reload
; ASM32-DAG: lwz 25, -172(1) # 4-byte Folded Reload
; ASM32-DAG: lwz 14, -216(1) # 4-byte Folded Reload
; ASM32: blr
; ASM64-LABEL .fprs_gprs_vecregs:
; ASM64-DAG: std 14, -288(1) # 8-byte Folded Spill
; ASM64-DAG: std 25, -200(1) # 8-byte Folded Spill
; ASM64-DAG: std 31, -152(1) # 8-byte Folded Spill
; ASM64-DAG: stfd 14, -144(1) # 8-byte Folded Spill
; ASM64-DAG: stfd 21, -88(1) # 8-byte Folded Spill
; ASM64-DAG: stfd 31, -8(1) # 8-byte Folded Spill
; ASM64-DAG: #APP
; ASM64-DAG: #NO_APP
; ASM64-DAG: lfd 31, -8(1) # 8-byte Folded Reload
; ASM64-DAG: lfd 21, -88(1) # 8-byte Folded Reload
; ASM64-DAG: lfd 14, -144(1) # 8-byte Folded Reload
; ASM64-DAG: ld 31, -152(1) # 8-byte Folded Reload
; ASM64-DAG: ld 25, -200(1) # 8-byte Folded Reload
; ASM64-DAG: ld 14, -288(1) # 8-byte Folded Reload
; ASM64: blr
define dso_local void @all_fprs_and_vecregs() {
call void asm sideeffect "", "~{f0},~{f1},~{f2},~{f3},~{f4},~{f5},~{f6},~{f7},~{f8},~{f9},~{f10},~{f12},~{f13},~{f14},~{f15},~{f16},~{f17},~{f18},~{f19},~{f20},~{f21},~{f22},~{f23},~{f24},~{f25},~{f26},~{f27},~{f28},~{f29},~{f30},~{f31},~{v0},~{v1},~{v2},~{v3},~{v4},~{v5},~{v6}~{v7},~{v8},~{v9},~{v10},~{v11},~{v12},~{v13},~{v14},~{v15},~{v16},~{v17},~{v18},~{v19}"()
ret void
}
;; Check that reserved vectors are not used.
; MIR32-LABEL: all_fprs_and_vecregs
; MIR32-NOT: $v20
; MIR32-NOT: $v21
; MIR32-NOT: $v22
; MIR32-NOT: $v23
; MIR32-NOT: $v24
; MIR32-NOT: $v25
; MIR32-NOT: $v26
; MIR32-NOT: $v27
; MIR32-NOT: $v28
; MIR32-NOT: $v29
; MIR32-NOT: $v30
; MIR32-NOT: $v31
; MIR64-LABEL: all_fprs_and_vecregs
; MIR64-NOT: $v20
; MIR64-NOT: $v21
; MIR64-NOT: $v22
; MIR64-NOT: $v23
; MIR64-NOT: $v24
; MIR64-NOT: $v25
; MIR64-NOT: $v26
; MIR64-NOT: $v27
; MIR64-NOT: $v28
; MIR64-NOT: $v29
; MIR64-NOT: $v30
; MIR64-NOT: $v31

View File

@ -0,0 +1,14 @@
; RUN: llc < %s -mtriple=powerpc-unknown-aix-xcoff -verify-machineinstrs \
; RUN: -mcpu=pwr7 -mattr=+altivec 2>&1 | \
; RUN: FileCheck --check-prefix=DFLTWRN %s
; RUN: llc < %s -mtriple=powerpc64-unknown-aix-xcoff -verify-machineinstrs \
; RUN: -mcpu=pwr7 -mattr=+altivec 2>&1 | \
; RUN: FileCheck --check-prefix=DFLTWRN %s
define dso_local void @vec_warn() {
entry:
call void asm sideeffect "", "~{v23}"()
ret void
}
; DFLTWRN: warning: vector registers 20 to 32 are reserved in the default AIX AltiVec ABI and cannot be used

View File

@ -1,8 +0,0 @@
; RUN: not --crash llc < %s -mtriple powerpc64-ibm-aix-xcoff -mcpu=pwr8 2>&1 | FileCheck %s --check-prefix=DFLTERROR
; RUN: not --crash llc < %s -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr8 2>&1 | FileCheck %s --check-prefix=DFLTERROR
define void @vec_callee(<4 x i32> %vec1) {
ret void
}
; DFLTERROR: LLVM ERROR: the default Altivec AIX ABI is not yet supported