diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp index 42cf674632f46..3f832df50fa3b 100644 --- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -282,6 +282,11 @@ struct PPCOperand : public MCParsedAsmOperand { return (unsigned) Imm.Val; } + unsigned getFpReg() const { + assert(isEvenRegNumber() && "Invalid access!"); + return (unsigned)(Imm.Val >> 1); + } + unsigned getVSReg() const { assert(isVSRegNumber() && "Invalid access!"); return (unsigned) Imm.Val; @@ -502,6 +507,11 @@ struct PPCOperand : public MCParsedAsmOperand { Inst.addOperand(MCOperand::createReg(FRegs[getReg()])); } + void addRegFpRCOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(FpRegs[getFpReg()])); + } + void addRegVFRCOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(VFRegs[getReg()])); diff --git a/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp b/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp index 9faad9b742097..3d9a9ccb18659 100644 --- a/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp +++ b/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp @@ -112,6 +112,14 @@ static DecodeStatus DecodeF8RCRegisterClass(MCInst &Inst, uint64_t RegNo, return decodeRegisterClass(Inst, RegNo, FRegs); } +static DecodeStatus DecodeFpRCRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const MCDisassembler *Decoder) { + assert(RegNo <= 30 && "Expecting a register number no more than 30."); + assert((RegNo & 1) == 0 && "Expecting an even register number."); + return decodeRegisterClass(Inst, RegNo >> 1, FpRegs); +} + static DecodeStatus DecodeVFRCRegisterClass(MCInst &Inst, uint64_t RegNo, uint64_t Address, const MCDisassembler *Decoder) { diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h index 3b9d5bc8f64dc..86ca1386fed9a 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h @@ -136,6 +136,12 @@ static inline bool isRunOfOnes64(uint64_t Val, unsigned &MB, unsigned &ME) { X##22, X##23, X##24, X##25, X##26, X##27, X##28, X##29, X##30, X##31 \ } +#define PPC_REGS_EVEN0_30(X) \ + { \ + X##0, X##2, X##4, X##6, X##8, X##10, X##12, X##14, X##16, X##18, X##20, \ + X##22, X##24, X##26, X##28, X##30 \ + } + #define PPC_REGS0_63(X) \ { \ X##0, X##1, X##2, X##3, X##4, X##5, X##6, X##7, X##8, X##9, X##10, X##11, \ @@ -178,41 +184,34 @@ static inline bool isRunOfOnes64(uint64_t Val, unsigned &MB, unsigned &ME) { using llvm::MCPhysReg; -#define DEFINE_PPC_REGCLASSES \ - static const MCPhysReg RRegs[32] = PPC_REGS0_31(PPC::R); \ - static const MCPhysReg XRegs[32] = PPC_REGS0_31(PPC::X); \ - static const MCPhysReg FRegs[32] = PPC_REGS0_31(PPC::F); \ - static const MCPhysReg VSRpRegs[32] = PPC_REGS0_31(PPC::VSRp); \ - static const MCPhysReg SPERegs[32] = PPC_REGS0_31(PPC::S); \ - static const MCPhysReg VFRegs[32] = PPC_REGS0_31(PPC::VF); \ - static const MCPhysReg VRegs[32] = PPC_REGS0_31(PPC::V); \ - static const MCPhysReg RRegsNoR0[32] = \ - PPC_REGS_NO0_31(PPC::ZERO, PPC::R); \ - static const MCPhysReg XRegsNoX0[32] = \ - PPC_REGS_NO0_31(PPC::ZERO8, PPC::X); \ - static const MCPhysReg VSRegs[64] = \ - PPC_REGS_LO_HI(PPC::VSL, PPC::V); \ - static const MCPhysReg VSFRegs[64] = \ - PPC_REGS_LO_HI(PPC::F, PPC::VF); \ - static const MCPhysReg VSSRegs[64] = \ - PPC_REGS_LO_HI(PPC::F, PPC::VF); \ - static const MCPhysReg CRBITRegs[32] = { \ - PPC::CR0LT, PPC::CR0GT, PPC::CR0EQ, PPC::CR0UN, \ - PPC::CR1LT, PPC::CR1GT, PPC::CR1EQ, PPC::CR1UN, \ - PPC::CR2LT, PPC::CR2GT, PPC::CR2EQ, PPC::CR2UN, \ - PPC::CR3LT, PPC::CR3GT, PPC::CR3EQ, PPC::CR3UN, \ - PPC::CR4LT, PPC::CR4GT, PPC::CR4EQ, PPC::CR4UN, \ - PPC::CR5LT, PPC::CR5GT, PPC::CR5EQ, PPC::CR5UN, \ - PPC::CR6LT, PPC::CR6GT, PPC::CR6EQ, PPC::CR6UN, \ - PPC::CR7LT, PPC::CR7GT, PPC::CR7EQ, PPC::CR7UN}; \ - static const MCPhysReg CRRegs[8] = PPC_REGS0_7(PPC::CR); \ - static const MCPhysReg ACCRegs[8] = PPC_REGS0_7(PPC::ACC); \ - static const MCPhysReg WACCRegs[8] = PPC_REGS0_7(PPC::WACC); \ - static const MCPhysReg WACC_HIRegs[8] = PPC_REGS0_7(PPC::WACC_HI); \ - static const MCPhysReg DMRROWpRegs[32] = PPC_REGS0_31(PPC::DMRROWp); \ - static const MCPhysReg DMRROWRegs[64] = PPC_REGS0_63(PPC::DMRROW); \ - static const MCPhysReg DMRRegs[8] = PPC_REGS0_7(PPC::DMR); \ +#define DEFINE_PPC_REGCLASSES \ + static const MCPhysReg RRegs[32] = PPC_REGS0_31(PPC::R); \ + static const MCPhysReg XRegs[32] = PPC_REGS0_31(PPC::X); \ + static const MCPhysReg FRegs[32] = PPC_REGS0_31(PPC::F); \ + static const MCPhysReg FpRegs[16] = PPC_REGS_EVEN0_30(PPC::Fpair); \ + static const MCPhysReg VSRpRegs[32] = PPC_REGS0_31(PPC::VSRp); \ + static const MCPhysReg SPERegs[32] = PPC_REGS0_31(PPC::S); \ + static const MCPhysReg VFRegs[32] = PPC_REGS0_31(PPC::VF); \ + static const MCPhysReg VRegs[32] = PPC_REGS0_31(PPC::V); \ + static const MCPhysReg RRegsNoR0[32] = PPC_REGS_NO0_31(PPC::ZERO, PPC::R); \ + static const MCPhysReg XRegsNoX0[32] = PPC_REGS_NO0_31(PPC::ZERO8, PPC::X); \ + static const MCPhysReg VSRegs[64] = PPC_REGS_LO_HI(PPC::VSL, PPC::V); \ + static const MCPhysReg VSFRegs[64] = PPC_REGS_LO_HI(PPC::F, PPC::VF); \ + static const MCPhysReg VSSRegs[64] = PPC_REGS_LO_HI(PPC::F, PPC::VF); \ + static const MCPhysReg CRBITRegs[32] = { \ + PPC::CR0LT, PPC::CR0GT, PPC::CR0EQ, PPC::CR0UN, PPC::CR1LT, PPC::CR1GT, \ + PPC::CR1EQ, PPC::CR1UN, PPC::CR2LT, PPC::CR2GT, PPC::CR2EQ, PPC::CR2UN, \ + PPC::CR3LT, PPC::CR3GT, PPC::CR3EQ, PPC::CR3UN, PPC::CR4LT, PPC::CR4GT, \ + PPC::CR4EQ, PPC::CR4UN, PPC::CR5LT, PPC::CR5GT, PPC::CR5EQ, PPC::CR5UN, \ + PPC::CR6LT, PPC::CR6GT, PPC::CR6EQ, PPC::CR6UN, PPC::CR7LT, PPC::CR7GT, \ + PPC::CR7EQ, PPC::CR7UN}; \ + static const MCPhysReg CRRegs[8] = PPC_REGS0_7(PPC::CR); \ + static const MCPhysReg ACCRegs[8] = PPC_REGS0_7(PPC::ACC); \ + static const MCPhysReg WACCRegs[8] = PPC_REGS0_7(PPC::WACC); \ + static const MCPhysReg WACC_HIRegs[8] = PPC_REGS0_7(PPC::WACC_HI); \ + static const MCPhysReg DMRROWpRegs[32] = PPC_REGS0_31(PPC::DMRROWp); \ + static const MCPhysReg DMRROWRegs[64] = PPC_REGS0_63(PPC::DMRROW); \ + static const MCPhysReg DMRRegs[8] = PPC_REGS0_7(PPC::DMR); \ static const MCPhysReg DMRpRegs[4] = PPC_REGS0_3(PPC::DMRp); - #endif // LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCMCTARGETDESC_H diff --git a/llvm/lib/Target/PowerPC/PPCInstrDFP.td b/llvm/lib/Target/PowerPC/PPCInstrDFP.td new file mode 100644 index 0000000000000..be13ed9b69c5b --- /dev/null +++ b/llvm/lib/Target/PowerPC/PPCInstrDFP.td @@ -0,0 +1,28 @@ +//===-- PPCInstrDFP.td - PowerPC Decimal Floating Point ----*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file describes the PowerPC Decimal Floating Point (DFP) instructions. +// +//===----------------------------------------------------------------------===// + +// We provide no scheduling info for the DFP instructions. +// While they are not pseudo instructions we don't intend on scheduling them. +let hasNoSchedulingInfo = 1 in { +defm DADD : XForm_28r<59, 2, (outs f8rc:$RST), (ins f8rc:$RA, f8rc:$RB), + "dadd", "$RST, $RA, $RB", IIC_FPGeneral, []>; + +defm DADDQ : XForm_28r<63, 2, (outs fpairrc:$RST), (ins fpairrc:$RA, fpairrc:$RB), + "daddq", "$RST, $RA, $RB", IIC_FPGeneral, []>; + +defm DSUB : XForm_28r<59, 514, (outs f8rc:$RST), (ins f8rc:$RA, f8rc:$RB), + "dsub", "$RST, $RA, $RB", IIC_FPGeneral, []>; + +defm DSUBQ : XForm_28r<63, 514, (outs fpairrc:$RST), (ins fpairrc:$RA, fpairrc:$RB), + "dsubq", "$RST, $RA, $RB", IIC_FPGeneral, []>; +} + diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td index bcd87eb599ef4..8681f3eec38ff 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -3321,6 +3321,7 @@ include "PPCInstrP10.td" include "PPCInstrFutureMMA.td" include "PPCInstrFuture.td" include "PPCInstrMMA.td" +include "PPCInstrDFP.td" // Patterns for arithmetic i1 operations. def : Pat<(add i1:$a, i1:$b), diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.h b/llvm/lib/Target/PowerPC/PPCRegisterInfo.h index 781f6255dc72b..2a2fe25989367 100644 --- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.h +++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.h @@ -179,9 +179,12 @@ class PPCRegisterInfo : public PPCGenRegisterInfo { case 'a': if (RegName[1] == 'c' && RegName[2] == 'c') return RegName + 3; - break; - case 'r': + break; case 'f': + if (RegName[1] == 'p') + return RegName + 2; + LLVM_FALLTHROUGH; + case 'r': case 'v': if (RegName[1] == 's') { if (RegName[2] == 'p') diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.td b/llvm/lib/Target/PowerPC/PPCRegisterInfo.td index ea16392b89a67..a8932a2be2cc8 100644 --- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.td +++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.td @@ -20,6 +20,8 @@ def sub_vsx0 : SubRegIndex<128>; def sub_vsx1 : SubRegIndex<128, 128>; def sub_gp8_x0 : SubRegIndex<64>; def sub_gp8_x1 : SubRegIndex<64, 64>; +def sub_fp0 : SubRegIndex<64>; +def sub_fp1 : SubRegIndex<64, 64>; } @@ -58,6 +60,15 @@ class FPR num, string n> : PPCReg { let HWEncoding{4-0} = num; } +// FPPair - A pair of 64-bit floating-point registers. +class FPPair EvenIndex> : PPCReg { + assert !eq(EvenIndex{0}, 0), "Index should be even."; + let HWEncoding{4-0} = EvenIndex; + let SubRegs = [!cast("F"#EvenIndex), !cast("F"#!add(EvenIndex, 1))]; + let DwarfNumbers = [-1, -1]; + let SubRegIndices = [sub_fp0, sub_fp1]; +} + // VF - One of the 32 64-bit floating-point subregisters of the vector // registers (used by VSX). class VF num, string n> : PPCReg { @@ -136,6 +147,11 @@ foreach Index = 0-31 in { DwarfRegNum<[!add(Index, 32), !add(Index, 32)]>; } +// Floating-point pair registers +foreach Index = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 } in { + def Fpair#Index : FPPair<"fp"#Index, Index>; +} + // 64-bit Floating-point subregisters of Altivec registers // Note: the register names are v0-v31 or vs32-vs63 depending on the use. // Custom C++ code is used to produce the correct name and encoding. @@ -349,6 +365,21 @@ def F8RC : RegisterClass<"PPC", [f64], 64, (add (sequence "F%u", 0, 13), (sequence "F%u", 31, 14))>; def F4RC : RegisterClass<"PPC", [f32], 32, (add F8RC)>; +// Floating point pair registers. +// Note that the type used for this register class is ppcf128. This is not +// completely correct. However, since we are not pattern matching any +// instructions for these registers and we are not register allocating or +// scheduling any of these instructions it should be safe to do this. +// The reason we didn't use the correct type (Decimal Floating Point) is that +// at the time of this implementation the correct type was not available. +def FpRC : + RegisterClass<"PPC", [ppcf128], 128, + (add Fpair0, Fpair2, Fpair4, Fpair6, Fpair8, Fpair10, Fpair12, + Fpair14, Fpair16, Fpair18, Fpair20, Fpair22, Fpair24, + Fpair26, Fpair28, Fpair30)> { + let Size = 128; +} + def VRRC : RegisterClass<"PPC", [v16i8,v8i16,v4i32,v2i64,v1i128,v4f32,v2f64, f128], 128, @@ -504,6 +535,12 @@ def PPCRegF4RCAsmOperand : AsmOperandClass { def f4rc : RegisterOperand { let ParserMatchClass = PPCRegF4RCAsmOperand; } +def PPCRegFpRCAsmOperand : AsmOperandClass { + let Name = "RegFpRC"; let PredicateMethod = "isEvenRegNumber"; +} +def fpairrc : RegisterOperand { + let ParserMatchClass = PPCRegFpRCAsmOperand; +} def PPCRegVRRCAsmOperand : AsmOperandClass { let Name = "RegVRRC"; let PredicateMethod = "isRegNumber"; } diff --git a/llvm/test/MC/Disassembler/PowerPC/ppc64-encoding-dfp.txt b/llvm/test/MC/Disassembler/PowerPC/ppc64-encoding-dfp.txt new file mode 100644 index 0000000000000..3b7fa5f4e3bd5 --- /dev/null +++ b/llvm/test/MC/Disassembler/PowerPC/ppc64-encoding-dfp.txt @@ -0,0 +1,25 @@ +# RUN: llvm-mc --disassemble %s -triple powerpc64-unknown-unknown -mcpu=pwr7 | FileCheck %s + +# CHECK: dadd 2, 3, 4 +0xec 0x43 0x20 0x04 + +# CHECK: dadd. 2, 3, 4 +0xec 0x43 0x20 0x05 + +# CHECK: daddq 2, 6, 4 +0xfc 0x46 0x20 0x04 + +# CHECK: daddq. 2, 6, 4 +0xfc 0x46 0x20 0x05 + +# CHECK: dsub 2, 3, 4 +0xec 0x43 0x24 0x04 + +# CHECK: dsub. 2, 3, 4 +0xec 0x43 0x24 0x05 + +# CHECK: dsubq 2, 6, 4 +0xfc 0x46 0x24 0x04 + +# CHECK: dsubq. 2, 6, 4 +0xfc 0x46 0x24 0x05 diff --git a/llvm/test/MC/PowerPC/invalid-instructions-spellcheck.s b/llvm/test/MC/PowerPC/invalid-instructions-spellcheck.s index b63e861fdc574..49798637eb511 100644 --- a/llvm/test/MC/PowerPC/invalid-instructions-spellcheck.s +++ b/llvm/test/MC/PowerPC/invalid-instructions-spellcheck.s @@ -39,6 +39,6 @@ xsnmsubad %r1, %r2 adXd %r1, %r2, %r3 -# CHECK: error: invalid instruction, did you mean: add, addc, adde, addi, addo, fadd? +# CHECK: error: invalid instruction, did you mean: add, addc, adde, addi, addo, dadd, fadd? # CHECK-NEXT: adXd %r1, %r2, %r3 # CHECK-NEXT: ^ diff --git a/llvm/test/MC/PowerPC/ppc64-encoding-dfp.s b/llvm/test/MC/PowerPC/ppc64-encoding-dfp.s new file mode 100644 index 0000000000000..4b76bd21c7911 --- /dev/null +++ b/llvm/test/MC/PowerPC/ppc64-encoding-dfp.s @@ -0,0 +1,28 @@ +# RUN: llvm-mc -triple powerpc64-unknown-unknown --show-encoding %s | FileCheck -check-prefix=CHECK-BE %s +# RUN: llvm-mc -triple powerpc64le-unknown-unknown --show-encoding %s | FileCheck -check-prefix=CHECK-LE %s + + +# CHECK-BE: dadd 2, 3, 4 # encoding: [0xec,0x43,0x20,0x04] +# CHECK-LE: dadd 2, 3, 4 # encoding: [0x04,0x20,0x43,0xec] + dadd 2, 3, 4 +# CHECK-BE: dadd. 2, 3, 4 # encoding: [0xec,0x43,0x20,0x05] +# CHECK-LE: dadd. 2, 3, 4 # encoding: [0x05,0x20,0x43,0xec] + dadd. 2, 3, 4 +# CHECK-BE: daddq 2, 6, 4 # encoding: [0xfc,0x46,0x20,0x04] +# CHECK-LE: daddq 2, 6, 4 # encoding: [0x04,0x20,0x46,0xfc] + daddq 2, 6, 4 +# CHECK-BE: daddq. 2, 6, 4 # encoding: [0xfc,0x46,0x20,0x05] +# CHECK-LE: daddq. 2, 6, 4 # encoding: [0x05,0x20,0x46,0xfc] + daddq. 2, 6, 4 +# CHECK-BE: dsub 2, 3, 4 # encoding: [0xec,0x43,0x24,0x04] +# CHECK-LE: dsub 2, 3, 4 # encoding: [0x04,0x24,0x43,0xec] + dsub 2, 3, 4 +# CHECK-BE: dsub. 2, 3, 4 # encoding: [0xec,0x43,0x24,0x05] +# CHECK-LE: dsub. 2, 3, 4 # encoding: [0x05,0x24,0x43,0xec] + dsub. 2, 3, 4 +# CHECK-BE: dsubq 2, 6, 4 # encoding: [0xfc,0x46,0x24,0x04] +# CHECK-LE: dsubq 2, 6, 4 # encoding: [0x04,0x24,0x46,0xfc] + dsubq 2, 6, 4 +# CHECK-BE: dsubq. 2, 6, 4 # encoding: [0xfc,0x46,0x24,0x05] +# CHECK-LE: dsubq. 2, 6, 4 # encoding: [0x05,0x24,0x46,0xfc] + dsubq. 2, 6, 4