diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -15620,6 +15620,13 @@ Function *F = CGM.getIntrinsic(Intrinsic::ppc_popcntb, {ArgType, ArgType}); return Builder.CreateCall(F, Ops, "popcntb"); } + case PPC::BI__builtin_ppc_mtfsf: { + // The builtin takes a uint32 that needs to be cast to an + // f64 to be passed to the intrinsic. + Value *Cast = Builder.CreateUIToFP(Ops[1], DoubleTy); + llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_mtfsf); + return Builder.CreateCall(F, {Ops[0], Cast}, ""); + } } } diff --git a/clang/test/CodeGen/builtins-ppc-xlcompat-math.c b/clang/test/CodeGen/builtins-ppc-xlcompat-math.c --- a/clang/test/CodeGen/builtins-ppc-xlcompat-math.c +++ b/clang/test/CodeGen/builtins-ppc-xlcompat-math.c @@ -24,10 +24,8 @@ } // 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: [[TMP0:%.*]] = uitofp i32 %{{.*}} to double +// CHECK-NEXT: call void @llvm.ppc.mtfsf(i32 8, double [[TMP0]]) // CHECK-NEXT: ret void // void mtfsf (unsigned int ui) { 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 @@ -1636,9 +1636,8 @@ : 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], + def int_ppc_mtfsf : + Intrinsic <[], [llvm_i32_ty, llvm_double_ty], [IntrNoMem, IntrHasSideEffects, ImmArg>]>; def int_ppc_mtfsfi : GCCBuiltin<"__builtin_ppc_mtfsfi">, diff --git a/llvm/lib/Target/PowerPC/P9InstrResources.td b/llvm/lib/Target/PowerPC/P9InstrResources.td --- a/llvm/lib/Target/PowerPC/P9InstrResources.td +++ b/llvm/lib/Target/PowerPC/P9InstrResources.td @@ -1079,7 +1079,8 @@ DISP_3SLOTS_1C, DISP_3SLOTS_1C], (instrs (instregex "MTFSF(b|_rec)?$"), - (instregex "MTFSFI(_rec)?$") + (instregex "MTFSFI(_rec)?$"), + MTFSFIb )>; // Cracked instruction made of two ALU ops. 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 @@ -3103,7 +3103,8 @@ let Defs = [RM] in { let isCodeGenOnly = 1 in def MTFSFb : XFLForm<63, 711, (outs), (ins i32imm:$FM, f8rc:$rT), - "mtfsf $FM, $rT", IIC_IntMTFSB0, []>, + "mtfsf $FM, $rT", IIC_IntMTFSB0, + [(int_ppc_mtfsf timm:$FM, f64:$rT)]>, PPC970_DGroup_Single, PPC970_Unit_FPU; } let Uses = [RM] in { @@ -4483,19 +4484,20 @@ def MCRFS : XLForm_3<63, 64, (outs crrc:$BF), (ins crrc:$BFA), "mcrfs $BF, $BFA", IIC_BrMCR>; -// If W is 0 and BF is 7, the 60:63 bits will be set, we should set the -// implicit-def RM. -def MTFSFI : XLForm_4<63, 134, (outs crrc:$BF), (ins i32imm:$U, i32imm:$W), +// All MTFSF variants may change the rounding mode so conservatively set it +// as an implicit def for all of them. +let Predicates = [HasFPU] in { +let Defs = [RM] in { +let isCodeGenOnly = 1, + Pattern = [(int_ppc_mtfsfi timm:$BF, timm:$U)], W = 0 in +def MTFSFIb : XLForm_4<63, 134, (outs), (ins u3imm:$BF, u4imm:$U), + "mtfsfi $BF, $U", IIC_IntMFFS>; +def MTFSFI : XLForm_4<63, 134, (outs), (ins u3imm:$BF, u4imm:$U, i32imm:$W), "mtfsfi $BF, $U, $W", IIC_IntMFFS>; let Defs = [CR1] in -def MTFSFI_rec : XLForm_4<63, 134, (outs crrc:$BF), (ins i32imm:$U, i32imm:$W), +def MTFSFI_rec : XLForm_4<63, 134, (outs), (ins u3imm:$BF, u4imm:$U, u1imm:$W), "mtfsfi. $BF, $U, $W", IIC_IntMFFS>, isRecordForm; -def : InstAlias<"mtfsfi $BF, $U", (MTFSFI crrc:$BF, i32imm:$U, 0)>; -def : InstAlias<"mtfsfi. $BF, $U", (MTFSFI_rec crrc:$BF, i32imm:$U, 0)>; - -let Predicates = [HasFPU] in { -let Defs = [RM] in { def MTFSF : XFLForm_1<63, 711, (outs), (ins i32imm:$FLM, f8rc:$FRB, u1imm:$L, i32imm:$W), "mtfsf $FLM, $FRB, $L, $W", IIC_IntMFFS, []>; @@ -4505,6 +4507,8 @@ "mtfsf. $FLM, $FRB, $L, $W", IIC_IntMFFS, []>, isRecordForm; } +def : InstAlias<"mtfsfi $BF, $U", (MTFSFI u3imm:$BF, u4imm:$U, 0)>; +def : InstAlias<"mtfsfi. $BF, $U", (MTFSFI_rec u3imm:$BF, u4imm:$U, 0)>; def : InstAlias<"mtfsf $FLM, $FRB", (MTFSF i32imm:$FLM, f8rc:$FRB, 0, 0)>; def : InstAlias<"mtfsf. $FLM, $FRB", (MTFSF_rec i32imm:$FLM, f8rc:$FRB, 0, 0)>; } diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-math.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-math.ll --- a/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-math.ll +++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-math.ll @@ -10,50 +10,6 @@ ; 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 diff --git a/llvm/test/CodeGen/PowerPC/fpscr-intrinsics.ll b/llvm/test/CodeGen/PowerPC/fpscr-intrinsics.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/fpscr-intrinsics.ll @@ -0,0 +1,121 @@ +; 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 +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix -mcpu=pwr7 \ +; RUN: < %s | FileCheck %s --check-prefix=CHECK-AIX64 +; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-aix -mcpu=pwr8 < %s | \ +; RUN: FileCheck %s --check-prefix=CHECK-AIX32 + +define dso_local void @mtfsb0() local_unnamed_addr #0 { +; CHECK-PWR8-LABEL: mtfsb0: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: mtfsb0 10 +; CHECK-PWR8-NEXT: blr +; +; CHECK-PWR7-LABEL: mtfsb0: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: mtfsb0 10 +; CHECK-PWR7-NEXT: blr +; CHECK-LABEL: mtfsb0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfsb0 10 +; CHECK-NEXT: blr +; +; CHECK-AIX64-LABEL: mtfsb0: +; CHECK-AIX64: # %bb.0: # %entry +; CHECK-AIX64-NEXT: mtfsb0 10 +; CHECK-AIX64-NEXT: blr +; +; CHECK-AIX32-LABEL: mtfsb0: +; CHECK-AIX32: # %bb.0: # %entry +; CHECK-AIX32-NEXT: mtfsb0 10 +; CHECK-AIX32-NEXT: blr +entry: + tail call void @llvm.ppc.mtfsb0(i32 10) + ret void +} + +define dso_local void @mtfsb1() local_unnamed_addr #0 { +; CHECK-PWR8-LABEL: mtfsb1: +; CHECK-PWR8: # %bb.0: # %entry +; CHECK-PWR8-NEXT: mtfsb1 0 +; CHECK-PWR8-NEXT: blr +; +; CHECK-PWR7-LABEL: mtfsb1: +; CHECK-PWR7: # %bb.0: # %entry +; CHECK-PWR7-NEXT: mtfsb1 0 +; CHECK-PWR7-NEXT: blr +; CHECK-LABEL: mtfsb1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfsb1 0 +; CHECK-NEXT: blr +; +; CHECK-AIX64-LABEL: mtfsb1: +; CHECK-AIX64: # %bb.0: # %entry +; CHECK-AIX64-NEXT: mtfsb1 0 +; CHECK-AIX64-NEXT: blr +; +; CHECK-AIX32-LABEL: mtfsb1: +; CHECK-AIX32: # %bb.0: # %entry +; CHECK-AIX32-NEXT: mtfsb1 0 +; CHECK-AIX32-NEXT: blr +entry: + tail call void @llvm.ppc.mtfsb1(i32 0) + ret void +} + +define dso_local void @callmtfsf(i32 zeroext %a) local_unnamed_addr { +; CHECK-LABEL: callmtfsf: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprwz 0, 3 +; CHECK-NEXT: xscvuxddp 0, 0 +; CHECK-NEXT: mtfsf 7, 0 +; CHECK-NEXT: blr +; +; CHECK-AIX64-LABEL: callmtfsf: +; CHECK-AIX64: # %bb.0: # %entry +; CHECK-AIX64-NEXT: addi 4, 1, -4 +; CHECK-AIX64-NEXT: stw 3, -4(1) +; CHECK-AIX64-NEXT: lfiwzx 0, 0, 4 +; CHECK-AIX64-NEXT: xscvuxddp 0, 0 +; CHECK-AIX64-NEXT: mtfsf 7, 0 +; CHECK-AIX64-NEXT: blr +; +; CHECK-AIX32-LABEL: callmtfsf: +; CHECK-AIX32: # %bb.0: # %entry +; CHECK-AIX32-NEXT: addi 4, 1, -4 +; CHECK-AIX32-NEXT: stw 3, -4(1) +; CHECK-AIX32-NEXT: lfiwzx 0, 0, 4 +; CHECK-AIX32-NEXT: xscvuxddp 0, 0 +; CHECK-AIX32-NEXT: mtfsf 7, 0 +; CHECK-AIX32-NEXT: blr +entry: + %0 = uitofp i32 %a to double + tail call void @llvm.ppc.mtfsf(i32 7, double %0) + ret void +} + +define dso_local void @callmtfsfi(i32 zeroext %a) local_unnamed_addr { +; CHECK-LABEL: callmtfsfi: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfsfi 1, 3 +; CHECK-NEXT: blr +; +; CHECK-AIX64-LABEL: callmtfsfi: +; CHECK-AIX64: # %bb.0: # %entry +; CHECK-AIX64-NEXT: mtfsfi 1, 3 +; CHECK-AIX64-NEXT: blr +; +; CHECK-AIX32-LABEL: callmtfsfi: +; CHECK-AIX32: # %bb.0: # %entry +; CHECK-AIX32-NEXT: mtfsfi 1, 3 +; CHECK-AIX32-NEXT: blr +entry: + tail call void @llvm.ppc.mtfsfi(i32 1, i32 3) + ret void +} + +declare void @llvm.ppc.mtfsb0(i32) +declare void @llvm.ppc.mtfsb1(i32) +declare void @llvm.ppc.mtfsfi(i32, i32) +declare void @llvm.ppc.mtfsf(i32, double)