diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -29,7 +29,7 @@ #define UNALIASED_CUSTOM_BUILTIN(ID, TYPES, ACCUMULATE) \ CUSTOM_BUILTIN(ID, ID, TYPES, ACCUMULATE) -// builtins for compatibility with the XL compiler +// XL Compatibility built-ins BUILTIN(__builtin_ppc_popcntb, "ULiULi", "") BUILTIN(__builtin_ppc_eieio, "v", "") BUILTIN(__builtin_ppc_iospace_eieio, "v", "") @@ -71,6 +71,21 @@ BUILTIN(__builtin_ppc_fctiwz, "dd", "") BUILTIN(__builtin_ppc_fctudz, "dd", "") BUILTIN(__builtin_ppc_fctuwz, "dd", "") +BUILTIN(__builtin_ppc_extract_exp, "Uid", "") +BUILTIN(__builtin_ppc_extract_sig, "ULLid", "") +BUILTIN(__builtin_ppc_mtfsb0, "vUIi", "") +BUILTIN(__builtin_ppc_mtfsb1, "vUIi", "") +BUILTIN(__builtin_ppc_mtfsf, "vUIiUi", "") +BUILTIN(__builtin_ppc_mtfsfi, "vUIiUIi", "") +BUILTIN(__builtin_ppc_insert_exp, "ddULLi", "") +BUILTIN(__builtin_ppc_fmsub, "dddd", "") +BUILTIN(__builtin_ppc_fmsubs, "ffff", "") +BUILTIN(__builtin_ppc_fnmadd, "dddd", "") +BUILTIN(__builtin_ppc_fnmadds, "ffff", "") +BUILTIN(__builtin_ppc_fnmsub, "dddd", "") +BUILTIN(__builtin_ppc_fnmsubs, "ffff", "") +BUILTIN(__builtin_ppc_fre, "dd", "") +BUILTIN(__builtin_ppc_fres, "ff", "") BUILTIN(__builtin_ppc_get_timebase, "ULLi", "n") diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -130,6 +130,21 @@ Builder.defineMacro("__fctiwz", "__builtin_ppc_fctiwz"); Builder.defineMacro("__fctudz", "__builtin_ppc_fctudz"); Builder.defineMacro("__fctuwz", "__builtin_ppc_fctuwz"); + Builder.defineMacro("__extract_exp", "__builtin_ppc_extract_exp"); + Builder.defineMacro("__extract_sig", "__builtin_ppc_extract_sig"); + Builder.defineMacro("__mtfsb0", "__builtin_ppc_mtfsb0"); + Builder.defineMacro("__mtfsb1", "__builtin_ppc_mtfsb1"); + Builder.defineMacro("__mtfsf", "__builtin_ppc_mtfsf"); + Builder.defineMacro("__mtfsfi", "__builtin_ppc_mtfsfi"); + Builder.defineMacro("__insert_exp", "__builtin_ppc_insert_exp"); + Builder.defineMacro("__fmsub", "__builtin_ppc_fmsub"); + Builder.defineMacro("__fmsubs", "__builtin_ppc_fmsubs"); + Builder.defineMacro("__fnmadd", "__builtin_ppc_fnmadd"); + Builder.defineMacro("__fnmadds", "__builtin_ppc_fnmadds"); + Builder.defineMacro("__fnmsub", "__builtin_ppc_fnmsub"); + Builder.defineMacro("__fnmsubs", "__builtin_ppc_fnmsubs"); + Builder.defineMacro("__fre", "__builtin_ppc_fre"); + Builder.defineMacro("__fres", "__builtin_ppc_fres"); } /// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3269,6 +3269,8 @@ case PPC::BI__builtin_ppc_stdcx: case PPC::BI__builtin_ppc_tdw: case PPC::BI__builtin_ppc_trapd: + case PPC::BI__builtin_ppc_insert_exp: + case PPC::BI__builtin_ppc_extract_sig: return true; } return false; @@ -3360,6 +3362,19 @@ case PPC::BI__builtin_ppc_tw: case PPC::BI__builtin_ppc_tdw: return SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + case PPC::BI__builtin_ppc_extract_exp: + case PPC::BI__builtin_ppc_extract_sig: + case PPC::BI__builtin_ppc_insert_exp: + return SemaFeatureCheck(*this, TheCall, "power9-vector", + diag::err_ppc_builtin_only_on_arch, "9"); + case PPC::BI__builtin_ppc_mtfsb0: + case PPC::BI__builtin_ppc_mtfsb1: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); + case PPC::BI__builtin_ppc_mtfsf: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 255); + case PPC::BI__builtin_ppc_mtfsfi: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7) || + SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); #define CUSTOM_BUILTIN(Name, Intr, Types, Acc) \ case PPC::BI__builtin_##Name: \ return SemaBuiltinPPCMMACall(TheCall, Types); diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-error.c b/clang/test/CodeGen/builtins-ppc-xlcompat-error.c --- a/clang/test/CodeGen/builtins-ppc-xlcompat-error.c +++ b/clang/test/CodeGen/builtins-ppc-xlcompat-error.c @@ -17,3 +17,20 @@ #endif __tw(ia, ib, 50); //expected-error {{argument value 50 is outside the valid range [0, 31]}} } + +extern unsigned int usi; +extern double d; +extern float f; + +void testMathBuiltin(void) { + __mtfsb0(usi); //expected-error {{argument to '__builtin_ppc_mtfsb0' must be a constant integer}} + __mtfsb0(32); //expected-error {{argument value 32 is outside the valid range [0, 31]}} + __mtfsb1(usi); //expected-error {{argument to '__builtin_ppc_mtfsb1' must be a constant integer}} + __mtfsb1(45); //expected-error {{argument value 45 is outside the valid range [0, 31]}} + __mtfsf(usi, usi); //expected-error {{argument to '__builtin_ppc_mtfsf' must be a constant integer}} + __mtfsf(350, usi); //expected-error {{argument value 350 is outside the valid range [0, 255]}} + __mtfsfi(usi, 0); //expected-error {{argument to '__builtin_ppc_mtfsfi' must be a constant integer}} + __mtfsfi(0, usi); //expected-error {{argument to '__builtin_ppc_mtfsfi' must be a constant integer}} + __mtfsfi(8, 0); //expected-error {{argument value 8 is outside the valid range [0, 7]}} + __mtfsfi(5, 24); //expected-error {{argument value 24 is outside the valid range [0, 15]}} +} diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-math.c b/clang/test/CodeGen/builtins-ppc-xlcompat-math.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtins-ppc-xlcompat-math.c @@ -0,0 +1,143 @@ +// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm %s \ +// RUN: -target-cpu pwr7 -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -emit-llvm %s \ +// RUN: -target-cpu pwr8 -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -emit-llvm %s \ +// RUN: -target-cpu pwr7 -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc-unknown-aix -emit-llvm %s \ +// RUN: -target-cpu pwr7 -o - | FileCheck %s + +// CHECK-LABEL: @mtfsb0( +// CHECK: call void @llvm.ppc.mtfsb0(i32 10) +// CHECK-NEXT: ret void +// +void mtfsb0 () { + __mtfsb0 (10); +} + +// CHECK-LABEL: @mtfsb1( +// CHECK: call void @llvm.ppc.mtfsb1(i32 0) +// CHECK-NEXT: ret void +// +void mtfsb1 () { + __mtfsb1 (0); +} + +// CHECK-LABEL: @mtfsf( +// CHECK: [[UI_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[UI:%.*]], i32* [[UI_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[UI_ADDR]], align 4 +// CHECK-NEXT: call void @llvm.ppc.mtfsf(i32 8, i32 [[TMP0]]) +// CHECK-NEXT: ret void +// +void mtfsf (unsigned int ui) { + __mtfsf (8, ui); +} + +// CHECK-LABEL: @mtfsfi( +// CHECK: call void @llvm.ppc.mtfsfi(i32 7, i32 15) +// CHECK-NEXT: ret void +// +void mtfsfi () { + __mtfsfi (7, 15); +} + +// CHECK-LABEL: @fmsub( +// CHECK: [[D_ADDR:%.*]] = alloca double, align 8 +// CHECK-NEXT: store double [[D:%.*]], double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = call double @llvm.ppc.fmsub(double [[TMP0]], double [[TMP1]], double [[TMP2]]) +// CHECK-NEXT: ret double [[TMP3]] +// +double fmsub (double d) { + return __fmsub (d, d, d); +} + +// CHECK-LABEL: @fmsubs( +// CHECK: [[F_ADDR:%.*]] = alloca float, align 4 +// CHECK-NEXT: store float [[F:%.*]], float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = call float @llvm.ppc.fmsubs(float [[TMP0]], float [[TMP1]], float [[TMP2]]) +// CHECK-NEXT: ret float [[TMP3]] +// +float fmsubs (float f) { + return __fmsubs (f, f, f); +} + +// CHECK-LABEL: @fnmadd( +// CHECK: [[D_ADDR:%.*]] = alloca double, align 8 +// CHECK-NEXT: store double [[D:%.*]], double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = call double @llvm.ppc.fnmadd(double [[TMP0]], double [[TMP1]], double [[TMP2]]) +// CHECK-NEXT: ret double [[TMP3]] +// +double fnmadd (double d) { + return __fnmadd (d, d, d); +} + +// CHECK-LABEL: @fnmadds( +// CHECK: [[F_ADDR:%.*]] = alloca float, align 4 +// CHECK-NEXT: store float [[F:%.*]], float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = call float @llvm.ppc.fnmadds(float [[TMP0]], float [[TMP1]], float [[TMP2]]) +// CHECK-NEXT: ret float [[TMP3]] +// +float fnmadds (float f) { + return __fnmadds (f, f, f); +} + +// CHECK-LABEL: @fnmsub( +// CHECK: [[D_ADDR:%.*]] = alloca double, align 8 +// CHECK-NEXT: store double [[D:%.*]], double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = call double @llvm.ppc.fnmsub(double [[TMP0]], double [[TMP1]], double [[TMP2]]) +// CHECK-NEXT: ret double [[TMP3]] +// +double fnmsub (double d) { + return __fnmsub (d, d, d); +} + +// CHECK-LABEL: @fnmsubs( +// CHECK: [[F_ADDR:%.*]] = alloca float, align 4 +// CHECK-NEXT: store float [[F:%.*]], float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = call float @llvm.ppc.fnmsubs(float [[TMP0]], float [[TMP1]], float [[TMP2]]) +// CHECK-NEXT: ret float [[TMP3]] +// +float fnmsubs (float f) { + return __fnmsubs (f, f, f); +} + +// CHECK-LABEL: @fre( +// CHECK: [[D_ADDR:%.*]] = alloca double, align 8 +// CHECK-NEXT: store double [[D:%.*]], double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load double, double* [[D_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.ppc.fre(double [[TMP0]]) +// CHECK-NEXT: ret double [[TMP1]] +// +double fre (double d) { + return __fre (d); +} + +// CHECK-LABEL: @fres( +// CHECK: [[F_ADDR:%.*]] = alloca float, align 4 +// CHECK-NEXT: store float [[F:%.*]], float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[F_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.ppc.fres(float [[TMP0]]) +// CHECK-NEXT: ret float [[TMP1]] +// +float fres (float f) { + return __fres (f); +} diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-pwr9-64bit.c b/clang/test/CodeGen/builtins-ppc-xlcompat-pwr9-64bit.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtins-ppc-xlcompat-pwr9-64bit.c @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm %s \ +// RUN: -target-cpu pwr9 -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -emit-llvm %s \ +// RUN: -target-cpu pwr9 -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -emit-llvm %s \ +// RUN: -target-cpu pwr9 -o - | FileCheck %s +// RUN: not %clang_cc1 -triple powerpc-unknown-aix %s \ +// RUN: -target-cpu pwr9 2>&1 | FileCheck %s --check-prefix=CHECK-32-ERROR +// RUN: not %clang_cc1 -triple powerpc64-unknown-aix -emit-llvm %s \ +// RUN: -target-cpu pwr8 2>&1 | FileCheck %s --check-prefix=CHECK-NONPWR9-ERR + +unsigned long long extract_sig (double d) { +// CHECK-LABEL: @extract_sig( +// CHECK: [[TMP1:%.*]] = call i64 @llvm.ppc.extract.sig(double %0) +// CHECK-NEXT: ret i64 [[TMP1]] +// +// CHECK-32-ERROR: error: this builtin is only available on 64-bit targets +// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs + return __extract_sig (d); +} + +double insert_exp (double d, unsigned long long ull) { +// CHECK-LABEL: @insert_exp( +// CHECK: [[TMP2:%.*]] = call double @llvm.ppc.insert.exp(double %0, i64 %1) +// CHECK-NEXT: ret double [[TMP2]] +// +// CHECK-32-ERROR: error: this builtin is only available on 64-bit targets +// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs + return __insert_exp (d, ull); +} diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-pwr9.c b/clang/test/CodeGen/builtins-ppc-xlcompat-pwr9.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtins-ppc-xlcompat-pwr9.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm %s \ +// RUN: -target-cpu pwr9 -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc64le-unknown-unknown -emit-llvm %s \ +// RUN: -target-cpu pwr9 -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -emit-llvm %s \ +// RUN: -target-cpu pwr9 -o - | FileCheck %s +// RUN: %clang_cc1 -triple powerpc-unknown-aix %s -emit-llvm %s \ +// RUN: -target-cpu pwr9 -o - | FileCheck %s +// RUN: not %clang_cc1 -triple powerpc64-unknown-aix -emit-llvm %s \ +// RUN: -target-cpu pwr8 2>&1 | FileCheck %s --check-prefix=CHECK-NONPWR9-ERR + +unsigned int extract_exp (double d) { +// CHECK-LABEL: @extract_exp +// CHECK: [[TMP1:%.*]] = call i32 @llvm.ppc.extract.exp(double %0) +// CHECK-NEXT: ret i32 [[TMP1]] +// CHECK-NONPWR9-ERR: error: this builtin is only valid on POWER9 or later CPUs + return __extract_exp (d); +} diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td --- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td +++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td @@ -1565,5 +1565,67 @@ def int_ppc_stwcx : GCCBuiltin<"__builtin_ppc_stwcx">, Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrWriteMem]>; + def int_ppc_insert_exp + : GCCBuiltin<"__builtin_ppc_insert_exp">, + Intrinsic <[llvm_double_ty], [llvm_double_ty, llvm_i64_ty], + [IntrNoMem]>; + def int_ppc_extract_exp + : GCCBuiltin<"__builtin_ppc_extract_exp">, + Intrinsic <[llvm_i32_ty], [llvm_double_ty], [IntrNoMem]>; + def int_ppc_extract_sig + : GCCBuiltin<"__builtin_ppc_extract_sig">, + Intrinsic <[llvm_i64_ty], [llvm_double_ty], [IntrNoMem]>; + def int_ppc_mtfsb0 + : GCCBuiltin<"__builtin_ppc_mtfsb0">, + Intrinsic <[], [llvm_i32_ty], + [IntrNoMem, IntrHasSideEffects, ImmArg>]>; + def int_ppc_mtfsb1 + : GCCBuiltin<"__builtin_ppc_mtfsb1">, + Intrinsic <[], [llvm_i32_ty], + [IntrNoMem, IntrHasSideEffects, ImmArg>]>; + def int_ppc_mtfsf + : GCCBuiltin<"__builtin_ppc_mtfsf">, + Intrinsic <[], [llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrHasSideEffects, ImmArg>]>; + def int_ppc_mtfsfi + : GCCBuiltin<"__builtin_ppc_mtfsfi">, + Intrinsic <[], [llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrHasSideEffects, + ImmArg>,ImmArg>]>; + def int_ppc_fmsub + : GCCBuiltin<"__builtin_ppc_fmsub">, + Intrinsic <[llvm_double_ty], + [llvm_double_ty, llvm_double_ty, llvm_double_ty], + [IntrNoMem]>; + def int_ppc_fmsubs + : GCCBuiltin<"__builtin_ppc_fmsubs">, + Intrinsic <[llvm_float_ty], + [llvm_float_ty, llvm_float_ty, llvm_float_ty], + [IntrNoMem]>; + def int_ppc_fnmadd + : GCCBuiltin<"__builtin_ppc_fnmadd">, + Intrinsic <[llvm_double_ty], + [llvm_double_ty, llvm_double_ty, llvm_double_ty], + [IntrNoMem]>; + def int_ppc_fnmadds + : GCCBuiltin<"__builtin_ppc_fnmadds">, + Intrinsic <[llvm_float_ty], + [llvm_float_ty, llvm_float_ty, llvm_float_ty], + [IntrNoMem]>; + def int_ppc_fnmsub + : GCCBuiltin<"__builtin_ppc_fnmsub">, + Intrinsic <[llvm_double_ty], + [llvm_double_ty, llvm_double_ty, llvm_double_ty], + [IntrNoMem]>; + def int_ppc_fnmsubs + : GCCBuiltin<"__builtin_ppc_fnmsubs">, + Intrinsic <[llvm_float_ty], + [llvm_float_ty, llvm_float_ty, llvm_float_ty], + [IntrNoMem]>; + def int_ppc_fre + : GCCBuiltin<"__builtin_ppc_fre">, + Intrinsic <[llvm_double_ty], [llvm_double_ty], [IntrNoMem]>; + def int_ppc_fres + : GCCBuiltin<"__builtin_ppc_fres">, + Intrinsic <[llvm_float_ty], [llvm_float_ty], [IntrNoMem]>; } - diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -3084,12 +3084,16 @@ // When FM is 30/31, we are setting the 62/63 bit of FPSCR, the implicit-def // RM should be set. +let hasSideEffects = 1 in { def MTFSB0 : XForm_43<63, 70, (outs), (ins u5imm:$FM), - "mtfsb0 $FM", IIC_IntMTFSB0, []>, + "mtfsb0 $FM", IIC_IntMTFSB0, + [(int_ppc_mtfsb0 timm:$FM)]>, PPC970_DGroup_Single, PPC970_Unit_FPU; def MTFSB1 : XForm_43<63, 38, (outs), (ins u5imm:$FM), - "mtfsb1 $FM", IIC_IntMTFSB0, []>, + "mtfsb1 $FM", IIC_IntMTFSB0, + [(int_ppc_mtfsb1 timm:$FM)]>, PPC970_DGroup_Single, PPC970_Unit_FPU; +} let Defs = [RM] in { let isCodeGenOnly = 1 in @@ -3642,6 +3646,16 @@ (FCPSGNS (COPY_TO_REGCLASS $frA, F4RC), $frB)>; } +// XL Compat intrinsics. +def : Pat<(int_ppc_fmsub f64:$A, f64:$B, f64:$C), (FMSUB $A, $B, $C)>; +def : Pat<(int_ppc_fmsubs f32:$A, f32:$B, f32:$C), (FMSUBS $A, $B, $C)>; +def : Pat<(int_ppc_fnmsub f64:$A, f64:$B, f64:$C), (FNMSUB $A, $B, $C)>; +def : Pat<(int_ppc_fnmsubs f32:$A, f32:$B, f32:$C), (FNMSUBS $A, $B, $C)>; +def : Pat<(int_ppc_fnmadd f64:$A, f64:$B, f64:$C), (FNMADD $A, $B, $C)>; +def : Pat<(int_ppc_fnmadds f32:$A, f32:$B, f32:$C), (FNMADDS $A, $B, $C)>; +def : Pat<(int_ppc_fre f64:$A), (FRE $A)>; +def : Pat<(int_ppc_fres f32:$A), (FRES $A)>; + include "PPCInstrAltivec.td" include "PPCInstrSPE.td" include "PPCInstr64Bit.td" diff --git a/llvm/lib/Target/PowerPC/PPCInstrVSX.td b/llvm/lib/Target/PowerPC/PPCInstrVSX.td --- a/llvm/lib/Target/PowerPC/PPCInstrVSX.td +++ b/llvm/lib/Target/PowerPC/PPCInstrVSX.td @@ -1539,10 +1539,10 @@ // Insert Exponent DP/QP // XT NOTE: XT.dword[1] = 0xUUUU_UUUU_UUUU_UUUU + def XSIEXPDP : XX1Form <60, 918, (outs vsrc:$XT), (ins g8rc:$rA, g8rc:$rB), + "xsiexpdp $XT, $rA, $rB", IIC_VecFP, []>; // FIXME: Setting the hasSideEffects flag here to match current behaviour. let hasSideEffects = 1 in { - def XSIEXPDP : XX1Form <60, 918, (outs vsrc:$XT), (ins g8rc:$rA, g8rc:$rB), - "xsiexpdp $XT, $rA, $rB", IIC_VecFP, []>; // vB NOTE: only vB.dword[0] is used, that's why we don't use // X_VT5_VA5_VB5 form def XSIEXPQP : XForm_18<63, 868, (outs vrrc:$vT), (ins vrrc:$vA, vsfrc:$vB), @@ -1550,11 +1550,11 @@ } // Extract Exponent/Significand DP/QP + def XSXEXPDP : XX2_RT5_XO5_XB6<60, 0, 347, "xsxexpdp", []>; + def XSXSIGDP : XX2_RT5_XO5_XB6<60, 1, 347, "xsxsigdp", []>; + // FIXME: Setting the hasSideEffects flag here to match current behaviour. let hasSideEffects = 1 in { - def XSXEXPDP : XX2_RT5_XO5_XB6<60, 0, 347, "xsxexpdp", []>; - def XSXSIGDP : XX2_RT5_XO5_XB6<60, 1, 347, "xsxsigdp", []>; - def XSXEXPQP : X_VT5_XO5_VB5 <63, 2, 804, "xsxexpqp", []>; def XSXSIGQP : X_VT5_XO5_VB5 <63, 18, 804, "xsxsigqp", []>; } @@ -2850,6 +2850,12 @@ def : Pat<(v2i64 (PPCvcmp_rec v2i64:$vA, v2i64:$vB, 199)), (VCMPGTUB_rec DblwdCmp.MRGEQ, (v2i64 (XXLXORz)))>; } // AddedComplexity = 0 + +// XL Compat builtins. +def : Pat<(int_ppc_fmsub f64:$A, f64:$B, f64:$C), (XSMSUBMDP $A, $B, $C)>; +def : Pat<(int_ppc_fnmsub f64:$A, f64:$B, f64:$C), (XSNMSUBMDP $A, $B, $C)>; +def : Pat<(int_ppc_fnmadd f64:$A, f64:$B, f64:$C), (XSNMADDMDP $A, $B, $C)>; +def : Pat<(int_ppc_fre f64:$A), (XSREDP $A)>; } // HasVSX // Any big endian VSX subtarget. @@ -3240,6 +3246,18 @@ (v8i16 (COPY_TO_REGCLASS(XXLEQVOnes), VSRC))>; def : Pat<(v16i8 (bitconvert (v16i8 immAllOnesV))), (v16i8 (COPY_TO_REGCLASS(XXLEQVOnes), VSRC))>; + +// XL Compat builtins. +def : Pat<(int_ppc_fmsubs f32:$A, f32:$B, f32:$C), (XSMSUBMSP $A, $B, $C)>; +def : Pat<(int_ppc_fnmsubs f32:$A, f32:$B, f32:$C), (XSNMSUBMSP $A, $B, $C)>; +def : Pat<(int_ppc_fnmadds f32:$A, f32:$B, f32:$C), (XSNMADDMSP $A, $B, $C)>; +def : Pat<(int_ppc_fres f32:$A), (XSRESP $A)>; +def : Pat<(i32 (int_ppc_extract_exp f64:$A)), + (EXTRACT_SUBREG (XSXEXPDP (COPY_TO_REGCLASS $A, VSFRC)), sub_32)>; +def : Pat<(int_ppc_extract_sig f64:$A), + (XSXSIGDP (COPY_TO_REGCLASS $A, VSFRC))>; +def : Pat<(f64 (int_ppc_insert_exp f64:$A, i64:$B)), + (COPY_TO_REGCLASS (XSIEXPDP (COPY_TO_REGCLASS $A, G8RC), $B), F8RC)>; } // HasVSX, HasP8Vector // Any big endian Power8 VSX subtarget. diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-math.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-math.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-math.ll @@ -0,0 +1,231 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu < %s |\ +; RUN: FileCheck %s --check-prefix=CHECK-PWR8 +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu \ +; RUN: -mattr=-vsx < %s | FileCheck %s --check-prefix=CHECK-NOVSX +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu \ +; RUN: -mcpu=pwr7 < %s | FileCheck %s --check-prefix=CHECK-PWR7 +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix -mcpu=pwr7 \ +; RUN: < %s | FileCheck %s --check-prefix=CHECK-PWR7 +; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-aix -mcpu=pwr8 < %s |\ +; RUN: FileCheck %s --check-prefix=CHECK-PWR8 + +define dso_local void @mtfsb0() { +; CHECK-PWR8-LABEL: mtfsb0: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: mtfsb0 10 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: mtfsb0: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: mtfsb0 10 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: mtfsb0: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: mtfsb0 10 +; CHECK-PWR7-NEXT: blr +entry: + tail call void @llvm.ppc.mtfsb0(i32 10) + ret void +} + +declare void @llvm.ppc.mtfsb0(i32 immarg) #1 + +define dso_local void @mtfsb1() { +; CHECK-PWR8-LABEL: mtfsb1: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: mtfsb1 0 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: mtfsb1: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: mtfsb1 0 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: mtfsb1: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: mtfsb1 0 +; CHECK-PWR7-NEXT: blr +entry: + tail call void @llvm.ppc.mtfsb1(i32 0) + ret void +} + +declare void @llvm.ppc.mtfsb1(i32 immarg) #1 + +define dso_local double @fmsub_t0(double %d, double %d2, double %d3) { +; CHECK-PWR8-LABEL: fmsub_t0: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: xsmsubmdp 1, 2, 3 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: fmsub_t0: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: fmsub 1, 1, 2, 3 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: fmsub_t0: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: xsmsubmdp 1, 2, 3 +; CHECK-PWR7-NEXT: blr +entry: + %0 = tail call double @llvm.ppc.fmsub(double %d, double %d2, double %d3) + ret double %0 +} + +declare double @llvm.ppc.fmsub(double, double, double) + +define dso_local float @fmsubs_t0(float %f, float %f2, float %f3) { +; CHECK-PWR8-LABEL: fmsubs_t0: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: xsmsubmsp 1, 2, 3 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: fmsubs_t0: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: fmsubs 1, 1, 2, 3 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: fmsubs_t0: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: fmsubs 1, 1, 2, 3 +; CHECK-PWR7-NEXT: blr +entry: + %0 = tail call float @llvm.ppc.fmsubs(float %f, float %f2, float %f3) + ret float %0 +} + +declare float @llvm.ppc.fmsubs(float, float, float) + +define dso_local double @fnmadd_t0(double %d, double %d2, double %d3) { +; CHECK-PWR8-LABEL: fnmadd_t0: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: xsnmaddmdp 1, 2, 3 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: fnmadd_t0: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: fnmadd 1, 1, 2, 3 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: fnmadd_t0: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: xsnmaddmdp 1, 2, 3 +; CHECK-PWR7-NEXT: blr +entry: + %0 = tail call double @llvm.ppc.fnmadd(double %d, double %d2, double %d3) + ret double %0 +} + +declare double @llvm.ppc.fnmadd(double, double, double) + +define dso_local float @fnmadds_t0(float %f, float %f2, float %f3) { +; CHECK-PWR8-LABEL: fnmadds_t0: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: xsnmaddmsp 1, 2, 3 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: fnmadds_t0: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: fnmadds 1, 1, 2, 3 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: fnmadds_t0: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: fnmadds 1, 1, 2, 3 +; CHECK-PWR7-NEXT: blr +entry: + %0 = tail call float @llvm.ppc.fnmadds(float %f, float %f2, float %f3) + ret float %0 +} + +declare float @llvm.ppc.fnmadds(float, float, float) + +define dso_local double @fnmsub_t0(double %d, double %d2, double %d3) { +; CHECK-PWR8-LABEL: fnmsub_t0: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: xsnmsubmdp 1, 2, 3 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: fnmsub_t0: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: fnmsub 1, 1, 2, 3 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: fnmsub_t0: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: xsnmsubmdp 1, 2, 3 +; CHECK-PWR7-NEXT: blr +entry: + %0 = tail call double @llvm.ppc.fnmsub(double %d, double %d2, double %d3) + ret double %0 +} + +declare double @llvm.ppc.fnmsub(double, double, double) + +define dso_local float @fnmsubs_t0(float %f, float %f2, float %f3) { +; CHECK-PWR8-LABEL: fnmsubs_t0: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: xsnmsubmsp 1, 2, 3 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: fnmsubs_t0: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: fnmsubs 1, 1, 2, 3 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: fnmsubs_t0: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: fnmsubs 1, 1, 2, 3 +; CHECK-PWR7-NEXT: blr +entry: + %0 = tail call float @llvm.ppc.fnmsubs(float %f, float %f2, float %f3) + ret float %0 +} + +declare float @llvm.ppc.fnmsubs(float, float, float) + +define dso_local double @fre(double %d) { +; CHECK-PWR8-LABEL: fre: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: xsredp 1, 1 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: fre: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: fre 1, 1 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: fre: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: xsredp 1, 1 +; CHECK-PWR7-NEXT: blr +entry: + %0 = tail call double @llvm.ppc.fre(double %d) + ret double %0 +} + +declare double @llvm.ppc.fre(double) + +define dso_local float @fres(float %f) { +; CHECK-PWR8-LABEL: fres: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: xsresp 1, 1 +; CHECK-PWR8-NEXT: blr +; +; CHECK-NOVSX-LABEL: fres: +; CHECK-NOVSX: # %bb.0: # %entry +; CHECK-NOVSX-NEXT: fres 1, 1 +; CHECK-NOVSX-NEXT: blr +; +; CHECK-PWR7-LABEL: fres: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: fres 1, 1 +; CHECK-PWR7-NEXT: blr +entry: + %0 = tail call float @llvm.ppc.fres(float %f) + ret float %0 +} + +declare float @llvm.ppc.fres(float) diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9-64bit.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9-64bit.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9-64bit.ll @@ -0,0 +1,31 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=pwr9 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu \ +; RUN: -mcpu=pwr9 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix \ +; RUN: -mcpu=pwr9 < %s | FileCheck %s + +define dso_local i64 @extract_sig(double %d) { +; CHECK-LABEL: extract_sig: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsxsigdp 3, 1 +; CHECK-NEXT: blr +entry: + %0 = tail call i64 @llvm.ppc.extract.sig(double %d) + ret i64 %0 +} +declare i64 @llvm.ppc.extract.sig(double) + +define dso_local double @insert_exp(double %d, i64 %ull) { +; CHECK-LABEL: insert_exp: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mffprd 3, 1 +; CHECK-NEXT: xsiexpdp 1, 3, 4 +; CHECK-NEXT: # kill: def $f1 killed $f1 killed $vsl1 +; CHECK-NEXT: blr +entry: + %0 = tail call double @llvm.ppc.insert.exp(double %d, i64 %ull) + ret double %0 +} +declare double @llvm.ppc.insert.exp(double, i64) diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-pwr9.ll @@ -0,0 +1,27 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=pwr9 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu \ +; RUN: -mcpu=pwr9 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix \ +; RUN: -mcpu=pwr9 < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-aix \ +; RUN: -mcpu=pwr9 < %s | FileCheck %s --check-prefix=CHECK-32BIT + +define dso_local zeroext i32 @extract_exp(double %d) { +; CHECK-LABEL: extract_exp: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xsxexpdp 3, 1 +; CHECK-NEXT: clrldi 3, 3, 32 +; CHECK-NEXT: blr +; +; CHECK-32BIT-LABEL: extract_exp: +; CHECK-32BIT: # %bb.0: # %entry +; CHECK-32BIT-NEXT: xsxexpdp 3, 1 +; CHECK-32BIT-NEXT: # kill: def $r3 killed $r3 killed $x3 +; CHECK-32BIT-NEXT: blr +entry: + %0 = tail call i32 @llvm.ppc.extract.exp(double %d) + ret i32 %0 +} +declare i32 @llvm.ppc.extract.exp(double)