1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ 3; RUN: | FileCheck -check-prefix=RV32I %s 4; RUN: llc -mtriple=riscv32 -target-abi ilp32 -mattr=+zfh -verify-machineinstrs \ 5; RUN: < %s | FileCheck -check-prefix=RV32IZFH %s 6; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ 7; RUN: | FileCheck -check-prefix=RV64I %s 8; RUN: llc -mtriple=riscv64 -target-abi lp64 -mattr=+zfh -verify-machineinstrs \ 9; RUN: < %s | FileCheck -check-prefix=RV64IZFH %s 10; RUN: llc -mtriple=riscv32 -target-abi ilp32 -mattr=+zhinx -verify-machineinstrs \ 11; RUN: < %s | FileCheck -check-prefix=RV32IZHINX %s 12; RUN: llc -mtriple=riscv64 -target-abi lp64 -mattr=+zhinx -verify-machineinstrs \ 13; RUN: < %s | FileCheck -check-prefix=RV64IZHINX %s 14; RUN: llc -mtriple=riscv32 -target-abi ilp32 -mattr=+zfhmin -verify-machineinstrs \ 15; RUN: < %s | FileCheck -check-prefix=RV32IZFHMIN %s 16; RUN: llc -mtriple=riscv64 -target-abi lp64 -verify-machineinstrs < %s \ 17; RUN: | FileCheck -check-prefix=RV64I %s 18; RUN: llc -mtriple=riscv64 -target-abi lp64 -mattr=+zfhmin -verify-machineinstrs \ 19; RUN: < %s | FileCheck -check-prefix=RV64IZFHMIN %s 20; RUN: llc -mtriple=riscv32 -target-abi ilp32 -mattr=+zhinxmin -verify-machineinstrs \ 21; RUN: < %s | FileCheck --check-prefixes=RVIZHINXMIN,RV32IZHINXMIN %s 22; RUN: llc -mtriple=riscv64 -target-abi lp64 -mattr=+zhinxmin -verify-machineinstrs \ 23; RUN: < %s | FileCheck --check-prefixes=RVIZHINXMIN,RV64IZHINXMIN %s 24 25; This file tests cases where simple floating point operations can be 26; profitably handled though bit manipulation if a soft-float ABI is being used 27; (e.g. fneg implemented by XORing the sign bit). This is typically handled in 28; DAGCombiner::visitBITCAST, but this target-independent code may not trigger 29; in cases where we perform custom legalisation (e.g. RV64F). 30 31define half @fneg(half %a) nounwind { 32; RV32I-LABEL: fneg: 33; RV32I: # %bb.0: 34; RV32I-NEXT: lui a1, 1048568 35; RV32I-NEXT: xor a0, a0, a1 36; RV32I-NEXT: ret 37; 38; RV32IZFH-LABEL: fneg: 39; RV32IZFH: # %bb.0: 40; RV32IZFH-NEXT: lui a1, 1048568 41; RV32IZFH-NEXT: xor a0, a0, a1 42; RV32IZFH-NEXT: ret 43; 44; RV64I-LABEL: fneg: 45; RV64I: # %bb.0: 46; RV64I-NEXT: lui a1, 1048568 47; RV64I-NEXT: xor a0, a0, a1 48; RV64I-NEXT: ret 49; 50; RV64IZFH-LABEL: fneg: 51; RV64IZFH: # %bb.0: 52; RV64IZFH-NEXT: lui a1, 1048568 53; RV64IZFH-NEXT: xor a0, a0, a1 54; RV64IZFH-NEXT: ret 55; 56; RV32IZHINX-LABEL: fneg: 57; RV32IZHINX: # %bb.0: 58; RV32IZHINX-NEXT: fneg.h a0, a0 59; RV32IZHINX-NEXT: ret 60; 61; RV64IZHINX-LABEL: fneg: 62; RV64IZHINX: # %bb.0: 63; RV64IZHINX-NEXT: fneg.h a0, a0 64; RV64IZHINX-NEXT: ret 65; 66; RV32IZFHMIN-LABEL: fneg: 67; RV32IZFHMIN: # %bb.0: 68; RV32IZFHMIN-NEXT: lui a1, 1048568 69; RV32IZFHMIN-NEXT: xor a0, a0, a1 70; RV32IZFHMIN-NEXT: ret 71; 72; RV64IZFHMIN-LABEL: fneg: 73; RV64IZFHMIN: # %bb.0: 74; RV64IZFHMIN-NEXT: lui a1, 1048568 75; RV64IZFHMIN-NEXT: xor a0, a0, a1 76; RV64IZFHMIN-NEXT: ret 77; 78; RVIZHINXMIN-LABEL: fneg: 79; RVIZHINXMIN: # %bb.0: 80; RVIZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 81; RVIZHINXMIN-NEXT: lui a1, 1048568 82; RVIZHINXMIN-NEXT: xor a0, a0, a1 83; RVIZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 84; RVIZHINXMIN-NEXT: ret 85 %1 = fneg half %a 86 ret half %1 87} 88 89declare half @llvm.fabs.f16(half) 90 91define half @fabs(half %a) nounwind { 92; RV32I-LABEL: fabs: 93; RV32I: # %bb.0: 94; RV32I-NEXT: slli a0, a0, 17 95; RV32I-NEXT: srli a0, a0, 17 96; RV32I-NEXT: ret 97; 98; RV32IZFH-LABEL: fabs: 99; RV32IZFH: # %bb.0: 100; RV32IZFH-NEXT: slli a0, a0, 17 101; RV32IZFH-NEXT: srli a0, a0, 17 102; RV32IZFH-NEXT: ret 103; 104; RV64I-LABEL: fabs: 105; RV64I: # %bb.0: 106; RV64I-NEXT: slli a0, a0, 49 107; RV64I-NEXT: srli a0, a0, 49 108; RV64I-NEXT: ret 109; 110; RV64IZFH-LABEL: fabs: 111; RV64IZFH: # %bb.0: 112; RV64IZFH-NEXT: slli a0, a0, 49 113; RV64IZFH-NEXT: srli a0, a0, 49 114; RV64IZFH-NEXT: ret 115; 116; RV32IZHINX-LABEL: fabs: 117; RV32IZHINX: # %bb.0: 118; RV32IZHINX-NEXT: fabs.h a0, a0 119; RV32IZHINX-NEXT: ret 120; 121; RV64IZHINX-LABEL: fabs: 122; RV64IZHINX: # %bb.0: 123; RV64IZHINX-NEXT: fabs.h a0, a0 124; RV64IZHINX-NEXT: ret 125; 126; RV32IZFHMIN-LABEL: fabs: 127; RV32IZFHMIN: # %bb.0: 128; RV32IZFHMIN-NEXT: slli a0, a0, 17 129; RV32IZFHMIN-NEXT: srli a0, a0, 17 130; RV32IZFHMIN-NEXT: ret 131; 132; RV64IZFHMIN-LABEL: fabs: 133; RV64IZFHMIN: # %bb.0: 134; RV64IZFHMIN-NEXT: slli a0, a0, 49 135; RV64IZFHMIN-NEXT: srli a0, a0, 49 136; RV64IZFHMIN-NEXT: ret 137; 138; RV32IZHINXMIN-LABEL: fabs: 139; RV32IZHINXMIN: # %bb.0: 140; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 141; RV32IZHINXMIN-NEXT: slli a0, a0, 17 142; RV32IZHINXMIN-NEXT: srli a0, a0, 17 143; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 144; RV32IZHINXMIN-NEXT: ret 145; 146; RV64IZHINXMIN-LABEL: fabs: 147; RV64IZHINXMIN: # %bb.0: 148; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 149; RV64IZHINXMIN-NEXT: slli a0, a0, 49 150; RV64IZHINXMIN-NEXT: srli a0, a0, 49 151; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 152; RV64IZHINXMIN-NEXT: ret 153 %1 = call half @llvm.fabs.f16(half %a) 154 ret half %1 155} 156 157declare half @llvm.copysign.f16(half, half) 158 159; DAGTypeLegalizer::SoftenFloatRes_FCOPYSIGN will convert to bitwise 160; operations if half precision floating point isn't supported. A combine could 161; be written to do the same even when f16 is legal. 162 163define half @fcopysign_fneg(half %a, half %b) nounwind { 164; RV32I-LABEL: fcopysign_fneg: 165; RV32I: # %bb.0: 166; RV32I-NEXT: not a1, a1 167; RV32I-NEXT: lui a2, 1048568 168; RV32I-NEXT: slli a0, a0, 17 169; RV32I-NEXT: and a1, a1, a2 170; RV32I-NEXT: srli a0, a0, 17 171; RV32I-NEXT: or a0, a0, a1 172; RV32I-NEXT: ret 173; 174; RV32IZFH-LABEL: fcopysign_fneg: 175; RV32IZFH: # %bb.0: 176; RV32IZFH-NEXT: fmv.h.x fa5, a1 177; RV32IZFH-NEXT: fmv.h.x fa4, a0 178; RV32IZFH-NEXT: fsgnjn.h fa5, fa4, fa5 179; RV32IZFH-NEXT: fmv.x.h a0, fa5 180; RV32IZFH-NEXT: ret 181; 182; RV64I-LABEL: fcopysign_fneg: 183; RV64I: # %bb.0: 184; RV64I-NEXT: not a1, a1 185; RV64I-NEXT: lui a2, 1048568 186; RV64I-NEXT: slli a0, a0, 49 187; RV64I-NEXT: and a1, a1, a2 188; RV64I-NEXT: srli a0, a0, 49 189; RV64I-NEXT: or a0, a0, a1 190; RV64I-NEXT: ret 191; 192; RV64IZFH-LABEL: fcopysign_fneg: 193; RV64IZFH: # %bb.0: 194; RV64IZFH-NEXT: fmv.h.x fa5, a1 195; RV64IZFH-NEXT: fmv.h.x fa4, a0 196; RV64IZFH-NEXT: fsgnjn.h fa5, fa4, fa5 197; RV64IZFH-NEXT: fmv.x.h a0, fa5 198; RV64IZFH-NEXT: ret 199; 200; RV32IZHINX-LABEL: fcopysign_fneg: 201; RV32IZHINX: # %bb.0: 202; RV32IZHINX-NEXT: fsgnjn.h a0, a0, a1 203; RV32IZHINX-NEXT: ret 204; 205; RV64IZHINX-LABEL: fcopysign_fneg: 206; RV64IZHINX: # %bb.0: 207; RV64IZHINX-NEXT: fsgnjn.h a0, a0, a1 208; RV64IZHINX-NEXT: ret 209; 210; RV32IZFHMIN-LABEL: fcopysign_fneg: 211; RV32IZFHMIN: # %bb.0: 212; RV32IZFHMIN-NEXT: not a1, a1 213; RV32IZFHMIN-NEXT: lui a2, 1048568 214; RV32IZFHMIN-NEXT: slli a0, a0, 17 215; RV32IZFHMIN-NEXT: and a1, a1, a2 216; RV32IZFHMIN-NEXT: srli a0, a0, 17 217; RV32IZFHMIN-NEXT: or a0, a0, a1 218; RV32IZFHMIN-NEXT: ret 219; 220; RV64IZFHMIN-LABEL: fcopysign_fneg: 221; RV64IZFHMIN: # %bb.0: 222; RV64IZFHMIN-NEXT: not a1, a1 223; RV64IZFHMIN-NEXT: lui a2, 1048568 224; RV64IZFHMIN-NEXT: slli a0, a0, 49 225; RV64IZFHMIN-NEXT: and a1, a1, a2 226; RV64IZFHMIN-NEXT: srli a0, a0, 49 227; RV64IZFHMIN-NEXT: or a0, a0, a1 228; RV64IZFHMIN-NEXT: ret 229; 230; RV32IZHINXMIN-LABEL: fcopysign_fneg: 231; RV32IZHINXMIN: # %bb.0: 232; RV32IZHINXMIN-NEXT: # kill: def $x11_h killed $x11_h def $x11 233; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 234; RV32IZHINXMIN-NEXT: not a1, a1 235; RV32IZHINXMIN-NEXT: lui a2, 1048568 236; RV32IZHINXMIN-NEXT: slli a0, a0, 17 237; RV32IZHINXMIN-NEXT: and a1, a1, a2 238; RV32IZHINXMIN-NEXT: srli a0, a0, 17 239; RV32IZHINXMIN-NEXT: or a0, a0, a1 240; RV32IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 241; RV32IZHINXMIN-NEXT: ret 242; 243; RV64IZHINXMIN-LABEL: fcopysign_fneg: 244; RV64IZHINXMIN: # %bb.0: 245; RV64IZHINXMIN-NEXT: # kill: def $x11_h killed $x11_h def $x11 246; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h def $x10 247; RV64IZHINXMIN-NEXT: not a1, a1 248; RV64IZHINXMIN-NEXT: lui a2, 1048568 249; RV64IZHINXMIN-NEXT: slli a0, a0, 49 250; RV64IZHINXMIN-NEXT: and a1, a1, a2 251; RV64IZHINXMIN-NEXT: srli a0, a0, 49 252; RV64IZHINXMIN-NEXT: or a0, a0, a1 253; RV64IZHINXMIN-NEXT: # kill: def $x10_h killed $x10_h killed $x10 254; RV64IZHINXMIN-NEXT: ret 255 %1 = fneg half %b 256 %2 = call half @llvm.copysign.f16(half %a, half %1) 257 ret half %2 258} 259