19250 lines · cpp
1//===-- SIISelLowering.cpp - SI DAG Lowering Implementation ---------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9/// \file10/// Custom DAG lowering for SI11//12//===----------------------------------------------------------------------===//13 14#include "SIISelLowering.h"15#include "AMDGPU.h"16#include "AMDGPUInstrInfo.h"17#include "AMDGPULaneMaskUtils.h"18#include "AMDGPUSelectionDAGInfo.h"19#include "AMDGPUTargetMachine.h"20#include "GCNSubtarget.h"21#include "MCTargetDesc/AMDGPUMCTargetDesc.h"22#include "SIMachineFunctionInfo.h"23#include "SIRegisterInfo.h"24#include "llvm/ADT/APInt.h"25#include "llvm/ADT/FloatingPointMode.h"26#include "llvm/ADT/Statistic.h"27#include "llvm/Analysis/OptimizationRemarkEmitter.h"28#include "llvm/Analysis/UniformityAnalysis.h"29#include "llvm/CodeGen/Analysis.h"30#include "llvm/CodeGen/ByteProvider.h"31#include "llvm/CodeGen/FunctionLoweringInfo.h"32#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h"33#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"34#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"35#include "llvm/CodeGen/MachineFrameInfo.h"36#include "llvm/CodeGen/MachineFunction.h"37#include "llvm/CodeGen/MachineLoopInfo.h"38#include "llvm/CodeGen/SDPatternMatch.h"39#include "llvm/IR/DiagnosticInfo.h"40#include "llvm/IR/IRBuilder.h"41#include "llvm/IR/IntrinsicInst.h"42#include "llvm/IR/IntrinsicsAMDGPU.h"43#include "llvm/IR/IntrinsicsR600.h"44#include "llvm/IR/MDBuilder.h"45#include "llvm/Support/CommandLine.h"46#include "llvm/Support/KnownBits.h"47#include "llvm/Support/ModRef.h"48#include "llvm/Transforms/Utils/LowerAtomic.h"49#include <optional>50 51using namespace llvm;52using namespace llvm::SDPatternMatch;53 54#define DEBUG_TYPE "si-lower"55 56STATISTIC(NumTailCalls, "Number of tail calls");57 58static cl::opt<bool>59 DisableLoopAlignment("amdgpu-disable-loop-alignment",60 cl::desc("Do not align and prefetch loops"),61 cl::init(false));62 63static cl::opt<bool> UseDivergentRegisterIndexing(64 "amdgpu-use-divergent-register-indexing", cl::Hidden,65 cl::desc("Use indirect register addressing for divergent indexes"),66 cl::init(false));67 68static bool denormalModeIsFlushAllF32(const MachineFunction &MF) {69 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();70 return Info->getMode().FP32Denormals == DenormalMode::getPreserveSign();71}72 73static bool denormalModeIsFlushAllF64F16(const MachineFunction &MF) {74 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();75 return Info->getMode().FP64FP16Denormals == DenormalMode::getPreserveSign();76}77 78static unsigned findFirstFreeSGPR(CCState &CCInfo) {79 unsigned NumSGPRs = AMDGPU::SGPR_32RegClass.getNumRegs();80 for (unsigned Reg = 0; Reg < NumSGPRs; ++Reg) {81 if (!CCInfo.isAllocated(AMDGPU::SGPR0 + Reg)) {82 return AMDGPU::SGPR0 + Reg;83 }84 }85 llvm_unreachable("Cannot allocate sgpr");86}87 88SITargetLowering::SITargetLowering(const TargetMachine &TM,89 const GCNSubtarget &STI)90 : AMDGPUTargetLowering(TM, STI, STI), Subtarget(&STI) {91 addRegisterClass(MVT::i1, &AMDGPU::VReg_1RegClass);92 addRegisterClass(MVT::i64, &AMDGPU::SReg_64RegClass);93 94 addRegisterClass(MVT::i32, &AMDGPU::SReg_32RegClass);95 96 const SIRegisterInfo *TRI = STI.getRegisterInfo();97 const TargetRegisterClass *V32RegClass =98 TRI->getDefaultVectorSuperClassForBitWidth(32);99 addRegisterClass(MVT::f32, V32RegClass);100 101 addRegisterClass(MVT::v2i32, &AMDGPU::SReg_64RegClass);102 103 const TargetRegisterClass *V64RegClass =104 TRI->getDefaultVectorSuperClassForBitWidth(64);105 106 addRegisterClass(MVT::f64, V64RegClass);107 addRegisterClass(MVT::v2f32, V64RegClass);108 addRegisterClass(MVT::Untyped, V64RegClass);109 110 addRegisterClass(MVT::v3i32, &AMDGPU::SGPR_96RegClass);111 addRegisterClass(MVT::v3f32, TRI->getDefaultVectorSuperClassForBitWidth(96));112 113 addRegisterClass(MVT::v2i64, &AMDGPU::SGPR_128RegClass);114 addRegisterClass(MVT::v2f64, &AMDGPU::SGPR_128RegClass);115 116 addRegisterClass(MVT::v4i32, &AMDGPU::SGPR_128RegClass);117 addRegisterClass(MVT::v4f32, TRI->getDefaultVectorSuperClassForBitWidth(128));118 119 addRegisterClass(MVT::v5i32, &AMDGPU::SGPR_160RegClass);120 addRegisterClass(MVT::v5f32, TRI->getDefaultVectorSuperClassForBitWidth(160));121 122 addRegisterClass(MVT::v6i32, &AMDGPU::SGPR_192RegClass);123 addRegisterClass(MVT::v6f32, TRI->getDefaultVectorSuperClassForBitWidth(192));124 125 addRegisterClass(MVT::v3i64, &AMDGPU::SGPR_192RegClass);126 addRegisterClass(MVT::v3f64, TRI->getDefaultVectorSuperClassForBitWidth(192));127 128 addRegisterClass(MVT::v7i32, &AMDGPU::SGPR_224RegClass);129 addRegisterClass(MVT::v7f32, TRI->getDefaultVectorSuperClassForBitWidth(224));130 131 addRegisterClass(MVT::v8i32, &AMDGPU::SGPR_256RegClass);132 addRegisterClass(MVT::v8f32, TRI->getDefaultVectorSuperClassForBitWidth(256));133 134 addRegisterClass(MVT::v4i64, &AMDGPU::SGPR_256RegClass);135 addRegisterClass(MVT::v4f64, TRI->getDefaultVectorSuperClassForBitWidth(256));136 137 addRegisterClass(MVT::v9i32, &AMDGPU::SGPR_288RegClass);138 addRegisterClass(MVT::v9f32, TRI->getDefaultVectorSuperClassForBitWidth(288));139 140 addRegisterClass(MVT::v10i32, &AMDGPU::SGPR_320RegClass);141 addRegisterClass(MVT::v10f32,142 TRI->getDefaultVectorSuperClassForBitWidth(320));143 144 addRegisterClass(MVT::v11i32, &AMDGPU::SGPR_352RegClass);145 addRegisterClass(MVT::v11f32,146 TRI->getDefaultVectorSuperClassForBitWidth(352));147 148 addRegisterClass(MVT::v12i32, &AMDGPU::SGPR_384RegClass);149 addRegisterClass(MVT::v12f32,150 TRI->getDefaultVectorSuperClassForBitWidth(384));151 152 addRegisterClass(MVT::v16i32, &AMDGPU::SGPR_512RegClass);153 addRegisterClass(MVT::v16f32,154 TRI->getDefaultVectorSuperClassForBitWidth(512));155 156 addRegisterClass(MVT::v8i64, &AMDGPU::SGPR_512RegClass);157 addRegisterClass(MVT::v8f64, TRI->getDefaultVectorSuperClassForBitWidth(512));158 159 addRegisterClass(MVT::v16i64, &AMDGPU::SGPR_1024RegClass);160 addRegisterClass(MVT::v16f64,161 TRI->getDefaultVectorSuperClassForBitWidth(1024));162 163 if (Subtarget->has16BitInsts()) {164 if (Subtarget->useRealTrue16Insts()) {165 addRegisterClass(MVT::i16, &AMDGPU::VGPR_16RegClass);166 addRegisterClass(MVT::f16, &AMDGPU::VGPR_16RegClass);167 addRegisterClass(MVT::bf16, &AMDGPU::VGPR_16RegClass);168 } else {169 addRegisterClass(MVT::i16, &AMDGPU::SReg_32RegClass);170 addRegisterClass(MVT::f16, &AMDGPU::SReg_32RegClass);171 addRegisterClass(MVT::bf16, &AMDGPU::SReg_32RegClass);172 }173 174 // Unless there are also VOP3P operations, not operations are really legal.175 addRegisterClass(MVT::v2i16, &AMDGPU::SReg_32RegClass);176 addRegisterClass(MVT::v2f16, &AMDGPU::SReg_32RegClass);177 addRegisterClass(MVT::v2bf16, &AMDGPU::SReg_32RegClass);178 addRegisterClass(MVT::v4i16, &AMDGPU::SReg_64RegClass);179 addRegisterClass(MVT::v4f16, &AMDGPU::SReg_64RegClass);180 addRegisterClass(MVT::v4bf16, &AMDGPU::SReg_64RegClass);181 addRegisterClass(MVT::v8i16, &AMDGPU::SGPR_128RegClass);182 addRegisterClass(MVT::v8f16, &AMDGPU::SGPR_128RegClass);183 addRegisterClass(MVT::v8bf16, &AMDGPU::SGPR_128RegClass);184 addRegisterClass(MVT::v16i16, &AMDGPU::SGPR_256RegClass);185 addRegisterClass(MVT::v16f16, &AMDGPU::SGPR_256RegClass);186 addRegisterClass(MVT::v16bf16, &AMDGPU::SGPR_256RegClass);187 addRegisterClass(MVT::v32i16, &AMDGPU::SGPR_512RegClass);188 addRegisterClass(MVT::v32f16, &AMDGPU::SGPR_512RegClass);189 addRegisterClass(MVT::v32bf16, &AMDGPU::SGPR_512RegClass);190 }191 192 addRegisterClass(MVT::v32i32, &AMDGPU::VReg_1024RegClass);193 addRegisterClass(MVT::v32f32,194 TRI->getDefaultVectorSuperClassForBitWidth(1024));195 196 computeRegisterProperties(Subtarget->getRegisterInfo());197 198 // The boolean content concept here is too inflexible. Compares only ever199 // really produce a 1-bit result. Any copy/extend from these will turn into a200 // select, and zext/1 or sext/-1 are equally cheap. Arbitrarily choose 0/1, as201 // it's what most targets use.202 setBooleanContents(ZeroOrOneBooleanContent);203 setBooleanVectorContents(ZeroOrOneBooleanContent);204 205 // We need to custom lower vector stores from local memory206 setOperationAction(ISD::LOAD,207 {MVT::v2i32, MVT::v3i32, MVT::v4i32, MVT::v5i32,208 MVT::v6i32, MVT::v7i32, MVT::v8i32, MVT::v9i32,209 MVT::v10i32, MVT::v11i32, MVT::v12i32, MVT::v16i32,210 MVT::i1, MVT::v32i32},211 Custom);212 213 setOperationAction(ISD::STORE,214 {MVT::v2i32, MVT::v3i32, MVT::v4i32, MVT::v5i32,215 MVT::v6i32, MVT::v7i32, MVT::v8i32, MVT::v9i32,216 MVT::v10i32, MVT::v11i32, MVT::v12i32, MVT::v16i32,217 MVT::i1, MVT::v32i32},218 Custom);219 220 if (isTypeLegal(MVT::bf16)) {221 for (unsigned Opc :222 {ISD::FADD, ISD::FSUB, ISD::FMUL, ISD::FDIV,223 ISD::FREM, ISD::FMA, ISD::FMINNUM, ISD::FMAXNUM,224 ISD::FMINIMUM, ISD::FMAXIMUM, ISD::FSQRT, ISD::FCBRT,225 ISD::FSIN, ISD::FCOS, ISD::FPOW, ISD::FPOWI,226 ISD::FLDEXP, ISD::FFREXP, ISD::FLOG, ISD::FLOG2,227 ISD::FLOG10, ISD::FEXP, ISD::FEXP2, ISD::FEXP10,228 ISD::FCEIL, ISD::FTRUNC, ISD::FRINT, ISD::FNEARBYINT,229 ISD::FROUND, ISD::FROUNDEVEN, ISD::FFLOOR, ISD::FCANONICALIZE,230 ISD::SETCC}) {231 // FIXME: The promoted to type shouldn't need to be explicit232 setOperationAction(Opc, MVT::bf16, Promote);233 AddPromotedToType(Opc, MVT::bf16, MVT::f32);234 }235 236 setOperationAction(ISD::FP_ROUND, MVT::bf16, Expand);237 238 setOperationAction(ISD::SELECT, MVT::bf16, Promote);239 AddPromotedToType(ISD::SELECT, MVT::bf16, MVT::i16);240 241 setOperationAction(ISD::FABS, MVT::bf16, Legal);242 setOperationAction(ISD::FNEG, MVT::bf16, Legal);243 setOperationAction(ISD::FCOPYSIGN, MVT::bf16, Legal);244 245 // We only need to custom lower because we can't specify an action for bf16246 // sources.247 setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);248 setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);249 }250 251 setTruncStoreAction(MVT::v2i32, MVT::v2i16, Expand);252 setTruncStoreAction(MVT::v3i32, MVT::v3i16, Expand);253 setTruncStoreAction(MVT::v4i32, MVT::v4i16, Expand);254 setTruncStoreAction(MVT::v8i32, MVT::v8i16, Expand);255 setTruncStoreAction(MVT::v16i32, MVT::v16i16, Expand);256 setTruncStoreAction(MVT::v32i32, MVT::v32i16, Expand);257 setTruncStoreAction(MVT::v2i32, MVT::v2i8, Expand);258 setTruncStoreAction(MVT::v4i32, MVT::v4i8, Expand);259 setTruncStoreAction(MVT::v8i32, MVT::v8i8, Expand);260 setTruncStoreAction(MVT::v16i32, MVT::v16i8, Expand);261 setTruncStoreAction(MVT::v32i32, MVT::v32i8, Expand);262 setTruncStoreAction(MVT::v2i16, MVT::v2i8, Expand);263 setTruncStoreAction(MVT::v4i16, MVT::v4i8, Expand);264 setTruncStoreAction(MVT::v8i16, MVT::v8i8, Expand);265 setTruncStoreAction(MVT::v16i16, MVT::v16i8, Expand);266 setTruncStoreAction(MVT::v32i16, MVT::v32i8, Expand);267 268 setTruncStoreAction(MVT::v3i64, MVT::v3i16, Expand);269 setTruncStoreAction(MVT::v3i64, MVT::v3i32, Expand);270 setTruncStoreAction(MVT::v4i64, MVT::v4i8, Expand);271 setTruncStoreAction(MVT::v8i64, MVT::v8i8, Expand);272 setTruncStoreAction(MVT::v8i64, MVT::v8i16, Expand);273 setTruncStoreAction(MVT::v8i64, MVT::v8i32, Expand);274 setTruncStoreAction(MVT::v16i64, MVT::v16i32, Expand);275 276 setOperationAction(ISD::GlobalAddress, {MVT::i32, MVT::i64}, Custom);277 278 setOperationAction(ISD::SELECT, MVT::i1, Promote);279 setOperationAction(ISD::SELECT, MVT::i64, Custom);280 setOperationAction(ISD::SELECT, MVT::f64, Promote);281 AddPromotedToType(ISD::SELECT, MVT::f64, MVT::i64);282 283 setOperationAction(ISD::FSQRT, {MVT::f32, MVT::f64}, Custom);284 285 setOperationAction(ISD::SELECT_CC,286 {MVT::f32, MVT::i32, MVT::i64, MVT::f64, MVT::i1}, Expand);287 288 setOperationAction(ISD::SETCC, MVT::i1, Promote);289 setOperationAction(ISD::SETCC, {MVT::v2i1, MVT::v4i1}, Expand);290 AddPromotedToType(ISD::SETCC, MVT::i1, MVT::i32);291 292 setOperationAction(ISD::TRUNCATE,293 {MVT::v2i32, MVT::v3i32, MVT::v4i32, MVT::v5i32,294 MVT::v6i32, MVT::v7i32, MVT::v8i32, MVT::v9i32,295 MVT::v10i32, MVT::v11i32, MVT::v12i32, MVT::v16i32},296 Expand);297 setOperationAction(ISD::FP_ROUND,298 {MVT::v2f32, MVT::v3f32, MVT::v4f32, MVT::v5f32,299 MVT::v6f32, MVT::v7f32, MVT::v8f32, MVT::v9f32,300 MVT::v10f32, MVT::v11f32, MVT::v12f32, MVT::v16f32},301 Expand);302 303 setOperationAction(ISD::SIGN_EXTEND_INREG,304 {MVT::v2i1, MVT::v4i1, MVT::v2i8, MVT::v4i8, MVT::v2i16,305 MVT::v3i16, MVT::v4i16, MVT::Other},306 Custom);307 308 setOperationAction(ISD::BRCOND, MVT::Other, Custom);309 setOperationAction(ISD::BR_CC,310 {MVT::i1, MVT::i32, MVT::i64, MVT::f32, MVT::f64}, Expand);311 312 setOperationAction({ISD::ABS, ISD::UADDO, ISD::USUBO}, MVT::i32, Legal);313 314 setOperationAction({ISD::UADDO_CARRY, ISD::USUBO_CARRY}, MVT::i32, Legal);315 316 setOperationAction({ISD::SHL_PARTS, ISD::SRA_PARTS, ISD::SRL_PARTS}, MVT::i64,317 Expand);318 319#if 0320 setOperationAction({ISD::UADDO_CARRY, ISD::USUBO_CARRY}, MVT::i64, Legal);321#endif322 323 // We only support LOAD/STORE and vector manipulation ops for vectors324 // with > 4 elements.325 for (MVT VT :326 {MVT::v8i32, MVT::v8f32, MVT::v9i32, MVT::v9f32, MVT::v10i32,327 MVT::v10f32, MVT::v11i32, MVT::v11f32, MVT::v12i32, MVT::v12f32,328 MVT::v16i32, MVT::v16f32, MVT::v2i64, MVT::v2f64, MVT::v4i16,329 MVT::v4f16, MVT::v4bf16, MVT::v3i64, MVT::v3f64, MVT::v6i32,330 MVT::v6f32, MVT::v4i64, MVT::v4f64, MVT::v8i64, MVT::v8f64,331 MVT::v8i16, MVT::v8f16, MVT::v8bf16, MVT::v16i16, MVT::v16f16,332 MVT::v16bf16, MVT::v16i64, MVT::v16f64, MVT::v32i32, MVT::v32f32,333 MVT::v32i16, MVT::v32f16, MVT::v32bf16}) {334 for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op) {335 switch (Op) {336 case ISD::LOAD:337 case ISD::STORE:338 case ISD::BUILD_VECTOR:339 case ISD::BITCAST:340 case ISD::UNDEF:341 case ISD::EXTRACT_VECTOR_ELT:342 case ISD::INSERT_VECTOR_ELT:343 case ISD::SCALAR_TO_VECTOR:344 case ISD::IS_FPCLASS:345 break;346 case ISD::EXTRACT_SUBVECTOR:347 case ISD::INSERT_SUBVECTOR:348 case ISD::CONCAT_VECTORS:349 setOperationAction(Op, VT, Custom);350 break;351 default:352 setOperationAction(Op, VT, Expand);353 break;354 }355 }356 }357 358 setOperationAction(ISD::FP_EXTEND, MVT::v4f32, Expand);359 360 // TODO: For dynamic 64-bit vector inserts/extracts, should emit a pseudo that361 // is expanded to avoid having two separate loops in case the index is a VGPR.362 363 // Most operations are naturally 32-bit vector operations. We only support364 // load and store of i64 vectors, so promote v2i64 vector operations to v4i32.365 for (MVT Vec64 : {MVT::v2i64, MVT::v2f64}) {366 setOperationAction(ISD::BUILD_VECTOR, Vec64, Promote);367 AddPromotedToType(ISD::BUILD_VECTOR, Vec64, MVT::v4i32);368 369 setOperationAction(ISD::EXTRACT_VECTOR_ELT, Vec64, Promote);370 AddPromotedToType(ISD::EXTRACT_VECTOR_ELT, Vec64, MVT::v4i32);371 372 setOperationAction(ISD::INSERT_VECTOR_ELT, Vec64, Promote);373 AddPromotedToType(ISD::INSERT_VECTOR_ELT, Vec64, MVT::v4i32);374 375 setOperationAction(ISD::SCALAR_TO_VECTOR, Vec64, Promote);376 AddPromotedToType(ISD::SCALAR_TO_VECTOR, Vec64, MVT::v4i32);377 }378 379 for (MVT Vec64 : {MVT::v3i64, MVT::v3f64}) {380 setOperationAction(ISD::BUILD_VECTOR, Vec64, Promote);381 AddPromotedToType(ISD::BUILD_VECTOR, Vec64, MVT::v6i32);382 383 setOperationAction(ISD::EXTRACT_VECTOR_ELT, Vec64, Promote);384 AddPromotedToType(ISD::EXTRACT_VECTOR_ELT, Vec64, MVT::v6i32);385 386 setOperationAction(ISD::INSERT_VECTOR_ELT, Vec64, Promote);387 AddPromotedToType(ISD::INSERT_VECTOR_ELT, Vec64, MVT::v6i32);388 389 setOperationAction(ISD::SCALAR_TO_VECTOR, Vec64, Promote);390 AddPromotedToType(ISD::SCALAR_TO_VECTOR, Vec64, MVT::v6i32);391 }392 393 for (MVT Vec64 : {MVT::v4i64, MVT::v4f64}) {394 setOperationAction(ISD::BUILD_VECTOR, Vec64, Promote);395 AddPromotedToType(ISD::BUILD_VECTOR, Vec64, MVT::v8i32);396 397 setOperationAction(ISD::EXTRACT_VECTOR_ELT, Vec64, Promote);398 AddPromotedToType(ISD::EXTRACT_VECTOR_ELT, Vec64, MVT::v8i32);399 400 setOperationAction(ISD::INSERT_VECTOR_ELT, Vec64, Promote);401 AddPromotedToType(ISD::INSERT_VECTOR_ELT, Vec64, MVT::v8i32);402 403 setOperationAction(ISD::SCALAR_TO_VECTOR, Vec64, Promote);404 AddPromotedToType(ISD::SCALAR_TO_VECTOR, Vec64, MVT::v8i32);405 }406 407 for (MVT Vec64 : {MVT::v8i64, MVT::v8f64}) {408 setOperationAction(ISD::BUILD_VECTOR, Vec64, Promote);409 AddPromotedToType(ISD::BUILD_VECTOR, Vec64, MVT::v16i32);410 411 setOperationAction(ISD::EXTRACT_VECTOR_ELT, Vec64, Promote);412 AddPromotedToType(ISD::EXTRACT_VECTOR_ELT, Vec64, MVT::v16i32);413 414 setOperationAction(ISD::INSERT_VECTOR_ELT, Vec64, Promote);415 AddPromotedToType(ISD::INSERT_VECTOR_ELT, Vec64, MVT::v16i32);416 417 setOperationAction(ISD::SCALAR_TO_VECTOR, Vec64, Promote);418 AddPromotedToType(ISD::SCALAR_TO_VECTOR, Vec64, MVT::v16i32);419 }420 421 for (MVT Vec64 : {MVT::v16i64, MVT::v16f64}) {422 setOperationAction(ISD::BUILD_VECTOR, Vec64, Promote);423 AddPromotedToType(ISD::BUILD_VECTOR, Vec64, MVT::v32i32);424 425 setOperationAction(ISD::EXTRACT_VECTOR_ELT, Vec64, Promote);426 AddPromotedToType(ISD::EXTRACT_VECTOR_ELT, Vec64, MVT::v32i32);427 428 setOperationAction(ISD::INSERT_VECTOR_ELT, Vec64, Promote);429 AddPromotedToType(ISD::INSERT_VECTOR_ELT, Vec64, MVT::v32i32);430 431 setOperationAction(ISD::SCALAR_TO_VECTOR, Vec64, Promote);432 AddPromotedToType(ISD::SCALAR_TO_VECTOR, Vec64, MVT::v32i32);433 }434 435 setOperationAction(ISD::VECTOR_SHUFFLE,436 {MVT::v4i32, MVT::v4f32, MVT::v8i32, MVT::v8f32,437 MVT::v16i32, MVT::v16f32, MVT::v32i32, MVT::v32f32},438 Custom);439 440 if (Subtarget->hasPkMovB32()) {441 // TODO: 16-bit element vectors should be legal with even aligned elements.442 // TODO: Can be legal with wider source types than the result with443 // subregister extracts.444 setOperationAction(ISD::VECTOR_SHUFFLE, {MVT::v2i32, MVT::v2f32}, Legal);445 }446 447 setOperationAction({ISD::AND, ISD::OR, ISD::XOR}, MVT::v2i32, Legal);448 // Prevent SELECT v2i32 from being implemented with the above bitwise ops and449 // instead lower to cndmask in SITargetLowering::LowerSELECT().450 setOperationAction(ISD::SELECT, MVT::v2i32, Custom);451 // Enable MatchRotate to produce ISD::ROTR, which is later transformed to452 // alignbit.453 setOperationAction(ISD::ROTR, MVT::v2i32, Custom);454 455 setOperationAction(ISD::BUILD_VECTOR, {MVT::v4f16, MVT::v4i16, MVT::v4bf16},456 Custom);457 458 // Avoid stack access for these.459 // TODO: Generalize to more vector types.460 setOperationAction({ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT},461 {MVT::v2i16, MVT::v2f16, MVT::v2bf16, MVT::v2i8, MVT::v4i8,462 MVT::v8i8, MVT::v4i16, MVT::v4f16, MVT::v4bf16},463 Custom);464 465 // Deal with vec3 vector operations when widened to vec4.466 setOperationAction(ISD::INSERT_SUBVECTOR,467 {MVT::v3i32, MVT::v3f32, MVT::v4i32, MVT::v4f32}, Custom);468 469 // Deal with vec5/6/7 vector operations when widened to vec8.470 setOperationAction(ISD::INSERT_SUBVECTOR,471 {MVT::v5i32, MVT::v5f32, MVT::v6i32, MVT::v6f32,472 MVT::v7i32, MVT::v7f32, MVT::v8i32, MVT::v8f32,473 MVT::v9i32, MVT::v9f32, MVT::v10i32, MVT::v10f32,474 MVT::v11i32, MVT::v11f32, MVT::v12i32, MVT::v12f32},475 Custom);476 477 // BUFFER/FLAT_ATOMIC_CMP_SWAP on GCN GPUs needs input marshalling,478 // and output demarshalling479 setOperationAction(ISD::ATOMIC_CMP_SWAP, {MVT::i32, MVT::i64}, Custom);480 481 // We can't return success/failure, only the old value,482 // let LLVM add the comparison483 setOperationAction(ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, {MVT::i32, MVT::i64},484 Expand);485 486 setOperationAction(ISD::ADDRSPACECAST, {MVT::i32, MVT::i64}, Custom);487 488 setOperationAction(ISD::BITREVERSE, {MVT::i32, MVT::i64}, Legal);489 490 // FIXME: This should be narrowed to i32, but that only happens if i64 is491 // illegal.492 // FIXME: Should lower sub-i32 bswaps to bit-ops without v_perm_b32.493 setOperationAction(ISD::BSWAP, {MVT::i64, MVT::i32}, Legal);494 495 // On SI this is s_memtime and s_memrealtime on VI.496 setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Legal);497 498 if (Subtarget->hasSMemRealTime() ||499 Subtarget->getGeneration() >= AMDGPUSubtarget::GFX11)500 setOperationAction(ISD::READSTEADYCOUNTER, MVT::i64, Legal);501 setOperationAction({ISD::TRAP, ISD::DEBUGTRAP}, MVT::Other, Custom);502 503 if (Subtarget->has16BitInsts()) {504 setOperationAction({ISD::FPOW, ISD::FPOWI}, MVT::f16, Promote);505 setOperationAction({ISD::FLOG, ISD::FEXP, ISD::FLOG10}, MVT::f16, Custom);506 } else {507 setOperationAction(ISD::FSQRT, MVT::f16, Custom);508 }509 510 if (Subtarget->hasMadMacF32Insts())511 setOperationAction(ISD::FMAD, MVT::f32, Legal);512 513 if (!Subtarget->hasBFI())514 // fcopysign can be done in a single instruction with BFI.515 setOperationAction(ISD::FCOPYSIGN, {MVT::f32, MVT::f64}, Expand);516 517 if (!Subtarget->hasBCNT(32))518 setOperationAction(ISD::CTPOP, MVT::i32, Expand);519 520 if (!Subtarget->hasBCNT(64))521 setOperationAction(ISD::CTPOP, MVT::i64, Expand);522 523 if (Subtarget->hasFFBH())524 setOperationAction({ISD::CTLZ, ISD::CTLZ_ZERO_UNDEF}, MVT::i32, Custom);525 526 if (Subtarget->hasFFBL())527 setOperationAction({ISD::CTTZ, ISD::CTTZ_ZERO_UNDEF}, MVT::i32, Custom);528 529 // We only really have 32-bit BFE instructions (and 16-bit on VI).530 //531 // On SI+ there are 64-bit BFEs, but they are scalar only and there isn't any532 // effort to match them now. We want this to be false for i64 cases when the533 // extraction isn't restricted to the upper or lower half. Ideally we would534 // have some pass reduce 64-bit extracts to 32-bit if possible. Extracts that535 // span the midpoint are probably relatively rare, so don't worry about them536 // for now.537 if (Subtarget->hasBFE())538 setHasExtractBitsInsn(true);539 540 // Clamp modifier on add/sub541 if (Subtarget->hasIntClamp())542 setOperationAction({ISD::UADDSAT, ISD::USUBSAT}, MVT::i32, Legal);543 544 if (Subtarget->hasAddNoCarry())545 setOperationAction({ISD::SADDSAT, ISD::SSUBSAT}, {MVT::i16, MVT::i32},546 Legal);547 548 setOperationAction(549 {ISD::FMINNUM, ISD::FMAXNUM, ISD::FMINIMUMNUM, ISD::FMAXIMUMNUM},550 {MVT::f32, MVT::f64}, Custom);551 552 // These are really only legal for ieee_mode functions. We should be avoiding553 // them for functions that don't have ieee_mode enabled, so just say they are554 // legal.555 setOperationAction({ISD::FMINNUM_IEEE, ISD::FMAXNUM_IEEE},556 {MVT::f32, MVT::f64}, Legal);557 558 if (Subtarget->haveRoundOpsF64())559 setOperationAction({ISD::FTRUNC, ISD::FCEIL, ISD::FROUNDEVEN}, MVT::f64,560 Legal);561 else562 setOperationAction({ISD::FCEIL, ISD::FTRUNC, ISD::FROUNDEVEN, ISD::FFLOOR},563 MVT::f64, Custom);564 565 setOperationAction(ISD::FFLOOR, MVT::f64, Legal);566 setOperationAction({ISD::FLDEXP, ISD::STRICT_FLDEXP}, {MVT::f32, MVT::f64},567 Legal);568 setOperationAction(ISD::FFREXP, {MVT::f32, MVT::f64}, Custom);569 570 setOperationAction({ISD::FSIN, ISD::FCOS, ISD::FDIV}, MVT::f32, Custom);571 setOperationAction(ISD::FDIV, MVT::f64, Custom);572 573 setOperationAction(ISD::BF16_TO_FP, {MVT::i16, MVT::f32, MVT::f64}, Expand);574 setOperationAction(ISD::FP_TO_BF16, {MVT::i16, MVT::f32, MVT::f64}, Expand);575 576 // Custom lower these because we can't specify a rule based on an illegal577 // source bf16.578 setOperationAction({ISD::FP_EXTEND, ISD::STRICT_FP_EXTEND}, MVT::f32, Custom);579 setOperationAction({ISD::FP_EXTEND, ISD::STRICT_FP_EXTEND}, MVT::f64, Custom);580 581 if (Subtarget->has16BitInsts()) {582 setOperationAction({ISD::Constant, ISD::SMIN, ISD::SMAX, ISD::UMIN,583 ISD::UMAX, ISD::UADDSAT, ISD::USUBSAT},584 MVT::i16, Legal);585 586 AddPromotedToType(ISD::SIGN_EXTEND, MVT::i16, MVT::i32);587 588 setOperationAction({ISD::ROTR, ISD::ROTL, ISD::SELECT_CC, ISD::BR_CC},589 MVT::i16, Expand);590 591 setOperationAction({ISD::SIGN_EXTEND, ISD::SDIV, ISD::UDIV, ISD::SREM,592 ISD::UREM, ISD::BITREVERSE, ISD::CTTZ,593 ISD::CTTZ_ZERO_UNDEF, ISD::CTLZ, ISD::CTLZ_ZERO_UNDEF,594 ISD::CTPOP},595 MVT::i16, Promote);596 597 setOperationAction(ISD::LOAD, MVT::i16, Custom);598 599 setTruncStoreAction(MVT::i64, MVT::i16, Expand);600 601 setOperationAction(ISD::FP16_TO_FP, MVT::i16, Promote);602 AddPromotedToType(ISD::FP16_TO_FP, MVT::i16, MVT::i32);603 setOperationAction(ISD::FP_TO_FP16, MVT::i16, Promote);604 AddPromotedToType(ISD::FP_TO_FP16, MVT::i16, MVT::i32);605 606 setOperationAction({ISD::FP_TO_SINT, ISD::FP_TO_UINT}, MVT::i16, Custom);607 setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, MVT::i16, Custom);608 setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, MVT::i1, Custom);609 610 setOperationAction({ISD::SINT_TO_FP, ISD::UINT_TO_FP}, MVT::i32, Custom);611 612 // F16 - Constant Actions.613 setOperationAction(ISD::ConstantFP, MVT::f16, Legal);614 setOperationAction(ISD::ConstantFP, MVT::bf16, Legal);615 616 // F16 - Load/Store Actions.617 setOperationAction(ISD::LOAD, MVT::f16, Promote);618 AddPromotedToType(ISD::LOAD, MVT::f16, MVT::i16);619 setOperationAction(ISD::STORE, MVT::f16, Promote);620 AddPromotedToType(ISD::STORE, MVT::f16, MVT::i16);621 622 // BF16 - Load/Store Actions.623 setOperationAction(ISD::LOAD, MVT::bf16, Promote);624 AddPromotedToType(ISD::LOAD, MVT::bf16, MVT::i16);625 setOperationAction(ISD::STORE, MVT::bf16, Promote);626 AddPromotedToType(ISD::STORE, MVT::bf16, MVT::i16);627 628 // F16 - VOP1 Actions.629 setOperationAction({ISD::FP_ROUND, ISD::STRICT_FP_ROUND, ISD::FCOS,630 ISD::FSIN, ISD::FROUND},631 MVT::f16, Custom);632 633 // BF16 - VOP1 Actions.634 if (Subtarget->hasBF16TransInsts())635 setOperationAction({ISD::FCOS, ISD::FSIN, ISD::FDIV}, MVT::bf16, Custom);636 637 setOperationAction({ISD::FP_TO_SINT, ISD::FP_TO_UINT}, MVT::f16, Promote);638 setOperationAction({ISD::FP_TO_SINT, ISD::FP_TO_UINT}, MVT::bf16, Promote);639 640 // F16 - VOP2 Actions.641 setOperationAction({ISD::BR_CC, ISD::SELECT_CC}, {MVT::f16, MVT::bf16},642 Expand);643 setOperationAction({ISD::FLDEXP, ISD::STRICT_FLDEXP}, MVT::f16, Custom);644 setOperationAction(ISD::FFREXP, MVT::f16, Custom);645 setOperationAction(ISD::FDIV, MVT::f16, Custom);646 647 // F16 - VOP3 Actions.648 setOperationAction(ISD::FMA, MVT::f16, Legal);649 if (STI.hasMadF16())650 setOperationAction(ISD::FMAD, MVT::f16, Legal);651 652 for (MVT VT :653 {MVT::v2i16, MVT::v2f16, MVT::v2bf16, MVT::v4i16, MVT::v4f16,654 MVT::v4bf16, MVT::v8i16, MVT::v8f16, MVT::v8bf16, MVT::v16i16,655 MVT::v16f16, MVT::v16bf16, MVT::v32i16, MVT::v32f16}) {656 for (unsigned Op = 0; Op < ISD::BUILTIN_OP_END; ++Op) {657 switch (Op) {658 case ISD::LOAD:659 case ISD::STORE:660 case ISD::BUILD_VECTOR:661 case ISD::BITCAST:662 case ISD::UNDEF:663 case ISD::EXTRACT_VECTOR_ELT:664 case ISD::INSERT_VECTOR_ELT:665 case ISD::INSERT_SUBVECTOR:666 case ISD::SCALAR_TO_VECTOR:667 case ISD::IS_FPCLASS:668 break;669 case ISD::EXTRACT_SUBVECTOR:670 case ISD::CONCAT_VECTORS:671 setOperationAction(Op, VT, Custom);672 break;673 default:674 setOperationAction(Op, VT, Expand);675 break;676 }677 }678 }679 680 // v_perm_b32 can handle either of these.681 setOperationAction(ISD::BSWAP, {MVT::i16, MVT::v2i16}, Legal);682 setOperationAction(ISD::BSWAP, MVT::v4i16, Custom);683 684 // XXX - Do these do anything? Vector constants turn into build_vector.685 setOperationAction(ISD::Constant, {MVT::v2i16, MVT::v2f16}, Legal);686 687 setOperationAction(ISD::UNDEF, {MVT::v2i16, MVT::v2f16, MVT::v2bf16},688 Legal);689 690 setOperationAction(ISD::STORE, MVT::v2i16, Promote);691 AddPromotedToType(ISD::STORE, MVT::v2i16, MVT::i32);692 setOperationAction(ISD::STORE, MVT::v2f16, Promote);693 AddPromotedToType(ISD::STORE, MVT::v2f16, MVT::i32);694 695 setOperationAction(ISD::LOAD, MVT::v2i16, Promote);696 AddPromotedToType(ISD::LOAD, MVT::v2i16, MVT::i32);697 setOperationAction(ISD::LOAD, MVT::v2f16, Promote);698 AddPromotedToType(ISD::LOAD, MVT::v2f16, MVT::i32);699 700 setOperationAction(ISD::AND, MVT::v2i16, Promote);701 AddPromotedToType(ISD::AND, MVT::v2i16, MVT::i32);702 setOperationAction(ISD::OR, MVT::v2i16, Promote);703 AddPromotedToType(ISD::OR, MVT::v2i16, MVT::i32);704 setOperationAction(ISD::XOR, MVT::v2i16, Promote);705 AddPromotedToType(ISD::XOR, MVT::v2i16, MVT::i32);706 707 setOperationAction(ISD::LOAD, MVT::v4i16, Promote);708 AddPromotedToType(ISD::LOAD, MVT::v4i16, MVT::v2i32);709 setOperationAction(ISD::LOAD, MVT::v4f16, Promote);710 AddPromotedToType(ISD::LOAD, MVT::v4f16, MVT::v2i32);711 setOperationAction(ISD::LOAD, MVT::v4bf16, Promote);712 AddPromotedToType(ISD::LOAD, MVT::v4bf16, MVT::v2i32);713 714 setOperationAction(ISD::STORE, MVT::v4i16, Promote);715 AddPromotedToType(ISD::STORE, MVT::v4i16, MVT::v2i32);716 setOperationAction(ISD::STORE, MVT::v4f16, Promote);717 AddPromotedToType(ISD::STORE, MVT::v4f16, MVT::v2i32);718 setOperationAction(ISD::STORE, MVT::v4bf16, Promote);719 AddPromotedToType(ISD::STORE, MVT::v4bf16, MVT::v2i32);720 721 setOperationAction(ISD::LOAD, MVT::v8i16, Promote);722 AddPromotedToType(ISD::LOAD, MVT::v8i16, MVT::v4i32);723 setOperationAction(ISD::LOAD, MVT::v8f16, Promote);724 AddPromotedToType(ISD::LOAD, MVT::v8f16, MVT::v4i32);725 setOperationAction(ISD::LOAD, MVT::v8bf16, Promote);726 AddPromotedToType(ISD::LOAD, MVT::v8bf16, MVT::v4i32);727 728 setOperationAction(ISD::STORE, MVT::v4i16, Promote);729 AddPromotedToType(ISD::STORE, MVT::v4i16, MVT::v2i32);730 setOperationAction(ISD::STORE, MVT::v4f16, Promote);731 AddPromotedToType(ISD::STORE, MVT::v4f16, MVT::v2i32);732 733 setOperationAction(ISD::STORE, MVT::v8i16, Promote);734 AddPromotedToType(ISD::STORE, MVT::v8i16, MVT::v4i32);735 setOperationAction(ISD::STORE, MVT::v8f16, Promote);736 AddPromotedToType(ISD::STORE, MVT::v8f16, MVT::v4i32);737 setOperationAction(ISD::STORE, MVT::v8bf16, Promote);738 AddPromotedToType(ISD::STORE, MVT::v8bf16, MVT::v4i32);739 740 setOperationAction(ISD::LOAD, MVT::v16i16, Promote);741 AddPromotedToType(ISD::LOAD, MVT::v16i16, MVT::v8i32);742 setOperationAction(ISD::LOAD, MVT::v16f16, Promote);743 AddPromotedToType(ISD::LOAD, MVT::v16f16, MVT::v8i32);744 setOperationAction(ISD::LOAD, MVT::v16bf16, Promote);745 AddPromotedToType(ISD::LOAD, MVT::v16bf16, MVT::v8i32);746 747 setOperationAction(ISD::STORE, MVT::v16i16, Promote);748 AddPromotedToType(ISD::STORE, MVT::v16i16, MVT::v8i32);749 setOperationAction(ISD::STORE, MVT::v16f16, Promote);750 AddPromotedToType(ISD::STORE, MVT::v16f16, MVT::v8i32);751 setOperationAction(ISD::STORE, MVT::v16bf16, Promote);752 AddPromotedToType(ISD::STORE, MVT::v16bf16, MVT::v8i32);753 754 setOperationAction(ISD::LOAD, MVT::v32i16, Promote);755 AddPromotedToType(ISD::LOAD, MVT::v32i16, MVT::v16i32);756 setOperationAction(ISD::LOAD, MVT::v32f16, Promote);757 AddPromotedToType(ISD::LOAD, MVT::v32f16, MVT::v16i32);758 setOperationAction(ISD::LOAD, MVT::v32bf16, Promote);759 AddPromotedToType(ISD::LOAD, MVT::v32bf16, MVT::v16i32);760 761 setOperationAction(ISD::STORE, MVT::v32i16, Promote);762 AddPromotedToType(ISD::STORE, MVT::v32i16, MVT::v16i32);763 setOperationAction(ISD::STORE, MVT::v32f16, Promote);764 AddPromotedToType(ISD::STORE, MVT::v32f16, MVT::v16i32);765 setOperationAction(ISD::STORE, MVT::v32bf16, Promote);766 AddPromotedToType(ISD::STORE, MVT::v32bf16, MVT::v16i32);767 768 setOperationAction({ISD::ANY_EXTEND, ISD::ZERO_EXTEND, ISD::SIGN_EXTEND},769 MVT::v2i32, Expand);770 setOperationAction(ISD::FP_EXTEND, MVT::v2f32, Expand);771 772 setOperationAction({ISD::ANY_EXTEND, ISD::ZERO_EXTEND, ISD::SIGN_EXTEND},773 MVT::v4i32, Expand);774 775 setOperationAction({ISD::ANY_EXTEND, ISD::ZERO_EXTEND, ISD::SIGN_EXTEND},776 MVT::v8i32, Expand);777 778 setOperationAction(ISD::BUILD_VECTOR, {MVT::v2i16, MVT::v2f16, MVT::v2bf16},779 Subtarget->hasVOP3PInsts() ? Legal : Custom);780 781 setOperationAction(ISD::FNEG, {MVT::v2f16, MVT::v2bf16}, Legal);782 // This isn't really legal, but this avoids the legalizer unrolling it (and783 // allows matching fneg (fabs x) patterns)784 setOperationAction(ISD::FABS, {MVT::v2f16, MVT::v2bf16}, Legal);785 786 // Can do this in one BFI plus a constant materialize.787 setOperationAction(ISD::FCOPYSIGN,788 {MVT::v2f16, MVT::v2bf16, MVT::v4f16, MVT::v4bf16,789 MVT::v8f16, MVT::v8bf16, MVT::v16f16, MVT::v16bf16,790 MVT::v32f16, MVT::v32bf16},791 Custom);792 793 setOperationAction(794 {ISD::FMAXNUM, ISD::FMINNUM, ISD::FMINIMUMNUM, ISD::FMAXIMUMNUM},795 MVT::f16, Custom);796 setOperationAction({ISD::FMAXNUM_IEEE, ISD::FMINNUM_IEEE}, MVT::f16, Legal);797 798 setOperationAction({ISD::FMINNUM_IEEE, ISD::FMAXNUM_IEEE, ISD::FMINIMUMNUM,799 ISD::FMAXIMUMNUM},800 {MVT::v4f16, MVT::v8f16, MVT::v16f16, MVT::v32f16},801 Custom);802 803 setOperationAction({ISD::FMINNUM, ISD::FMAXNUM},804 {MVT::v4f16, MVT::v8f16, MVT::v16f16, MVT::v32f16},805 Expand);806 807 for (MVT Vec16 :808 {MVT::v8i16, MVT::v8f16, MVT::v8bf16, MVT::v16i16, MVT::v16f16,809 MVT::v16bf16, MVT::v32i16, MVT::v32f16, MVT::v32bf16}) {810 setOperationAction(811 {ISD::BUILD_VECTOR, ISD::EXTRACT_VECTOR_ELT, ISD::SCALAR_TO_VECTOR},812 Vec16, Custom);813 setOperationAction(ISD::INSERT_VECTOR_ELT, Vec16, Expand);814 }815 }816 817 if (Subtarget->hasVOP3PInsts()) {818 setOperationAction({ISD::ADD, ISD::SUB, ISD::MUL, ISD::SHL, ISD::SRL,819 ISD::SRA, ISD::SMIN, ISD::UMIN, ISD::SMAX, ISD::UMAX,820 ISD::UADDSAT, ISD::USUBSAT, ISD::SADDSAT, ISD::SSUBSAT},821 MVT::v2i16, Legal);822 823 setOperationAction({ISD::FADD, ISD::FMUL, ISD::FMA, ISD::FMINNUM_IEEE,824 ISD::FMAXNUM_IEEE, ISD::FCANONICALIZE},825 MVT::v2f16, Legal);826 827 setOperationAction(ISD::EXTRACT_VECTOR_ELT,828 {MVT::v2i16, MVT::v2f16, MVT::v2bf16}, Custom);829 830 setOperationAction(ISD::VECTOR_SHUFFLE,831 {MVT::v4f16, MVT::v4i16, MVT::v4bf16, MVT::v8f16,832 MVT::v8i16, MVT::v8bf16, MVT::v16f16, MVT::v16i16,833 MVT::v16bf16, MVT::v32f16, MVT::v32i16, MVT::v32bf16},834 Custom);835 836 for (MVT VT : {MVT::v4i16, MVT::v8i16, MVT::v16i16, MVT::v32i16})837 // Split vector operations.838 setOperationAction({ISD::SHL, ISD::SRA, ISD::SRL, ISD::ADD, ISD::SUB,839 ISD::MUL, ISD::ABS, ISD::SMIN, ISD::SMAX, ISD::UMIN,840 ISD::UMAX, ISD::UADDSAT, ISD::SADDSAT, ISD::USUBSAT,841 ISD::SSUBSAT},842 VT, Custom);843 844 for (MVT VT : {MVT::v4f16, MVT::v8f16, MVT::v16f16, MVT::v32f16})845 // Split vector operations.846 setOperationAction({ISD::FADD, ISD::FMUL, ISD::FMA, ISD::FCANONICALIZE},847 VT, Custom);848 849 setOperationAction(850 {ISD::FMAXNUM, ISD::FMINNUM, ISD::FMINIMUMNUM, ISD::FMAXIMUMNUM},851 {MVT::v2f16, MVT::v4f16}, Custom);852 853 setOperationAction(ISD::FEXP, MVT::v2f16, Custom);854 setOperationAction(ISD::SELECT, {MVT::v4i16, MVT::v4f16, MVT::v4bf16},855 Custom);856 857 if (Subtarget->hasBF16PackedInsts()) {858 for (MVT VT : {MVT::v4bf16, MVT::v8bf16, MVT::v16bf16, MVT::v32bf16})859 // Split vector operations.860 setOperationAction({ISD::FADD, ISD::FMUL, ISD::FMA, ISD::FCANONICALIZE},861 VT, Custom);862 }863 864 if (Subtarget->hasPackedFP32Ops()) {865 setOperationAction({ISD::FADD, ISD::FMUL, ISD::FMA, ISD::FNEG},866 MVT::v2f32, Legal);867 setOperationAction({ISD::FADD, ISD::FMUL, ISD::FMA},868 {MVT::v4f32, MVT::v8f32, MVT::v16f32, MVT::v32f32},869 Custom);870 }871 }872 873 setOperationAction({ISD::FNEG, ISD::FABS}, MVT::v4f16, Custom);874 875 if (Subtarget->has16BitInsts()) {876 setOperationAction(ISD::SELECT, MVT::v2i16, Promote);877 AddPromotedToType(ISD::SELECT, MVT::v2i16, MVT::i32);878 setOperationAction(ISD::SELECT, MVT::v2f16, Promote);879 AddPromotedToType(ISD::SELECT, MVT::v2f16, MVT::i32);880 } else {881 // Legalization hack.882 setOperationAction(ISD::SELECT, {MVT::v2i16, MVT::v2f16}, Custom);883 884 setOperationAction({ISD::FNEG, ISD::FABS}, MVT::v2f16, Custom);885 }886 887 setOperationAction(ISD::SELECT,888 {MVT::v4i16, MVT::v4f16, MVT::v4bf16, MVT::v2i8, MVT::v4i8,889 MVT::v8i8, MVT::v8i16, MVT::v8f16, MVT::v8bf16,890 MVT::v16i16, MVT::v16f16, MVT::v16bf16, MVT::v32i16,891 MVT::v32f16, MVT::v32bf16},892 Custom);893 894 setOperationAction({ISD::SMULO, ISD::UMULO}, MVT::i64, Custom);895 896 if (Subtarget->hasVectorMulU64())897 setOperationAction(ISD::MUL, MVT::i64, Legal);898 else if (Subtarget->hasScalarSMulU64())899 setOperationAction(ISD::MUL, MVT::i64, Custom);900 901 if (Subtarget->hasMad64_32())902 setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, MVT::i32, Custom);903 904 if (Subtarget->hasSafeSmemPrefetch() || Subtarget->hasVmemPrefInsts())905 setOperationAction(ISD::PREFETCH, MVT::Other, Custom);906 907 if (Subtarget->hasIEEEMinimumMaximumInsts()) {908 setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM},909 {MVT::f16, MVT::f32, MVT::f64, MVT::v2f16}, Legal);910 } else {911 // FIXME: For nnan fmaximum, emit the fmaximum3 instead of fmaxnum912 if (Subtarget->hasMinimum3Maximum3F32())913 setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, MVT::f32, Legal);914 915 if (Subtarget->hasMinimum3Maximum3PKF16()) {916 setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, MVT::v2f16, Legal);917 918 // If only the vector form is available, we need to widen to a vector.919 if (!Subtarget->hasMinimum3Maximum3F16())920 setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, MVT::f16, Custom);921 }922 }923 924 if (Subtarget->hasVOP3PInsts()) {925 // We want to break these into v2f16 pieces, not scalarize.926 setOperationAction({ISD::FMINIMUM, ISD::FMAXIMUM},927 {MVT::v4f16, MVT::v8f16, MVT::v16f16, MVT::v32f16},928 Custom);929 }930 931 if (Subtarget->hasIntMinMax64())932 setOperationAction({ISD::SMIN, ISD::UMIN, ISD::SMAX, ISD::UMAX}, MVT::i64,933 Legal);934 935 setOperationAction(ISD::INTRINSIC_WO_CHAIN,936 {MVT::Other, MVT::f32, MVT::v4f32, MVT::i16, MVT::f16,937 MVT::bf16, MVT::v2i16, MVT::v2f16, MVT::v2bf16, MVT::i128,938 MVT::i8},939 Custom);940 941 setOperationAction(ISD::INTRINSIC_W_CHAIN,942 {MVT::v2f16, MVT::v2i16, MVT::v2bf16, MVT::v3f16,943 MVT::v3i16, MVT::v4f16, MVT::v4i16, MVT::v4bf16,944 MVT::v8i16, MVT::v8f16, MVT::v8bf16, MVT::Other, MVT::f16,945 MVT::i16, MVT::bf16, MVT::i8, MVT::i128},946 Custom);947 948 setOperationAction(ISD::INTRINSIC_VOID,949 {MVT::Other, MVT::v2i16, MVT::v2f16, MVT::v2bf16,950 MVT::v3i16, MVT::v3f16, MVT::v4f16, MVT::v4i16,951 MVT::v4bf16, MVT::v8i16, MVT::v8f16, MVT::v8bf16,952 MVT::f16, MVT::i16, MVT::bf16, MVT::i8, MVT::i128},953 Custom);954 955 setOperationAction(ISD::STACKSAVE, MVT::Other, Custom);956 setOperationAction(ISD::GET_ROUNDING, MVT::i32, Custom);957 setOperationAction(ISD::SET_ROUNDING, MVT::Other, Custom);958 setOperationAction(ISD::GET_FPENV, MVT::i64, Custom);959 setOperationAction(ISD::SET_FPENV, MVT::i64, Custom);960 961 // TODO: Could move this to custom lowering, could benefit from combines on962 // extract of relevant bits.963 setOperationAction(ISD::GET_FPMODE, MVT::i32, Legal);964 965 setOperationAction(ISD::MUL, MVT::i1, Promote);966 967 if (Subtarget->hasBF16ConversionInsts()) {968 setOperationAction(ISD::FP_ROUND, {MVT::bf16, MVT::v2bf16}, Custom);969 setOperationAction(ISD::BUILD_VECTOR, MVT::v2bf16, Legal);970 }971 972 if (Subtarget->hasBF16PackedInsts()) {973 setOperationAction(974 {ISD::FADD, ISD::FMUL, ISD::FMINNUM, ISD::FMAXNUM, ISD::FMA},975 MVT::v2bf16, Legal);976 }977 978 if (Subtarget->hasBF16TransInsts()) {979 setOperationAction({ISD::FEXP2, ISD::FLOG2, ISD::FSQRT}, MVT::bf16, Legal);980 }981 982 if (Subtarget->hasCvtPkF16F32Inst()) {983 setOperationAction(ISD::FP_ROUND,984 {MVT::v2f16, MVT::v4f16, MVT::v8f16, MVT::v16f16},985 Custom);986 }987 988 setTargetDAGCombine({ISD::ADD,989 ISD::PTRADD,990 ISD::UADDO_CARRY,991 ISD::SUB,992 ISD::USUBO_CARRY,993 ISD::MUL,994 ISD::FADD,995 ISD::FSUB,996 ISD::FDIV,997 ISD::FMUL,998 ISD::FMINNUM,999 ISD::FMAXNUM,1000 ISD::FMINNUM_IEEE,1001 ISD::FMAXNUM_IEEE,1002 ISD::FMINIMUM,1003 ISD::FMAXIMUM,1004 ISD::FMINIMUMNUM,1005 ISD::FMAXIMUMNUM,1006 ISD::FMA,1007 ISD::SMIN,1008 ISD::SMAX,1009 ISD::UMIN,1010 ISD::UMAX,1011 ISD::SETCC,1012 ISD::SELECT,1013 ISD::SMIN,1014 ISD::SMAX,1015 ISD::UMIN,1016 ISD::UMAX,1017 ISD::AND,1018 ISD::OR,1019 ISD::XOR,1020 ISD::SHL,1021 ISD::SRL,1022 ISD::SRA,1023 ISD::FSHR,1024 ISD::SINT_TO_FP,1025 ISD::UINT_TO_FP,1026 ISD::FCANONICALIZE,1027 ISD::SCALAR_TO_VECTOR,1028 ISD::ZERO_EXTEND,1029 ISD::SIGN_EXTEND_INREG,1030 ISD::EXTRACT_VECTOR_ELT,1031 ISD::INSERT_VECTOR_ELT,1032 ISD::FCOPYSIGN});1033 1034 if (Subtarget->has16BitInsts() && !Subtarget->hasMed3_16())1035 setTargetDAGCombine(ISD::FP_ROUND);1036 1037 // All memory operations. Some folding on the pointer operand is done to help1038 // matching the constant offsets in the addressing modes.1039 setTargetDAGCombine({ISD::LOAD,1040 ISD::STORE,1041 ISD::ATOMIC_LOAD,1042 ISD::ATOMIC_STORE,1043 ISD::ATOMIC_CMP_SWAP,1044 ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS,1045 ISD::ATOMIC_SWAP,1046 ISD::ATOMIC_LOAD_ADD,1047 ISD::ATOMIC_LOAD_SUB,1048 ISD::ATOMIC_LOAD_AND,1049 ISD::ATOMIC_LOAD_OR,1050 ISD::ATOMIC_LOAD_XOR,1051 ISD::ATOMIC_LOAD_NAND,1052 ISD::ATOMIC_LOAD_MIN,1053 ISD::ATOMIC_LOAD_MAX,1054 ISD::ATOMIC_LOAD_UMIN,1055 ISD::ATOMIC_LOAD_UMAX,1056 ISD::ATOMIC_LOAD_FADD,1057 ISD::ATOMIC_LOAD_FMIN,1058 ISD::ATOMIC_LOAD_FMAX,1059 ISD::ATOMIC_LOAD_UINC_WRAP,1060 ISD::ATOMIC_LOAD_UDEC_WRAP,1061 ISD::INTRINSIC_VOID,1062 ISD::INTRINSIC_W_CHAIN});1063 1064 // FIXME: In other contexts we pretend this is a per-function property.1065 setStackPointerRegisterToSaveRestore(AMDGPU::SGPR32);1066 1067 setSchedulingPreference(Sched::RegPressure);1068}1069 1070const GCNSubtarget *SITargetLowering::getSubtarget() const { return Subtarget; }1071 1072ArrayRef<MCPhysReg> SITargetLowering::getRoundingControlRegisters() const {1073 static const MCPhysReg RCRegs[] = {AMDGPU::MODE};1074 return RCRegs;1075}1076 1077//===----------------------------------------------------------------------===//1078// TargetLowering queries1079//===----------------------------------------------------------------------===//1080 1081// v_mad_mix* support a conversion from f16 to f32.1082//1083// There is only one special case when denormals are enabled we don't currently,1084// where this is OK to use.1085bool SITargetLowering::isFPExtFoldable(const SelectionDAG &DAG, unsigned Opcode,1086 EVT DestVT, EVT SrcVT) const {1087 return DestVT.getScalarType() == MVT::f32 &&1088 ((((Opcode == ISD::FMAD && Subtarget->hasMadMixInsts()) ||1089 (Opcode == ISD::FMA && Subtarget->hasFmaMixInsts())) &&1090 SrcVT.getScalarType() == MVT::f16) ||1091 (Opcode == ISD::FMA && Subtarget->hasFmaMixBF16Insts() &&1092 SrcVT.getScalarType() == MVT::bf16)) &&1093 // TODO: This probably only requires no input flushing?1094 denormalModeIsFlushAllF32(DAG.getMachineFunction());1095}1096 1097bool SITargetLowering::isFPExtFoldable(const MachineInstr &MI, unsigned Opcode,1098 LLT DestTy, LLT SrcTy) const {1099 return ((Opcode == TargetOpcode::G_FMAD && Subtarget->hasMadMixInsts()) ||1100 (Opcode == TargetOpcode::G_FMA && Subtarget->hasFmaMixInsts())) &&1101 DestTy.getScalarSizeInBits() == 32 &&1102 SrcTy.getScalarSizeInBits() == 16 &&1103 // TODO: This probably only requires no input flushing?1104 denormalModeIsFlushAllF32(*MI.getMF());1105}1106 1107bool SITargetLowering::isShuffleMaskLegal(ArrayRef<int>, EVT) const {1108 // SI has some legal vector types, but no legal vector operations. Say no1109 // shuffles are legal in order to prefer scalarizing some vector operations.1110 return false;1111}1112 1113MVT SITargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,1114 CallingConv::ID CC,1115 EVT VT) const {1116 if (CC == CallingConv::AMDGPU_KERNEL)1117 return TargetLowering::getRegisterTypeForCallingConv(Context, CC, VT);1118 1119 if (VT.isVector()) {1120 EVT ScalarVT = VT.getScalarType();1121 unsigned Size = ScalarVT.getSizeInBits();1122 if (Size == 16) {1123 if (Subtarget->has16BitInsts()) {1124 if (VT.isInteger())1125 return MVT::v2i16;1126 return (ScalarVT == MVT::bf16 ? MVT::i32 : MVT::v2f16);1127 }1128 return VT.isInteger() ? MVT::i32 : MVT::f32;1129 }1130 1131 if (Size < 16)1132 return Subtarget->has16BitInsts() ? MVT::i16 : MVT::i32;1133 return Size == 32 ? ScalarVT.getSimpleVT() : MVT::i32;1134 }1135 1136 if (VT.getSizeInBits() > 32)1137 return MVT::i32;1138 1139 return TargetLowering::getRegisterTypeForCallingConv(Context, CC, VT);1140}1141 1142unsigned SITargetLowering::getNumRegistersForCallingConv(LLVMContext &Context,1143 CallingConv::ID CC,1144 EVT VT) const {1145 if (CC == CallingConv::AMDGPU_KERNEL)1146 return TargetLowering::getNumRegistersForCallingConv(Context, CC, VT);1147 1148 if (VT.isVector()) {1149 unsigned NumElts = VT.getVectorNumElements();1150 EVT ScalarVT = VT.getScalarType();1151 unsigned Size = ScalarVT.getSizeInBits();1152 1153 // FIXME: Should probably promote 8-bit vectors to i16.1154 if (Size == 16 && Subtarget->has16BitInsts())1155 return (NumElts + 1) / 2;1156 1157 if (Size <= 32)1158 return NumElts;1159 1160 if (Size > 32)1161 return NumElts * ((Size + 31) / 32);1162 } else if (VT.getSizeInBits() > 32)1163 return (VT.getSizeInBits() + 31) / 32;1164 1165 return TargetLowering::getNumRegistersForCallingConv(Context, CC, VT);1166}1167 1168unsigned SITargetLowering::getVectorTypeBreakdownForCallingConv(1169 LLVMContext &Context, CallingConv::ID CC, EVT VT, EVT &IntermediateVT,1170 unsigned &NumIntermediates, MVT &RegisterVT) const {1171 if (CC != CallingConv::AMDGPU_KERNEL && VT.isVector()) {1172 unsigned NumElts = VT.getVectorNumElements();1173 EVT ScalarVT = VT.getScalarType();1174 unsigned Size = ScalarVT.getSizeInBits();1175 // FIXME: We should fix the ABI to be the same on targets without 16-bit1176 // support, but unless we can properly handle 3-vectors, it will be still be1177 // inconsistent.1178 if (Size == 16 && Subtarget->has16BitInsts()) {1179 if (ScalarVT == MVT::bf16) {1180 RegisterVT = MVT::i32;1181 IntermediateVT = MVT::v2bf16;1182 } else {1183 RegisterVT = VT.isInteger() ? MVT::v2i16 : MVT::v2f16;1184 IntermediateVT = RegisterVT;1185 }1186 NumIntermediates = (NumElts + 1) / 2;1187 return NumIntermediates;1188 }1189 1190 if (Size == 32) {1191 RegisterVT = ScalarVT.getSimpleVT();1192 IntermediateVT = RegisterVT;1193 NumIntermediates = NumElts;1194 return NumIntermediates;1195 }1196 1197 if (Size < 16 && Subtarget->has16BitInsts()) {1198 // FIXME: Should probably form v2i16 pieces1199 RegisterVT = MVT::i16;1200 IntermediateVT = ScalarVT;1201 NumIntermediates = NumElts;1202 return NumIntermediates;1203 }1204 1205 if (Size != 16 && Size <= 32) {1206 RegisterVT = MVT::i32;1207 IntermediateVT = ScalarVT;1208 NumIntermediates = NumElts;1209 return NumIntermediates;1210 }1211 1212 if (Size > 32) {1213 RegisterVT = MVT::i32;1214 IntermediateVT = RegisterVT;1215 NumIntermediates = NumElts * ((Size + 31) / 32);1216 return NumIntermediates;1217 }1218 }1219 1220 return TargetLowering::getVectorTypeBreakdownForCallingConv(1221 Context, CC, VT, IntermediateVT, NumIntermediates, RegisterVT);1222}1223 1224static EVT memVTFromLoadIntrData(const SITargetLowering &TLI,1225 const DataLayout &DL, Type *Ty,1226 unsigned MaxNumLanes) {1227 assert(MaxNumLanes != 0);1228 1229 LLVMContext &Ctx = Ty->getContext();1230 if (auto *VT = dyn_cast<FixedVectorType>(Ty)) {1231 unsigned NumElts = std::min(MaxNumLanes, VT->getNumElements());1232 return EVT::getVectorVT(Ctx, TLI.getValueType(DL, VT->getElementType()),1233 NumElts);1234 }1235 1236 return TLI.getValueType(DL, Ty);1237}1238 1239// Peek through TFE struct returns to only use the data size.1240static EVT memVTFromLoadIntrReturn(const SITargetLowering &TLI,1241 const DataLayout &DL, Type *Ty,1242 unsigned MaxNumLanes) {1243 auto *ST = dyn_cast<StructType>(Ty);1244 if (!ST)1245 return memVTFromLoadIntrData(TLI, DL, Ty, MaxNumLanes);1246 1247 // TFE intrinsics return an aggregate type.1248 assert(ST->getNumContainedTypes() == 2 &&1249 ST->getContainedType(1)->isIntegerTy(32));1250 return memVTFromLoadIntrData(TLI, DL, ST->getContainedType(0), MaxNumLanes);1251}1252 1253/// Map address space 7 to MVT::amdgpuBufferFatPointer because that's its1254/// in-memory representation. This return value is a custom type because there1255/// is no MVT::i160 and adding one breaks integer promotion logic. While this1256/// could cause issues during codegen, these address space 7 pointers will be1257/// rewritten away by then. Therefore, we can return MVT::amdgpuBufferFatPointer1258/// in order to allow pre-codegen passes that query TargetTransformInfo, often1259/// for cost modeling, to work. (This also sets us up decently for doing the1260/// buffer lowering in GlobalISel if SelectionDAG ever goes away.)1261MVT SITargetLowering::getPointerTy(const DataLayout &DL, unsigned AS) const {1262 if (AMDGPUAS::BUFFER_FAT_POINTER == AS && DL.getPointerSizeInBits(AS) == 160)1263 return MVT::amdgpuBufferFatPointer;1264 if (AMDGPUAS::BUFFER_STRIDED_POINTER == AS &&1265 DL.getPointerSizeInBits(AS) == 192)1266 return MVT::amdgpuBufferStridedPointer;1267 return AMDGPUTargetLowering::getPointerTy(DL, AS);1268}1269/// Similarly, the in-memory representation of a p7 is {p8, i32}, aka1270/// v8i32 when padding is added.1271/// The in-memory representation of a p9 is {p8, i32, i32}, which is1272/// also v8i32 with padding.1273MVT SITargetLowering::getPointerMemTy(const DataLayout &DL, unsigned AS) const {1274 if ((AMDGPUAS::BUFFER_FAT_POINTER == AS &&1275 DL.getPointerSizeInBits(AS) == 160) ||1276 (AMDGPUAS::BUFFER_STRIDED_POINTER == AS &&1277 DL.getPointerSizeInBits(AS) == 192))1278 return MVT::v8i32;1279 return AMDGPUTargetLowering::getPointerMemTy(DL, AS);1280}1281 1282static unsigned getIntrMemWidth(unsigned IntrID) {1283 switch (IntrID) {1284 case Intrinsic::amdgcn_global_load_async_to_lds_b8:1285 case Intrinsic::amdgcn_cluster_load_async_to_lds_b8:1286 case Intrinsic::amdgcn_global_store_async_from_lds_b8:1287 return 8;1288 case Intrinsic::amdgcn_global_load_async_to_lds_b32:1289 case Intrinsic::amdgcn_cluster_load_async_to_lds_b32:1290 case Intrinsic::amdgcn_global_store_async_from_lds_b32:1291 case Intrinsic::amdgcn_cooperative_atomic_load_32x4B:1292 case Intrinsic::amdgcn_cooperative_atomic_store_32x4B:1293 return 32;1294 case Intrinsic::amdgcn_global_load_async_to_lds_b64:1295 case Intrinsic::amdgcn_cluster_load_async_to_lds_b64:1296 case Intrinsic::amdgcn_global_store_async_from_lds_b64:1297 case Intrinsic::amdgcn_cooperative_atomic_load_16x8B:1298 case Intrinsic::amdgcn_cooperative_atomic_store_16x8B:1299 return 64;1300 case Intrinsic::amdgcn_global_load_async_to_lds_b128:1301 case Intrinsic::amdgcn_cluster_load_async_to_lds_b128:1302 case Intrinsic::amdgcn_global_store_async_from_lds_b128:1303 case Intrinsic::amdgcn_cooperative_atomic_load_8x16B:1304 case Intrinsic::amdgcn_cooperative_atomic_store_8x16B:1305 return 128;1306 default:1307 llvm_unreachable("Unknown width");1308 }1309}1310 1311static void getCoopAtomicOperandsInfo(const CallInst &CI, bool IsLoad,1312 TargetLoweringBase::IntrinsicInfo &Info) {1313 Value *OrderingArg = CI.getArgOperand(IsLoad ? 1 : 2);1314 unsigned Ord = cast<ConstantInt>(OrderingArg)->getZExtValue();1315 switch (AtomicOrderingCABI(Ord)) {1316 case AtomicOrderingCABI::acquire:1317 Info.order = AtomicOrdering::Acquire;1318 break;1319 case AtomicOrderingCABI::release:1320 Info.order = AtomicOrdering::Release;1321 break;1322 case AtomicOrderingCABI::seq_cst:1323 Info.order = AtomicOrdering::SequentiallyConsistent;1324 break;1325 default:1326 Info.order = AtomicOrdering::Monotonic;1327 break;1328 }1329 1330 Info.flags =1331 (IsLoad ? MachineMemOperand::MOLoad : MachineMemOperand::MOStore);1332 Info.flags |= MOCooperative;1333 1334 MDNode *ScopeMD = cast<MDNode>(1335 cast<MetadataAsValue>(CI.getArgOperand(IsLoad ? 2 : 3))->getMetadata());1336 StringRef Scope = cast<MDString>(ScopeMD->getOperand(0))->getString();1337 Info.ssid = CI.getContext().getOrInsertSyncScopeID(Scope);1338}1339 1340bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,1341 const CallInst &CI,1342 MachineFunction &MF,1343 unsigned IntrID) const {1344 Info.flags = MachineMemOperand::MONone;1345 if (CI.hasMetadata(LLVMContext::MD_invariant_load))1346 Info.flags |= MachineMemOperand::MOInvariant;1347 if (CI.hasMetadata(LLVMContext::MD_nontemporal))1348 Info.flags |= MachineMemOperand::MONonTemporal;1349 Info.flags |= getTargetMMOFlags(CI);1350 1351 if (const AMDGPU::RsrcIntrinsic *RsrcIntr =1352 AMDGPU::lookupRsrcIntrinsic(IntrID)) {1353 AttributeSet Attr =1354 Intrinsic::getFnAttributes(CI.getContext(), (Intrinsic::ID)IntrID);1355 MemoryEffects ME = Attr.getMemoryEffects();1356 if (ME.doesNotAccessMemory())1357 return false;1358 1359 // TODO: Should images get their own address space?1360 Info.fallbackAddressSpace = AMDGPUAS::BUFFER_RESOURCE;1361 1362 const AMDGPU::MIMGBaseOpcodeInfo *BaseOpcode = nullptr;1363 if (RsrcIntr->IsImage) {1364 const AMDGPU::ImageDimIntrinsicInfo *Intr =1365 AMDGPU::getImageDimIntrinsicInfo(IntrID);1366 BaseOpcode = AMDGPU::getMIMGBaseOpcodeInfo(Intr->BaseOpcode);1367 Info.align.reset();1368 }1369 1370 Value *RsrcArg = CI.getArgOperand(RsrcIntr->RsrcArg);1371 if (auto *RsrcPtrTy = dyn_cast<PointerType>(RsrcArg->getType())) {1372 if (RsrcPtrTy->getAddressSpace() == AMDGPUAS::BUFFER_RESOURCE)1373 // We conservatively set the memory operand of a buffer intrinsic to the1374 // base resource pointer, so that we can access alias information about1375 // those pointers. Cases like "this points at the same value1376 // but with a different offset" are handled in1377 // areMemAccessesTriviallyDisjoint.1378 Info.ptrVal = RsrcArg;1379 }1380 1381 bool IsSPrefetch = IntrID == Intrinsic::amdgcn_s_buffer_prefetch_data;1382 if (!IsSPrefetch) {1383 auto *Aux = cast<ConstantInt>(CI.getArgOperand(CI.arg_size() - 1));1384 if (Aux->getZExtValue() & AMDGPU::CPol::VOLATILE)1385 Info.flags |= MachineMemOperand::MOVolatile;1386 }1387 1388 Info.flags |= MachineMemOperand::MODereferenceable;1389 if (ME.onlyReadsMemory()) {1390 if (RsrcIntr->IsImage) {1391 unsigned MaxNumLanes = 4;1392 1393 if (!BaseOpcode->Gather4) {1394 // If this isn't a gather, we may have excess loaded elements in the1395 // IR type. Check the dmask for the real number of elements loaded.1396 unsigned DMask =1397 cast<ConstantInt>(CI.getArgOperand(0))->getZExtValue();1398 MaxNumLanes = DMask == 0 ? 1 : llvm::popcount(DMask);1399 }1400 1401 Info.memVT = memVTFromLoadIntrReturn(*this, MF.getDataLayout(),1402 CI.getType(), MaxNumLanes);1403 } else {1404 Info.memVT =1405 memVTFromLoadIntrReturn(*this, MF.getDataLayout(), CI.getType(),1406 std::numeric_limits<unsigned>::max());1407 }1408 1409 // FIXME: What does alignment mean for an image?1410 Info.opc = ISD::INTRINSIC_W_CHAIN;1411 Info.flags |= MachineMemOperand::MOLoad;1412 } else if (ME.onlyWritesMemory()) {1413 Info.opc = ISD::INTRINSIC_VOID;1414 1415 Type *DataTy = CI.getArgOperand(0)->getType();1416 if (RsrcIntr->IsImage) {1417 unsigned DMask = cast<ConstantInt>(CI.getArgOperand(1))->getZExtValue();1418 unsigned DMaskLanes = DMask == 0 ? 1 : llvm::popcount(DMask);1419 Info.memVT = memVTFromLoadIntrData(*this, MF.getDataLayout(), DataTy,1420 DMaskLanes);1421 } else1422 Info.memVT = getValueType(MF.getDataLayout(), DataTy);1423 1424 Info.flags |= MachineMemOperand::MOStore;1425 } else {1426 // Atomic, NoReturn Sampler or prefetch1427 Info.opc = CI.getType()->isVoidTy() ? ISD::INTRINSIC_VOID1428 : ISD::INTRINSIC_W_CHAIN;1429 Info.flags |=1430 MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable;1431 1432 if (!IsSPrefetch)1433 Info.flags |= MachineMemOperand::MOStore;1434 1435 switch (IntrID) {1436 default:1437 if ((RsrcIntr->IsImage && BaseOpcode->NoReturn) || IsSPrefetch) {1438 // Fake memory access type for no return sampler intrinsics1439 Info.memVT = MVT::i32;1440 } else {1441 // XXX - Should this be volatile without known ordering?1442 Info.flags |= MachineMemOperand::MOVolatile;1443 Info.memVT = MVT::getVT(CI.getArgOperand(0)->getType());1444 }1445 break;1446 case Intrinsic::amdgcn_raw_buffer_load_lds:1447 case Intrinsic::amdgcn_raw_ptr_buffer_load_lds:1448 case Intrinsic::amdgcn_struct_buffer_load_lds:1449 case Intrinsic::amdgcn_struct_ptr_buffer_load_lds: {1450 unsigned Width = cast<ConstantInt>(CI.getArgOperand(2))->getZExtValue();1451 Info.memVT = EVT::getIntegerVT(CI.getContext(), Width * 8);1452 Info.ptrVal = CI.getArgOperand(1);1453 return true;1454 }1455 case Intrinsic::amdgcn_raw_atomic_buffer_load:1456 case Intrinsic::amdgcn_raw_ptr_atomic_buffer_load:1457 case Intrinsic::amdgcn_struct_atomic_buffer_load:1458 case Intrinsic::amdgcn_struct_ptr_atomic_buffer_load: {1459 Info.memVT =1460 memVTFromLoadIntrReturn(*this, MF.getDataLayout(), CI.getType(),1461 std::numeric_limits<unsigned>::max());1462 Info.flags &= ~MachineMemOperand::MOStore;1463 return true;1464 }1465 }1466 }1467 return true;1468 }1469 1470 switch (IntrID) {1471 case Intrinsic::amdgcn_ds_ordered_add:1472 case Intrinsic::amdgcn_ds_ordered_swap: {1473 Info.opc = ISD::INTRINSIC_W_CHAIN;1474 Info.memVT = MVT::getVT(CI.getType());1475 Info.ptrVal = CI.getOperand(0);1476 Info.align.reset();1477 Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore;1478 1479 const ConstantInt *Vol = cast<ConstantInt>(CI.getOperand(4));1480 if (!Vol->isZero())1481 Info.flags |= MachineMemOperand::MOVolatile;1482 1483 return true;1484 }1485 case Intrinsic::amdgcn_ds_add_gs_reg_rtn:1486 case Intrinsic::amdgcn_ds_sub_gs_reg_rtn: {1487 Info.opc = ISD::INTRINSIC_W_CHAIN;1488 Info.memVT = MVT::getVT(CI.getOperand(0)->getType());1489 Info.ptrVal = nullptr;1490 Info.fallbackAddressSpace = AMDGPUAS::STREAMOUT_REGISTER;1491 Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore;1492 return true;1493 }1494 case Intrinsic::amdgcn_ds_append:1495 case Intrinsic::amdgcn_ds_consume: {1496 Info.opc = ISD::INTRINSIC_W_CHAIN;1497 Info.memVT = MVT::getVT(CI.getType());1498 Info.ptrVal = CI.getOperand(0);1499 Info.align.reset();1500 Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore;1501 1502 const ConstantInt *Vol = cast<ConstantInt>(CI.getOperand(1));1503 if (!Vol->isZero())1504 Info.flags |= MachineMemOperand::MOVolatile;1505 1506 return true;1507 }1508 case Intrinsic::amdgcn_ds_atomic_async_barrier_arrive_b64:1509 case Intrinsic::amdgcn_ds_atomic_barrier_arrive_rtn_b64: {1510 Info.opc = (IntrID == Intrinsic::amdgcn_ds_atomic_barrier_arrive_rtn_b64)1511 ? ISD::INTRINSIC_W_CHAIN1512 : ISD::INTRINSIC_VOID;1513 Info.memVT = MVT::getVT(CI.getType());1514 Info.ptrVal = CI.getOperand(0);1515 Info.memVT = MVT::i64;1516 Info.size = 8;1517 Info.align.reset();1518 Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore;1519 return true;1520 }1521 case Intrinsic::amdgcn_global_atomic_csub: {1522 Info.opc = ISD::INTRINSIC_W_CHAIN;1523 Info.memVT = MVT::getVT(CI.getType());1524 Info.ptrVal = CI.getOperand(0);1525 Info.align.reset();1526 Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore |1527 MachineMemOperand::MOVolatile;1528 return true;1529 }1530 case Intrinsic::amdgcn_image_bvh_dual_intersect_ray:1531 case Intrinsic::amdgcn_image_bvh_intersect_ray:1532 case Intrinsic::amdgcn_image_bvh8_intersect_ray: {1533 Info.opc = ISD::INTRINSIC_W_CHAIN;1534 Info.memVT =1535 MVT::getVT(IntrID == Intrinsic::amdgcn_image_bvh_intersect_ray1536 ? CI.getType()1537 : cast<StructType>(CI.getType())1538 ->getElementType(0)); // XXX: what is correct VT?1539 1540 Info.fallbackAddressSpace = AMDGPUAS::BUFFER_RESOURCE;1541 Info.align.reset();1542 Info.flags |=1543 MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable;1544 return true;1545 }1546 case Intrinsic::amdgcn_global_atomic_fmin_num:1547 case Intrinsic::amdgcn_global_atomic_fmax_num:1548 case Intrinsic::amdgcn_global_atomic_ordered_add_b64:1549 case Intrinsic::amdgcn_flat_atomic_fmin_num:1550 case Intrinsic::amdgcn_flat_atomic_fmax_num:1551 case Intrinsic::amdgcn_atomic_cond_sub_u32: {1552 Info.opc = ISD::INTRINSIC_W_CHAIN;1553 Info.memVT = MVT::getVT(CI.getType());1554 Info.ptrVal = CI.getOperand(0);1555 Info.align.reset();1556 Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore |1557 MachineMemOperand::MODereferenceable |1558 MachineMemOperand::MOVolatile;1559 return true;1560 }1561 case Intrinsic::amdgcn_flat_load_monitor_b32:1562 case Intrinsic::amdgcn_flat_load_monitor_b64:1563 case Intrinsic::amdgcn_flat_load_monitor_b128:1564 case Intrinsic::amdgcn_global_load_monitor_b32:1565 case Intrinsic::amdgcn_global_load_monitor_b64:1566 case Intrinsic::amdgcn_global_load_monitor_b128:1567 case Intrinsic::amdgcn_cluster_load_b32:1568 case Intrinsic::amdgcn_cluster_load_b64:1569 case Intrinsic::amdgcn_cluster_load_b128:1570 case Intrinsic::amdgcn_ds_load_tr6_b96:1571 case Intrinsic::amdgcn_ds_load_tr4_b64:1572 case Intrinsic::amdgcn_ds_load_tr8_b64:1573 case Intrinsic::amdgcn_ds_load_tr16_b128:1574 case Intrinsic::amdgcn_global_load_tr6_b96:1575 case Intrinsic::amdgcn_global_load_tr4_b64:1576 case Intrinsic::amdgcn_global_load_tr_b64:1577 case Intrinsic::amdgcn_global_load_tr_b128:1578 case Intrinsic::amdgcn_ds_read_tr4_b64:1579 case Intrinsic::amdgcn_ds_read_tr6_b96:1580 case Intrinsic::amdgcn_ds_read_tr8_b64:1581 case Intrinsic::amdgcn_ds_read_tr16_b64: {1582 Info.opc = ISD::INTRINSIC_W_CHAIN;1583 Info.memVT = MVT::getVT(CI.getType());1584 Info.ptrVal = CI.getOperand(0);1585 Info.align.reset();1586 Info.flags |= MachineMemOperand::MOLoad;1587 return true;1588 }1589 case Intrinsic::amdgcn_cooperative_atomic_load_32x4B:1590 case Intrinsic::amdgcn_cooperative_atomic_load_16x8B:1591 case Intrinsic::amdgcn_cooperative_atomic_load_8x16B: {1592 Info.opc = ISD::INTRINSIC_W_CHAIN;1593 Info.memVT = EVT::getIntegerVT(CI.getContext(), getIntrMemWidth(IntrID));1594 Info.ptrVal = CI.getOperand(0);1595 Info.align.reset();1596 getCoopAtomicOperandsInfo(CI, /*IsLoad=*/true, Info);1597 return true;1598 }1599 case Intrinsic::amdgcn_cooperative_atomic_store_32x4B:1600 case Intrinsic::amdgcn_cooperative_atomic_store_16x8B:1601 case Intrinsic::amdgcn_cooperative_atomic_store_8x16B: {1602 Info.opc = ISD::INTRINSIC_VOID;1603 Info.memVT = EVT::getIntegerVT(CI.getContext(), getIntrMemWidth(IntrID));1604 Info.ptrVal = CI.getArgOperand(0);1605 Info.align.reset();1606 getCoopAtomicOperandsInfo(CI, /*IsLoad=*/false, Info);1607 return true;1608 }1609 case Intrinsic::amdgcn_ds_gws_init:1610 case Intrinsic::amdgcn_ds_gws_barrier:1611 case Intrinsic::amdgcn_ds_gws_sema_v:1612 case Intrinsic::amdgcn_ds_gws_sema_br:1613 case Intrinsic::amdgcn_ds_gws_sema_p:1614 case Intrinsic::amdgcn_ds_gws_sema_release_all: {1615 Info.opc = ISD::INTRINSIC_VOID;1616 1617 const GCNTargetMachine &TM =1618 static_cast<const GCNTargetMachine &>(getTargetMachine());1619 1620 SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();1621 Info.ptrVal = MFI->getGWSPSV(TM);1622 1623 // This is an abstract access, but we need to specify a type and size.1624 Info.memVT = MVT::i32;1625 Info.size = 4;1626 Info.align = Align(4);1627 1628 if (IntrID == Intrinsic::amdgcn_ds_gws_barrier)1629 Info.flags |= MachineMemOperand::MOLoad;1630 else1631 Info.flags |= MachineMemOperand::MOStore;1632 return true;1633 }1634 case Intrinsic::amdgcn_global_load_async_to_lds_b8:1635 case Intrinsic::amdgcn_global_load_async_to_lds_b32:1636 case Intrinsic::amdgcn_global_load_async_to_lds_b64:1637 case Intrinsic::amdgcn_global_load_async_to_lds_b128:1638 case Intrinsic::amdgcn_cluster_load_async_to_lds_b8:1639 case Intrinsic::amdgcn_cluster_load_async_to_lds_b32:1640 case Intrinsic::amdgcn_cluster_load_async_to_lds_b64:1641 case Intrinsic::amdgcn_cluster_load_async_to_lds_b128: {1642 Info.opc = ISD::INTRINSIC_VOID;1643 Info.memVT = EVT::getIntegerVT(CI.getContext(), getIntrMemWidth(IntrID));1644 Info.ptrVal = CI.getArgOperand(1);1645 Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore;1646 return true;1647 }1648 case Intrinsic::amdgcn_global_store_async_from_lds_b8:1649 case Intrinsic::amdgcn_global_store_async_from_lds_b32:1650 case Intrinsic::amdgcn_global_store_async_from_lds_b64:1651 case Intrinsic::amdgcn_global_store_async_from_lds_b128: {1652 Info.opc = ISD::INTRINSIC_VOID;1653 Info.memVT = EVT::getIntegerVT(CI.getContext(), getIntrMemWidth(IntrID));1654 Info.ptrVal = CI.getArgOperand(0);1655 Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore;1656 return true;1657 }1658 case Intrinsic::amdgcn_load_to_lds:1659 case Intrinsic::amdgcn_global_load_lds: {1660 Info.opc = ISD::INTRINSIC_VOID;1661 unsigned Width = cast<ConstantInt>(CI.getArgOperand(2))->getZExtValue();1662 Info.memVT = EVT::getIntegerVT(CI.getContext(), Width * 8);1663 Info.ptrVal = CI.getArgOperand(1);1664 Info.flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore;1665 auto *Aux = cast<ConstantInt>(CI.getArgOperand(CI.arg_size() - 1));1666 if (Aux->getZExtValue() & AMDGPU::CPol::VOLATILE)1667 Info.flags |= MachineMemOperand::MOVolatile;1668 return true;1669 }1670 case Intrinsic::amdgcn_ds_bvh_stack_rtn:1671 case Intrinsic::amdgcn_ds_bvh_stack_push4_pop1_rtn:1672 case Intrinsic::amdgcn_ds_bvh_stack_push8_pop1_rtn:1673 case Intrinsic::amdgcn_ds_bvh_stack_push8_pop2_rtn: {1674 Info.opc = ISD::INTRINSIC_W_CHAIN;1675 1676 const GCNTargetMachine &TM =1677 static_cast<const GCNTargetMachine &>(getTargetMachine());1678 1679 SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();1680 Info.ptrVal = MFI->getGWSPSV(TM);1681 1682 // This is an abstract access, but we need to specify a type and size.1683 Info.memVT = MVT::i32;1684 Info.size = 4;1685 Info.align = Align(4);1686 1687 Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore;1688 return true;1689 }1690 case Intrinsic::amdgcn_s_prefetch_data:1691 case Intrinsic::amdgcn_flat_prefetch:1692 case Intrinsic::amdgcn_global_prefetch: {1693 Info.opc = ISD::INTRINSIC_VOID;1694 Info.memVT = EVT::getIntegerVT(CI.getContext(), 8);1695 Info.ptrVal = CI.getArgOperand(0);1696 Info.flags |= MachineMemOperand::MOLoad;1697 return true;1698 }1699 default:1700 return false;1701 }1702}1703 1704void SITargetLowering::CollectTargetIntrinsicOperands(1705 const CallInst &I, SmallVectorImpl<SDValue> &Ops, SelectionDAG &DAG) const {1706 switch (cast<IntrinsicInst>(I).getIntrinsicID()) {1707 case Intrinsic::amdgcn_addrspacecast_nonnull: {1708 // The DAG's ValueType loses the addrspaces.1709 // Add them as 2 extra Constant operands "from" and "to".1710 unsigned SrcAS = I.getOperand(0)->getType()->getPointerAddressSpace();1711 unsigned DstAS = I.getType()->getPointerAddressSpace();1712 Ops.push_back(DAG.getTargetConstant(SrcAS, SDLoc(), MVT::i32));1713 Ops.push_back(DAG.getTargetConstant(DstAS, SDLoc(), MVT::i32));1714 break;1715 }1716 default:1717 break;1718 }1719}1720 1721bool SITargetLowering::getAddrModeArguments(const IntrinsicInst *II,1722 SmallVectorImpl<Value *> &Ops,1723 Type *&AccessTy) const {1724 Value *Ptr = nullptr;1725 switch (II->getIntrinsicID()) {1726 case Intrinsic::amdgcn_atomic_cond_sub_u32:1727 case Intrinsic::amdgcn_cluster_load_b128:1728 case Intrinsic::amdgcn_cluster_load_b64:1729 case Intrinsic::amdgcn_cluster_load_b32:1730 case Intrinsic::amdgcn_ds_append:1731 case Intrinsic::amdgcn_ds_consume:1732 case Intrinsic::amdgcn_ds_load_tr8_b64:1733 case Intrinsic::amdgcn_ds_load_tr16_b128:1734 case Intrinsic::amdgcn_ds_load_tr4_b64:1735 case Intrinsic::amdgcn_ds_load_tr6_b96:1736 case Intrinsic::amdgcn_ds_read_tr4_b64:1737 case Intrinsic::amdgcn_ds_read_tr6_b96:1738 case Intrinsic::amdgcn_ds_read_tr8_b64:1739 case Intrinsic::amdgcn_ds_read_tr16_b64:1740 case Intrinsic::amdgcn_ds_ordered_add:1741 case Intrinsic::amdgcn_ds_ordered_swap:1742 case Intrinsic::amdgcn_ds_atomic_async_barrier_arrive_b64:1743 case Intrinsic::amdgcn_ds_atomic_barrier_arrive_rtn_b64:1744 case Intrinsic::amdgcn_flat_atomic_fmax_num:1745 case Intrinsic::amdgcn_flat_atomic_fmin_num:1746 case Intrinsic::amdgcn_flat_load_monitor_b128:1747 case Intrinsic::amdgcn_flat_load_monitor_b32:1748 case Intrinsic::amdgcn_flat_load_monitor_b64:1749 case Intrinsic::amdgcn_global_atomic_csub:1750 case Intrinsic::amdgcn_global_atomic_fmax_num:1751 case Intrinsic::amdgcn_global_atomic_fmin_num:1752 case Intrinsic::amdgcn_global_atomic_ordered_add_b64:1753 case Intrinsic::amdgcn_global_load_monitor_b128:1754 case Intrinsic::amdgcn_global_load_monitor_b32:1755 case Intrinsic::amdgcn_global_load_monitor_b64:1756 case Intrinsic::amdgcn_global_load_tr_b64:1757 case Intrinsic::amdgcn_global_load_tr_b128:1758 case Intrinsic::amdgcn_global_load_tr4_b64:1759 case Intrinsic::amdgcn_global_load_tr6_b96:1760 case Intrinsic::amdgcn_global_store_async_from_lds_b8:1761 case Intrinsic::amdgcn_global_store_async_from_lds_b32:1762 case Intrinsic::amdgcn_global_store_async_from_lds_b64:1763 case Intrinsic::amdgcn_global_store_async_from_lds_b128:1764 Ptr = II->getArgOperand(0);1765 break;1766 case Intrinsic::amdgcn_load_to_lds:1767 case Intrinsic::amdgcn_global_load_lds:1768 case Intrinsic::amdgcn_global_load_async_to_lds_b8:1769 case Intrinsic::amdgcn_global_load_async_to_lds_b32:1770 case Intrinsic::amdgcn_global_load_async_to_lds_b64:1771 case Intrinsic::amdgcn_global_load_async_to_lds_b128:1772 case Intrinsic::amdgcn_cluster_load_async_to_lds_b8:1773 case Intrinsic::amdgcn_cluster_load_async_to_lds_b32:1774 case Intrinsic::amdgcn_cluster_load_async_to_lds_b64:1775 case Intrinsic::amdgcn_cluster_load_async_to_lds_b128:1776 Ptr = II->getArgOperand(1);1777 break;1778 default:1779 return false;1780 }1781 AccessTy = II->getType();1782 Ops.push_back(Ptr);1783 return true;1784}1785 1786bool SITargetLowering::isLegalFlatAddressingMode(const AddrMode &AM,1787 unsigned AddrSpace) const {1788 if (!Subtarget->hasFlatInstOffsets()) {1789 // Flat instructions do not have offsets, and only have the register1790 // address.1791 return AM.BaseOffs == 0 && AM.Scale == 0;1792 }1793 1794 decltype(SIInstrFlags::FLAT) FlatVariant =1795 AddrSpace == AMDGPUAS::GLOBAL_ADDRESS ? SIInstrFlags::FlatGlobal1796 : AddrSpace == AMDGPUAS::PRIVATE_ADDRESS ? SIInstrFlags::FlatScratch1797 : SIInstrFlags::FLAT;1798 1799 return AM.Scale == 0 &&1800 (AM.BaseOffs == 0 || Subtarget->getInstrInfo()->isLegalFLATOffset(1801 AM.BaseOffs, AddrSpace, FlatVariant));1802}1803 1804bool SITargetLowering::isLegalGlobalAddressingMode(const AddrMode &AM) const {1805 if (Subtarget->hasFlatGlobalInsts())1806 return isLegalFlatAddressingMode(AM, AMDGPUAS::GLOBAL_ADDRESS);1807 1808 if (!Subtarget->hasAddr64() || Subtarget->useFlatForGlobal()) {1809 // Assume the we will use FLAT for all global memory accesses1810 // on VI.1811 // FIXME: This assumption is currently wrong. On VI we still use1812 // MUBUF instructions for the r + i addressing mode. As currently1813 // implemented, the MUBUF instructions only work on buffer < 4GB.1814 // It may be possible to support > 4GB buffers with MUBUF instructions,1815 // by setting the stride value in the resource descriptor which would1816 // increase the size limit to (stride * 4GB). However, this is risky,1817 // because it has never been validated.1818 return isLegalFlatAddressingMode(AM, AMDGPUAS::FLAT_ADDRESS);1819 }1820 1821 return isLegalMUBUFAddressingMode(AM);1822}1823 1824bool SITargetLowering::isLegalMUBUFAddressingMode(const AddrMode &AM) const {1825 // MUBUF / MTBUF instructions have a 12-bit unsigned byte offset, and1826 // additionally can do r + r + i with addr64. 32-bit has more addressing1827 // mode options. Depending on the resource constant, it can also do1828 // (i64 r0) + (i32 r1) * (i14 i).1829 //1830 // Private arrays end up using a scratch buffer most of the time, so also1831 // assume those use MUBUF instructions. Scratch loads / stores are currently1832 // implemented as mubuf instructions with offen bit set, so slightly1833 // different than the normal addr64.1834 const SIInstrInfo *TII = Subtarget->getInstrInfo();1835 if (!TII->isLegalMUBUFImmOffset(AM.BaseOffs))1836 return false;1837 1838 // FIXME: Since we can split immediate into soffset and immediate offset,1839 // would it make sense to allow any immediate?1840 1841 switch (AM.Scale) {1842 case 0: // r + i or just i, depending on HasBaseReg.1843 return true;1844 case 1:1845 return true; // We have r + r or r + i.1846 case 2:1847 if (AM.HasBaseReg) {1848 // Reject 2 * r + r.1849 return false;1850 }1851 1852 // Allow 2 * r as r + r1853 // Or 2 * r + i is allowed as r + r + i.1854 return true;1855 default: // Don't allow n * r1856 return false;1857 }1858}1859 1860bool SITargetLowering::isLegalAddressingMode(const DataLayout &DL,1861 const AddrMode &AM, Type *Ty,1862 unsigned AS,1863 Instruction *I) const {1864 // No global is ever allowed as a base.1865 if (AM.BaseGV)1866 return false;1867 1868 if (AS == AMDGPUAS::GLOBAL_ADDRESS)1869 return isLegalGlobalAddressingMode(AM);1870 1871 if (AS == AMDGPUAS::CONSTANT_ADDRESS ||1872 AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT ||1873 AS == AMDGPUAS::BUFFER_FAT_POINTER || AS == AMDGPUAS::BUFFER_RESOURCE ||1874 AS == AMDGPUAS::BUFFER_STRIDED_POINTER) {1875 // If the offset isn't a multiple of 4, it probably isn't going to be1876 // correctly aligned.1877 // FIXME: Can we get the real alignment here?1878 if (AM.BaseOffs % 4 != 0)1879 return isLegalMUBUFAddressingMode(AM);1880 1881 if (!Subtarget->hasScalarSubwordLoads()) {1882 // There are no SMRD extloads, so if we have to do a small type access we1883 // will use a MUBUF load.1884 // FIXME?: We also need to do this if unaligned, but we don't know the1885 // alignment here.1886 if (Ty->isSized() && DL.getTypeStoreSize(Ty) < 4)1887 return isLegalGlobalAddressingMode(AM);1888 }1889 1890 if (Subtarget->getGeneration() == AMDGPUSubtarget::SOUTHERN_ISLANDS) {1891 // SMRD instructions have an 8-bit, dword offset on SI.1892 if (!isUInt<8>(AM.BaseOffs / 4))1893 return false;1894 } else if (Subtarget->getGeneration() == AMDGPUSubtarget::SEA_ISLANDS) {1895 // On CI+, this can also be a 32-bit literal constant offset. If it fits1896 // in 8-bits, it can use a smaller encoding.1897 if (!isUInt<32>(AM.BaseOffs / 4))1898 return false;1899 } else if (Subtarget->getGeneration() < AMDGPUSubtarget::GFX9) {1900 // On VI, these use the SMEM format and the offset is 20-bit in bytes.1901 if (!isUInt<20>(AM.BaseOffs))1902 return false;1903 } else if (Subtarget->getGeneration() < AMDGPUSubtarget::GFX12) {1904 // On GFX9 the offset is signed 21-bit in bytes (but must not be negative1905 // for S_BUFFER_* instructions).1906 if (!isInt<21>(AM.BaseOffs))1907 return false;1908 } else {1909 // On GFX12, all offsets are signed 24-bit in bytes.1910 if (!isInt<24>(AM.BaseOffs))1911 return false;1912 }1913 1914 if ((AS == AMDGPUAS::CONSTANT_ADDRESS ||1915 AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT) &&1916 AM.BaseOffs < 0) {1917 // Scalar (non-buffer) loads can only use a negative offset if1918 // soffset+offset is non-negative. Since the compiler can only prove that1919 // in a few special cases, it is safer to claim that negative offsets are1920 // not supported.1921 return false;1922 }1923 1924 if (AM.Scale == 0) // r + i or just i, depending on HasBaseReg.1925 return true;1926 1927 if (AM.Scale == 1 && AM.HasBaseReg)1928 return true;1929 1930 return false;1931 }1932 1933 if (AS == AMDGPUAS::PRIVATE_ADDRESS)1934 return Subtarget->enableFlatScratch()1935 ? isLegalFlatAddressingMode(AM, AMDGPUAS::PRIVATE_ADDRESS)1936 : isLegalMUBUFAddressingMode(AM);1937 1938 if (AS == AMDGPUAS::LOCAL_ADDRESS ||1939 (AS == AMDGPUAS::REGION_ADDRESS && Subtarget->hasGDS())) {1940 // Basic, single offset DS instructions allow a 16-bit unsigned immediate1941 // field.1942 // XXX - If doing a 4-byte aligned 8-byte type access, we effectively have1943 // an 8-bit dword offset but we don't know the alignment here.1944 if (!isUInt<16>(AM.BaseOffs))1945 return false;1946 1947 if (AM.Scale == 0) // r + i or just i, depending on HasBaseReg.1948 return true;1949 1950 if (AM.Scale == 1 && AM.HasBaseReg)1951 return true;1952 1953 return false;1954 }1955 1956 if (AS == AMDGPUAS::FLAT_ADDRESS || AS == AMDGPUAS::UNKNOWN_ADDRESS_SPACE) {1957 // For an unknown address space, this usually means that this is for some1958 // reason being used for pure arithmetic, and not based on some addressing1959 // computation. We don't have instructions that compute pointers with any1960 // addressing modes, so treat them as having no offset like flat1961 // instructions.1962 return isLegalFlatAddressingMode(AM, AMDGPUAS::FLAT_ADDRESS);1963 }1964 1965 // Assume a user alias of global for unknown address spaces.1966 return isLegalGlobalAddressingMode(AM);1967}1968 1969bool SITargetLowering::canMergeStoresTo(unsigned AS, EVT MemVT,1970 const MachineFunction &MF) const {1971 if (AS == AMDGPUAS::GLOBAL_ADDRESS || AS == AMDGPUAS::FLAT_ADDRESS)1972 return (MemVT.getSizeInBits() <= 4 * 32);1973 if (AS == AMDGPUAS::PRIVATE_ADDRESS) {1974 unsigned MaxPrivateBits = 8 * getSubtarget()->getMaxPrivateElementSize();1975 return (MemVT.getSizeInBits() <= MaxPrivateBits);1976 }1977 if (AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::REGION_ADDRESS)1978 return (MemVT.getSizeInBits() <= 2 * 32);1979 return true;1980}1981 1982bool SITargetLowering::allowsMisalignedMemoryAccessesImpl(1983 unsigned Size, unsigned AddrSpace, Align Alignment,1984 MachineMemOperand::Flags Flags, unsigned *IsFast) const {1985 if (IsFast)1986 *IsFast = 0;1987 1988 if (AddrSpace == AMDGPUAS::LOCAL_ADDRESS ||1989 AddrSpace == AMDGPUAS::REGION_ADDRESS) {1990 // Check if alignment requirements for ds_read/write instructions are1991 // disabled.1992 if (!Subtarget->hasUnalignedDSAccessEnabled() && Alignment < Align(4))1993 return false;1994 1995 Align RequiredAlignment(1996 PowerOf2Ceil(divideCeil(Size, 8))); // Natural alignment.1997 if (Subtarget->hasLDSMisalignedBug() && Size > 32 &&1998 Alignment < RequiredAlignment)1999 return false;2000 2001 // Either, the alignment requirements are "enabled", or there is an2002 // unaligned LDS access related hardware bug though alignment requirements2003 // are "disabled". In either case, we need to check for proper alignment2004 // requirements.2005 //2006 switch (Size) {2007 case 64:2008 // SI has a hardware bug in the LDS / GDS bounds checking: if the base2009 // address is negative, then the instruction is incorrectly treated as2010 // out-of-bounds even if base + offsets is in bounds. Split vectorized2011 // loads here to avoid emitting ds_read2_b32. We may re-combine the2012 // load later in the SILoadStoreOptimizer.2013 if (!Subtarget->hasUsableDSOffset() && Alignment < Align(8))2014 return false;2015 2016 // 8 byte accessing via ds_read/write_b64 require 8-byte alignment, but we2017 // can do a 4 byte aligned, 8 byte access in a single operation using2018 // ds_read2/write2_b32 with adjacent offsets.2019 RequiredAlignment = Align(4);2020 2021 if (Subtarget->hasUnalignedDSAccessEnabled()) {2022 // We will either select ds_read_b64/ds_write_b64 or ds_read2_b32/2023 // ds_write2_b32 depending on the alignment. In either case with either2024 // alignment there is no faster way of doing this.2025 2026 // The numbers returned here and below are not additive, it is a 'speed2027 // rank'. They are just meant to be compared to decide if a certain way2028 // of lowering an operation is faster than another. For that purpose2029 // naturally aligned operation gets it bitsize to indicate that "it2030 // operates with a speed comparable to N-bit wide load". With the full2031 // alignment ds128 is slower than ds96 for example. If underaligned it2032 // is comparable to a speed of a single dword access, which would then2033 // mean 32 < 128 and it is faster to issue a wide load regardless.2034 // 1 is simply "slow, don't do it". I.e. comparing an aligned load to a2035 // wider load which will not be aligned anymore the latter is slower.2036 if (IsFast)2037 *IsFast = (Alignment >= RequiredAlignment) ? 642038 : (Alignment < Align(4)) ? 322039 : 1;2040 return true;2041 }2042 2043 break;2044 case 96:2045 if (!Subtarget->hasDS96AndDS128())2046 return false;2047 2048 // 12 byte accessing via ds_read/write_b96 require 16-byte alignment on2049 // gfx8 and older.2050 2051 if (Subtarget->hasUnalignedDSAccessEnabled()) {2052 // Naturally aligned access is fastest. However, also report it is Fast2053 // if memory is aligned less than DWORD. A narrow load or store will be2054 // be equally slow as a single ds_read_b96/ds_write_b96, but there will2055 // be more of them, so overall we will pay less penalty issuing a single2056 // instruction.2057 2058 // See comment on the values above.2059 if (IsFast)2060 *IsFast = (Alignment >= RequiredAlignment) ? 962061 : (Alignment < Align(4)) ? 322062 : 1;2063 return true;2064 }2065 2066 break;2067 case 128:2068 if (!Subtarget->hasDS96AndDS128() || !Subtarget->useDS128())2069 return false;2070 2071 // 16 byte accessing via ds_read/write_b128 require 16-byte alignment on2072 // gfx8 and older, but we can do a 8 byte aligned, 16 byte access in a2073 // single operation using ds_read2/write2_b64.2074 RequiredAlignment = Align(8);2075 2076 if (Subtarget->hasUnalignedDSAccessEnabled()) {2077 // Naturally aligned access is fastest. However, also report it is Fast2078 // if memory is aligned less than DWORD. A narrow load or store will be2079 // be equally slow as a single ds_read_b128/ds_write_b128, but there2080 // will be more of them, so overall we will pay less penalty issuing a2081 // single instruction.2082 2083 // See comment on the values above.2084 if (IsFast)2085 *IsFast = (Alignment >= RequiredAlignment) ? 1282086 : (Alignment < Align(4)) ? 322087 : 1;2088 return true;2089 }2090 2091 break;2092 default:2093 if (Size > 32)2094 return false;2095 2096 break;2097 }2098 2099 // See comment on the values above.2100 // Note that we have a single-dword or sub-dword here, so if underaligned2101 // it is a slowest possible access, hence returned value is 0.2102 if (IsFast)2103 *IsFast = (Alignment >= RequiredAlignment) ? Size : 0;2104 2105 return Alignment >= RequiredAlignment ||2106 Subtarget->hasUnalignedDSAccessEnabled();2107 }2108 2109 // FIXME: We have to be conservative here and assume that flat operations2110 // will access scratch. If we had access to the IR function, then we2111 // could determine if any private memory was used in the function.2112 if (AddrSpace == AMDGPUAS::PRIVATE_ADDRESS ||2113 AddrSpace == AMDGPUAS::FLAT_ADDRESS) {2114 bool AlignedBy4 = Alignment >= Align(4);2115 if (Subtarget->hasUnalignedScratchAccessEnabled()) {2116 if (IsFast)2117 *IsFast = AlignedBy4 ? Size : 1;2118 return true;2119 }2120 2121 if (IsFast)2122 *IsFast = AlignedBy4;2123 2124 return AlignedBy4;2125 }2126 2127 // So long as they are correct, wide global memory operations perform better2128 // than multiple smaller memory ops -- even when misaligned2129 if (AMDGPU::isExtendedGlobalAddrSpace(AddrSpace)) {2130 if (IsFast)2131 *IsFast = Size;2132 2133 return Alignment >= Align(4) ||2134 Subtarget->hasUnalignedBufferAccessEnabled();2135 }2136 2137 // Ensure robust out-of-bounds guarantees for buffer accesses are met if2138 // RelaxedBufferOOBMode is disabled. Normally hardware will ensure proper2139 // out-of-bounds behavior, but in the edge case where an access starts2140 // out-of-bounds and then enter in-bounds, the entire access would be treated2141 // as out-of-bounds. Prevent misaligned memory accesses by requiring the2142 // natural alignment of buffer accesses.2143 if (AddrSpace == AMDGPUAS::BUFFER_FAT_POINTER ||2144 AddrSpace == AMDGPUAS::BUFFER_RESOURCE ||2145 AddrSpace == AMDGPUAS::BUFFER_STRIDED_POINTER) {2146 if (!Subtarget->hasRelaxedBufferOOBMode() &&2147 Alignment < Align(PowerOf2Ceil(divideCeil(Size, 8))))2148 return false;2149 }2150 2151 // Smaller than dword value must be aligned.2152 if (Size < 32)2153 return false;2154 2155 // 8.1.6 - For Dword or larger reads or writes, the two LSBs of the2156 // byte-address are ignored, thus forcing Dword alignment.2157 // This applies to private, global, and constant memory.2158 if (IsFast)2159 *IsFast = 1;2160 2161 return Size >= 32 && Alignment >= Align(4);2162}2163 2164bool SITargetLowering::allowsMisalignedMemoryAccesses(2165 EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,2166 unsigned *IsFast) const {2167 return allowsMisalignedMemoryAccessesImpl(VT.getSizeInBits(), AddrSpace,2168 Alignment, Flags, IsFast);2169}2170 2171EVT SITargetLowering::getOptimalMemOpType(2172 LLVMContext &Context, const MemOp &Op,2173 const AttributeList &FuncAttributes) const {2174 // FIXME: Should account for address space here.2175 2176 // The default fallback uses the private pointer size as a guess for a type to2177 // use. Make sure we switch these to 64-bit accesses.2178 2179 if (Op.size() >= 16 &&2180 Op.isDstAligned(Align(4))) // XXX: Should only do for global2181 return MVT::v4i32;2182 2183 if (Op.size() >= 8 && Op.isDstAligned(Align(4)))2184 return MVT::v2i32;2185 2186 // Use the default.2187 return MVT::Other;2188}2189 2190bool SITargetLowering::isMemOpHasNoClobberedMemOperand(const SDNode *N) const {2191 const MemSDNode *MemNode = cast<MemSDNode>(N);2192 return MemNode->getMemOperand()->getFlags() & MONoClobber;2193}2194 2195bool SITargetLowering::isNonGlobalAddrSpace(unsigned AS) {2196 return AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::REGION_ADDRESS ||2197 AS == AMDGPUAS::PRIVATE_ADDRESS;2198}2199 2200bool SITargetLowering::isFreeAddrSpaceCast(unsigned SrcAS,2201 unsigned DestAS) const {2202 if (SrcAS == AMDGPUAS::FLAT_ADDRESS) {2203 if (DestAS == AMDGPUAS::PRIVATE_ADDRESS &&2204 Subtarget->hasGloballyAddressableScratch()) {2205 // Flat -> private requires subtracting src_flat_scratch_base_lo.2206 return false;2207 }2208 2209 // Flat -> private/local is a simple truncate.2210 // Flat -> global is no-op2211 return true;2212 }2213 2214 const GCNTargetMachine &TM =2215 static_cast<const GCNTargetMachine &>(getTargetMachine());2216 return TM.isNoopAddrSpaceCast(SrcAS, DestAS);2217}2218 2219TargetLoweringBase::LegalizeTypeAction2220SITargetLowering::getPreferredVectorAction(MVT VT) const {2221 if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&2222 VT.getScalarType().bitsLE(MVT::i16))2223 return VT.isPow2VectorType() ? TypeSplitVector : TypeWidenVector;2224 return TargetLoweringBase::getPreferredVectorAction(VT);2225}2226 2227bool SITargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm,2228 Type *Ty) const {2229 // FIXME: Could be smarter if called for vector constants.2230 return true;2231}2232 2233bool SITargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,2234 unsigned Index) const {2235 if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT))2236 return false;2237 2238 // TODO: Add more cases that are cheap.2239 return Index == 0;2240}2241 2242bool SITargetLowering::isExtractVecEltCheap(EVT VT, unsigned Index) const {2243 // TODO: This should be more aggressive, particular for 16-bit element2244 // vectors. However there are some mixed improvements and regressions.2245 EVT EltTy = VT.getVectorElementType();2246 return EltTy.getSizeInBits() % 32 == 0;2247}2248 2249bool SITargetLowering::isTypeDesirableForOp(unsigned Op, EVT VT) const {2250 if (Subtarget->has16BitInsts() && VT == MVT::i16) {2251 switch (Op) {2252 case ISD::LOAD:2253 case ISD::STORE:2254 return true;2255 default:2256 return false;2257 }2258 }2259 2260 // SimplifySetCC uses this function to determine whether or not it should2261 // create setcc with i1 operands. We don't have instructions for i1 setcc.2262 if (VT == MVT::i1 && Op == ISD::SETCC)2263 return false;2264 2265 return TargetLowering::isTypeDesirableForOp(Op, VT);2266}2267 2268SDValue SITargetLowering::lowerKernArgParameterPtr(SelectionDAG &DAG,2269 const SDLoc &SL,2270 SDValue Chain,2271 uint64_t Offset) const {2272 const DataLayout &DL = DAG.getDataLayout();2273 MachineFunction &MF = DAG.getMachineFunction();2274 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();2275 MVT PtrVT = getPointerTy(DL, AMDGPUAS::CONSTANT_ADDRESS);2276 2277 auto [InputPtrReg, RC, ArgTy] =2278 Info->getPreloadedValue(AMDGPUFunctionArgInfo::KERNARG_SEGMENT_PTR);2279 2280 // We may not have the kernarg segment argument if we have no kernel2281 // arguments.2282 if (!InputPtrReg)2283 return DAG.getConstant(Offset, SL, PtrVT);2284 2285 MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();2286 SDValue BasePtr = DAG.getCopyFromReg(2287 Chain, SL, MRI.getLiveInVirtReg(InputPtrReg->getRegister()), PtrVT);2288 2289 return DAG.getObjectPtrOffset(SL, BasePtr, TypeSize::getFixed(Offset));2290}2291 2292SDValue SITargetLowering::getImplicitArgPtr(SelectionDAG &DAG,2293 const SDLoc &SL) const {2294 uint64_t Offset =2295 getImplicitParameterOffset(DAG.getMachineFunction(), FIRST_IMPLICIT);2296 return lowerKernArgParameterPtr(DAG, SL, DAG.getEntryNode(), Offset);2297}2298 2299SDValue SITargetLowering::getLDSKernelId(SelectionDAG &DAG,2300 const SDLoc &SL) const {2301 2302 Function &F = DAG.getMachineFunction().getFunction();2303 std::optional<uint32_t> KnownSize =2304 AMDGPUMachineFunction::getLDSKernelIdMetadata(F);2305 if (KnownSize.has_value())2306 return DAG.getConstant(*KnownSize, SL, MVT::i32);2307 return SDValue();2308}2309 2310SDValue SITargetLowering::convertArgType(SelectionDAG &DAG, EVT VT, EVT MemVT,2311 const SDLoc &SL, SDValue Val,2312 bool Signed,2313 const ISD::InputArg *Arg) const {2314 // First, if it is a widened vector, narrow it.2315 if (VT.isVector() &&2316 VT.getVectorNumElements() != MemVT.getVectorNumElements()) {2317 EVT NarrowedVT =2318 EVT::getVectorVT(*DAG.getContext(), MemVT.getVectorElementType(),2319 VT.getVectorNumElements());2320 Val = DAG.getNode(ISD::EXTRACT_SUBVECTOR, SL, NarrowedVT, Val,2321 DAG.getConstant(0, SL, MVT::i32));2322 }2323 2324 // Then convert the vector elements or scalar value.2325 if (Arg && (Arg->Flags.isSExt() || Arg->Flags.isZExt()) && VT.bitsLT(MemVT)) {2326 unsigned Opc = Arg->Flags.isZExt() ? ISD::AssertZext : ISD::AssertSext;2327 Val = DAG.getNode(Opc, SL, MemVT, Val, DAG.getValueType(VT));2328 }2329 2330 if (MemVT.isFloatingPoint())2331 Val = getFPExtOrFPRound(DAG, Val, SL, VT);2332 else if (Signed)2333 Val = DAG.getSExtOrTrunc(Val, SL, VT);2334 else2335 Val = DAG.getZExtOrTrunc(Val, SL, VT);2336 2337 return Val;2338}2339 2340SDValue SITargetLowering::lowerKernargMemParameter(2341 SelectionDAG &DAG, EVT VT, EVT MemVT, const SDLoc &SL, SDValue Chain,2342 uint64_t Offset, Align Alignment, bool Signed,2343 const ISD::InputArg *Arg) const {2344 MachinePointerInfo PtrInfo(AMDGPUAS::CONSTANT_ADDRESS);2345 2346 // Try to avoid using an extload by loading earlier than the argument address,2347 // and extracting the relevant bits. The load should hopefully be merged with2348 // the previous argument.2349 if (MemVT.getStoreSize() < 4 && Alignment < 4) {2350 // TODO: Handle align < 4 and size >= 4 (can happen with packed structs).2351 int64_t AlignDownOffset = alignDown(Offset, 4);2352 int64_t OffsetDiff = Offset - AlignDownOffset;2353 2354 EVT IntVT = MemVT.changeTypeToInteger();2355 2356 // TODO: If we passed in the base kernel offset we could have a better2357 // alignment than 4, but we don't really need it.2358 SDValue Ptr = lowerKernArgParameterPtr(DAG, SL, Chain, AlignDownOffset);2359 SDValue Load = DAG.getLoad(MVT::i32, SL, Chain, Ptr, PtrInfo, Align(4),2360 MachineMemOperand::MODereferenceable |2361 MachineMemOperand::MOInvariant);2362 2363 SDValue ShiftAmt = DAG.getConstant(OffsetDiff * 8, SL, MVT::i32);2364 SDValue Extract = DAG.getNode(ISD::SRL, SL, MVT::i32, Load, ShiftAmt);2365 2366 SDValue ArgVal = DAG.getNode(ISD::TRUNCATE, SL, IntVT, Extract);2367 ArgVal = DAG.getNode(ISD::BITCAST, SL, MemVT, ArgVal);2368 ArgVal = convertArgType(DAG, VT, MemVT, SL, ArgVal, Signed, Arg);2369 2370 return DAG.getMergeValues({ArgVal, Load.getValue(1)}, SL);2371 }2372 2373 SDValue Ptr = lowerKernArgParameterPtr(DAG, SL, Chain, Offset);2374 SDValue Load = DAG.getLoad(MemVT, SL, Chain, Ptr, PtrInfo, Alignment,2375 MachineMemOperand::MODereferenceable |2376 MachineMemOperand::MOInvariant);2377 2378 SDValue Val = convertArgType(DAG, VT, MemVT, SL, Load, Signed, Arg);2379 return DAG.getMergeValues({Val, Load.getValue(1)}, SL);2380}2381 2382/// Coerce an argument which was passed in a different ABI type to the original2383/// expected value type.2384SDValue SITargetLowering::convertABITypeToValueType(SelectionDAG &DAG,2385 SDValue Val,2386 CCValAssign &VA,2387 const SDLoc &SL) const {2388 EVT ValVT = VA.getValVT();2389 2390 // If this is an 8 or 16-bit value, it is really passed promoted2391 // to 32 bits. Insert an assert[sz]ext to capture this, then2392 // truncate to the right size.2393 switch (VA.getLocInfo()) {2394 case CCValAssign::Full:2395 return Val;2396 case CCValAssign::BCvt:2397 return DAG.getNode(ISD::BITCAST, SL, ValVT, Val);2398 case CCValAssign::SExt:2399 Val = DAG.getNode(ISD::AssertSext, SL, VA.getLocVT(), Val,2400 DAG.getValueType(ValVT));2401 return DAG.getNode(ISD::TRUNCATE, SL, ValVT, Val);2402 case CCValAssign::ZExt:2403 Val = DAG.getNode(ISD::AssertZext, SL, VA.getLocVT(), Val,2404 DAG.getValueType(ValVT));2405 return DAG.getNode(ISD::TRUNCATE, SL, ValVT, Val);2406 case CCValAssign::AExt:2407 return DAG.getNode(ISD::TRUNCATE, SL, ValVT, Val);2408 default:2409 llvm_unreachable("Unknown loc info!");2410 }2411}2412 2413SDValue SITargetLowering::lowerStackParameter(SelectionDAG &DAG,2414 CCValAssign &VA, const SDLoc &SL,2415 SDValue Chain,2416 const ISD::InputArg &Arg) const {2417 MachineFunction &MF = DAG.getMachineFunction();2418 MachineFrameInfo &MFI = MF.getFrameInfo();2419 2420 if (Arg.Flags.isByVal()) {2421 unsigned Size = Arg.Flags.getByValSize();2422 int FrameIdx = MFI.CreateFixedObject(Size, VA.getLocMemOffset(), false);2423 return DAG.getFrameIndex(FrameIdx, MVT::i32);2424 }2425 2426 unsigned ArgOffset = VA.getLocMemOffset();2427 unsigned ArgSize = VA.getValVT().getStoreSize();2428 2429 int FI = MFI.CreateFixedObject(ArgSize, ArgOffset, true);2430 2431 // Create load nodes to retrieve arguments from the stack.2432 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);2433 2434 // For NON_EXTLOAD, generic code in getLoad assert(ValVT == MemVT)2435 ISD::LoadExtType ExtType = ISD::NON_EXTLOAD;2436 MVT MemVT = VA.getValVT();2437 2438 switch (VA.getLocInfo()) {2439 default:2440 break;2441 case CCValAssign::BCvt:2442 MemVT = VA.getLocVT();2443 break;2444 case CCValAssign::SExt:2445 ExtType = ISD::SEXTLOAD;2446 break;2447 case CCValAssign::ZExt:2448 ExtType = ISD::ZEXTLOAD;2449 break;2450 case CCValAssign::AExt:2451 ExtType = ISD::EXTLOAD;2452 break;2453 }2454 2455 SDValue ArgValue = DAG.getExtLoad(2456 ExtType, SL, VA.getLocVT(), Chain, FIN,2457 MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), MemVT);2458 2459 SDValue ConvertedVal = convertABITypeToValueType(DAG, ArgValue, VA, SL);2460 if (ConvertedVal == ArgValue)2461 return ConvertedVal;2462 2463 return DAG.getMergeValues({ConvertedVal, ArgValue.getValue(1)}, SL);2464}2465 2466SDValue SITargetLowering::lowerWorkGroupId(2467 SelectionDAG &DAG, const SIMachineFunctionInfo &MFI, EVT VT,2468 AMDGPUFunctionArgInfo::PreloadedValue WorkGroupIdPV,2469 AMDGPUFunctionArgInfo::PreloadedValue ClusterMaxIdPV,2470 AMDGPUFunctionArgInfo::PreloadedValue ClusterWorkGroupIdPV) const {2471 if (!Subtarget->hasClusters())2472 return getPreloadedValue(DAG, MFI, VT, WorkGroupIdPV);2473 2474 // Clusters are supported. Return the global position in the grid. If clusters2475 // are enabled, WorkGroupIdPV returns the cluster ID not the workgroup ID.2476 2477 // WorkGroupIdXYZ = ClusterId == 0 ?2478 // ClusterIdXYZ :2479 // ClusterIdXYZ * (ClusterMaxIdXYZ + 1) + ClusterWorkGroupIdXYZ2480 SDValue ClusterIdXYZ = getPreloadedValue(DAG, MFI, VT, WorkGroupIdPV);2481 SDLoc SL(ClusterIdXYZ);2482 SDValue ClusterMaxIdXYZ = getPreloadedValue(DAG, MFI, VT, ClusterMaxIdPV);2483 SDValue One = DAG.getConstant(1, SL, VT);2484 SDValue ClusterSizeXYZ = DAG.getNode(ISD::ADD, SL, VT, ClusterMaxIdXYZ, One);2485 SDValue ClusterWorkGroupIdXYZ =2486 getPreloadedValue(DAG, MFI, VT, ClusterWorkGroupIdPV);2487 SDValue GlobalIdXYZ =2488 DAG.getNode(ISD::ADD, SL, VT, ClusterWorkGroupIdXYZ,2489 DAG.getNode(ISD::MUL, SL, VT, ClusterIdXYZ, ClusterSizeXYZ));2490 2491 switch (MFI.getClusterDims().getKind()) {2492 case AMDGPU::ClusterDimsAttr::Kind::FixedDims:2493 case AMDGPU::ClusterDimsAttr::Kind::VariableDims:2494 return GlobalIdXYZ;2495 case AMDGPU::ClusterDimsAttr::Kind::NoCluster:2496 return ClusterIdXYZ;2497 case AMDGPU::ClusterDimsAttr::Kind::Unknown: {2498 using namespace AMDGPU::Hwreg;2499 SDValue ClusterIdField =2500 DAG.getTargetConstant(HwregEncoding::encode(ID_IB_STS2, 6, 4), SL, VT);2501 SDNode *GetReg =2502 DAG.getMachineNode(AMDGPU::S_GETREG_B32_const, SL, VT, ClusterIdField);2503 SDValue ClusterId(GetReg, 0);2504 SDValue Zero = DAG.getConstant(0, SL, VT);2505 return DAG.getNode(ISD::SELECT_CC, SL, VT, ClusterId, Zero, ClusterIdXYZ,2506 GlobalIdXYZ, DAG.getCondCode(ISD::SETEQ));2507 }2508 }2509 2510 llvm_unreachable("nothing should reach here");2511}2512 2513SDValue SITargetLowering::getPreloadedValue(2514 SelectionDAG &DAG, const SIMachineFunctionInfo &MFI, EVT VT,2515 AMDGPUFunctionArgInfo::PreloadedValue PVID) const {2516 const ArgDescriptor *Reg = nullptr;2517 const TargetRegisterClass *RC;2518 LLT Ty;2519 2520 CallingConv::ID CC = DAG.getMachineFunction().getFunction().getCallingConv();2521 const ArgDescriptor WorkGroupIDX =2522 ArgDescriptor::createRegister(AMDGPU::TTMP9);2523 // If GridZ is not programmed in an entry function then the hardware will set2524 // it to all zeros, so there is no need to mask the GridY value in the low2525 // order bits.2526 const ArgDescriptor WorkGroupIDY = ArgDescriptor::createRegister(2527 AMDGPU::TTMP7,2528 AMDGPU::isEntryFunctionCC(CC) && !MFI.hasWorkGroupIDZ() ? ~0u : 0xFFFFu);2529 const ArgDescriptor WorkGroupIDZ =2530 ArgDescriptor::createRegister(AMDGPU::TTMP7, 0xFFFF0000u);2531 const ArgDescriptor ClusterWorkGroupIDX =2532 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0000000Fu);2533 const ArgDescriptor ClusterWorkGroupIDY =2534 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x000000F0u);2535 const ArgDescriptor ClusterWorkGroupIDZ =2536 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x00000F00u);2537 const ArgDescriptor ClusterWorkGroupMaxIDX =2538 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0000F000u);2539 const ArgDescriptor ClusterWorkGroupMaxIDY =2540 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x000F0000u);2541 const ArgDescriptor ClusterWorkGroupMaxIDZ =2542 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x00F00000u);2543 const ArgDescriptor ClusterWorkGroupMaxFlatID =2544 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0F000000u);2545 2546 auto LoadConstant = [&](unsigned N) {2547 return DAG.getConstant(N, SDLoc(), VT);2548 };2549 2550 if (Subtarget->hasArchitectedSGPRs() &&2551 (AMDGPU::isCompute(CC) || CC == CallingConv::AMDGPU_Gfx)) {2552 AMDGPU::ClusterDimsAttr ClusterDims = MFI.getClusterDims();2553 bool HasFixedDims = ClusterDims.isFixedDims();2554 2555 switch (PVID) {2556 case AMDGPUFunctionArgInfo::WORKGROUP_ID_X:2557 Reg = &WorkGroupIDX;2558 RC = &AMDGPU::SReg_32RegClass;2559 Ty = LLT::scalar(32);2560 break;2561 case AMDGPUFunctionArgInfo::WORKGROUP_ID_Y:2562 Reg = &WorkGroupIDY;2563 RC = &AMDGPU::SReg_32RegClass;2564 Ty = LLT::scalar(32);2565 break;2566 case AMDGPUFunctionArgInfo::WORKGROUP_ID_Z:2567 Reg = &WorkGroupIDZ;2568 RC = &AMDGPU::SReg_32RegClass;2569 Ty = LLT::scalar(32);2570 break;2571 case AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_ID_X:2572 if (HasFixedDims && ClusterDims.getDims()[0] == 1)2573 return LoadConstant(0);2574 Reg = &ClusterWorkGroupIDX;2575 RC = &AMDGPU::SReg_32RegClass;2576 Ty = LLT::scalar(32);2577 break;2578 case AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_ID_Y:2579 if (HasFixedDims && ClusterDims.getDims()[1] == 1)2580 return LoadConstant(0);2581 Reg = &ClusterWorkGroupIDY;2582 RC = &AMDGPU::SReg_32RegClass;2583 Ty = LLT::scalar(32);2584 break;2585 case AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_ID_Z:2586 if (HasFixedDims && ClusterDims.getDims()[2] == 1)2587 return LoadConstant(0);2588 Reg = &ClusterWorkGroupIDZ;2589 RC = &AMDGPU::SReg_32RegClass;2590 Ty = LLT::scalar(32);2591 break;2592 case AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_ID_X:2593 if (HasFixedDims)2594 return LoadConstant(ClusterDims.getDims()[0] - 1);2595 Reg = &ClusterWorkGroupMaxIDX;2596 RC = &AMDGPU::SReg_32RegClass;2597 Ty = LLT::scalar(32);2598 break;2599 case AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_ID_Y:2600 if (HasFixedDims)2601 return LoadConstant(ClusterDims.getDims()[1] - 1);2602 Reg = &ClusterWorkGroupMaxIDY;2603 RC = &AMDGPU::SReg_32RegClass;2604 Ty = LLT::scalar(32);2605 break;2606 case AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_ID_Z:2607 if (HasFixedDims)2608 return LoadConstant(ClusterDims.getDims()[2] - 1);2609 Reg = &ClusterWorkGroupMaxIDZ;2610 RC = &AMDGPU::SReg_32RegClass;2611 Ty = LLT::scalar(32);2612 break;2613 case AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_FLAT_ID:2614 Reg = &ClusterWorkGroupMaxFlatID;2615 RC = &AMDGPU::SReg_32RegClass;2616 Ty = LLT::scalar(32);2617 break;2618 default:2619 break;2620 }2621 }2622 2623 if (!Reg)2624 std::tie(Reg, RC, Ty) = MFI.getPreloadedValue(PVID);2625 if (!Reg) {2626 if (PVID == AMDGPUFunctionArgInfo::PreloadedValue::KERNARG_SEGMENT_PTR) {2627 // It's possible for a kernarg intrinsic call to appear in a kernel with2628 // no allocated segment, in which case we do not add the user sgpr2629 // argument, so just return null.2630 return DAG.getConstant(0, SDLoc(), VT);2631 }2632 2633 // It's undefined behavior if a function marked with the amdgpu-no-*2634 // attributes uses the corresponding intrinsic.2635 return DAG.getPOISON(VT);2636 }2637 2638 return loadInputValue(DAG, RC, VT, SDLoc(DAG.getEntryNode()), *Reg);2639}2640 2641static void processPSInputArgs(SmallVectorImpl<ISD::InputArg> &Splits,2642 CallingConv::ID CallConv,2643 ArrayRef<ISD::InputArg> Ins, BitVector &Skipped,2644 FunctionType *FType,2645 SIMachineFunctionInfo *Info) {2646 for (unsigned I = 0, E = Ins.size(), PSInputNum = 0; I != E; ++I) {2647 const ISD::InputArg *Arg = &Ins[I];2648 2649 assert((!Arg->VT.isVector() || Arg->VT.getScalarSizeInBits() == 16) &&2650 "vector type argument should have been split");2651 2652 // First check if it's a PS input addr.2653 if (CallConv == CallingConv::AMDGPU_PS && !Arg->Flags.isInReg() &&2654 PSInputNum <= 15) {2655 bool SkipArg = !Arg->Used && !Info->isPSInputAllocated(PSInputNum);2656 2657 // Inconveniently only the first part of the split is marked as isSplit,2658 // so skip to the end. We only want to increment PSInputNum once for the2659 // entire split argument.2660 if (Arg->Flags.isSplit()) {2661 while (!Arg->Flags.isSplitEnd()) {2662 assert((!Arg->VT.isVector() || Arg->VT.getScalarSizeInBits() == 16) &&2663 "unexpected vector split in ps argument type");2664 if (!SkipArg)2665 Splits.push_back(*Arg);2666 Arg = &Ins[++I];2667 }2668 }2669 2670 if (SkipArg) {2671 // We can safely skip PS inputs.2672 Skipped.set(Arg->getOrigArgIndex());2673 ++PSInputNum;2674 continue;2675 }2676 2677 Info->markPSInputAllocated(PSInputNum);2678 if (Arg->Used)2679 Info->markPSInputEnabled(PSInputNum);2680 2681 ++PSInputNum;2682 }2683 2684 Splits.push_back(*Arg);2685 }2686}2687 2688// Allocate special inputs passed in VGPRs.2689void SITargetLowering::allocateSpecialEntryInputVGPRs(2690 CCState &CCInfo, MachineFunction &MF, const SIRegisterInfo &TRI,2691 SIMachineFunctionInfo &Info) const {2692 const LLT S32 = LLT::scalar(32);2693 MachineRegisterInfo &MRI = MF.getRegInfo();2694 2695 if (Info.hasWorkItemIDX()) {2696 Register Reg = AMDGPU::VGPR0;2697 MRI.setType(MF.addLiveIn(Reg, &AMDGPU::VGPR_32RegClass), S32);2698 2699 CCInfo.AllocateReg(Reg);2700 unsigned Mask =2701 (Subtarget->hasPackedTID() && Info.hasWorkItemIDY()) ? 0x3ff : ~0u;2702 Info.setWorkItemIDX(ArgDescriptor::createRegister(Reg, Mask));2703 }2704 2705 if (Info.hasWorkItemIDY()) {2706 assert(Info.hasWorkItemIDX());2707 if (Subtarget->hasPackedTID()) {2708 Info.setWorkItemIDY(2709 ArgDescriptor::createRegister(AMDGPU::VGPR0, 0x3ff << 10));2710 } else {2711 unsigned Reg = AMDGPU::VGPR1;2712 MRI.setType(MF.addLiveIn(Reg, &AMDGPU::VGPR_32RegClass), S32);2713 2714 CCInfo.AllocateReg(Reg);2715 Info.setWorkItemIDY(ArgDescriptor::createRegister(Reg));2716 }2717 }2718 2719 if (Info.hasWorkItemIDZ()) {2720 assert(Info.hasWorkItemIDX() && Info.hasWorkItemIDY());2721 if (Subtarget->hasPackedTID()) {2722 Info.setWorkItemIDZ(2723 ArgDescriptor::createRegister(AMDGPU::VGPR0, 0x3ff << 20));2724 } else {2725 unsigned Reg = AMDGPU::VGPR2;2726 MRI.setType(MF.addLiveIn(Reg, &AMDGPU::VGPR_32RegClass), S32);2727 2728 CCInfo.AllocateReg(Reg);2729 Info.setWorkItemIDZ(ArgDescriptor::createRegister(Reg));2730 }2731 }2732}2733 2734// Try to allocate a VGPR at the end of the argument list, or if no argument2735// VGPRs are left allocating a stack slot.2736// If \p Mask is is given it indicates bitfield position in the register.2737// If \p Arg is given use it with new ]p Mask instead of allocating new.2738static ArgDescriptor allocateVGPR32Input(CCState &CCInfo, unsigned Mask = ~0u,2739 ArgDescriptor Arg = ArgDescriptor()) {2740 if (Arg.isSet())2741 return ArgDescriptor::createArg(Arg, Mask);2742 2743 ArrayRef<MCPhysReg> ArgVGPRs = ArrayRef(AMDGPU::VGPR_32RegClass.begin(), 32);2744 unsigned RegIdx = CCInfo.getFirstUnallocated(ArgVGPRs);2745 if (RegIdx == ArgVGPRs.size()) {2746 // Spill to stack required.2747 int64_t Offset = CCInfo.AllocateStack(4, Align(4));2748 2749 return ArgDescriptor::createStack(Offset, Mask);2750 }2751 2752 unsigned Reg = ArgVGPRs[RegIdx];2753 Reg = CCInfo.AllocateReg(Reg);2754 assert(Reg != AMDGPU::NoRegister);2755 2756 MachineFunction &MF = CCInfo.getMachineFunction();2757 Register LiveInVReg = MF.addLiveIn(Reg, &AMDGPU::VGPR_32RegClass);2758 MF.getRegInfo().setType(LiveInVReg, LLT::scalar(32));2759 return ArgDescriptor::createRegister(Reg, Mask);2760}2761 2762static ArgDescriptor allocateSGPR32InputImpl(CCState &CCInfo,2763 const TargetRegisterClass *RC,2764 unsigned NumArgRegs) {2765 ArrayRef<MCPhysReg> ArgSGPRs = ArrayRef(RC->begin(), 32);2766 unsigned RegIdx = CCInfo.getFirstUnallocated(ArgSGPRs);2767 if (RegIdx == ArgSGPRs.size())2768 report_fatal_error("ran out of SGPRs for arguments");2769 2770 unsigned Reg = ArgSGPRs[RegIdx];2771 Reg = CCInfo.AllocateReg(Reg);2772 assert(Reg != AMDGPU::NoRegister);2773 2774 MachineFunction &MF = CCInfo.getMachineFunction();2775 MF.addLiveIn(Reg, RC);2776 return ArgDescriptor::createRegister(Reg);2777}2778 2779// If this has a fixed position, we still should allocate the register in the2780// CCInfo state. Technically we could get away with this for values passed2781// outside of the normal argument range.2782static void allocateFixedSGPRInputImpl(CCState &CCInfo,2783 const TargetRegisterClass *RC,2784 MCRegister Reg) {2785 Reg = CCInfo.AllocateReg(Reg);2786 assert(Reg != AMDGPU::NoRegister);2787 MachineFunction &MF = CCInfo.getMachineFunction();2788 MF.addLiveIn(Reg, RC);2789}2790 2791static void allocateSGPR32Input(CCState &CCInfo, ArgDescriptor &Arg) {2792 if (Arg) {2793 allocateFixedSGPRInputImpl(CCInfo, &AMDGPU::SGPR_32RegClass,2794 Arg.getRegister());2795 } else2796 Arg = allocateSGPR32InputImpl(CCInfo, &AMDGPU::SGPR_32RegClass, 32);2797}2798 2799static void allocateSGPR64Input(CCState &CCInfo, ArgDescriptor &Arg) {2800 if (Arg) {2801 allocateFixedSGPRInputImpl(CCInfo, &AMDGPU::SGPR_64RegClass,2802 Arg.getRegister());2803 } else2804 Arg = allocateSGPR32InputImpl(CCInfo, &AMDGPU::SGPR_64RegClass, 16);2805}2806 2807/// Allocate implicit function VGPR arguments at the end of allocated user2808/// arguments.2809void SITargetLowering::allocateSpecialInputVGPRs(2810 CCState &CCInfo, MachineFunction &MF, const SIRegisterInfo &TRI,2811 SIMachineFunctionInfo &Info) const {2812 const unsigned Mask = 0x3ff;2813 ArgDescriptor Arg;2814 2815 if (Info.hasWorkItemIDX()) {2816 Arg = allocateVGPR32Input(CCInfo, Mask);2817 Info.setWorkItemIDX(Arg);2818 }2819 2820 if (Info.hasWorkItemIDY()) {2821 Arg = allocateVGPR32Input(CCInfo, Mask << 10, Arg);2822 Info.setWorkItemIDY(Arg);2823 }2824 2825 if (Info.hasWorkItemIDZ())2826 Info.setWorkItemIDZ(allocateVGPR32Input(CCInfo, Mask << 20, Arg));2827}2828 2829/// Allocate implicit function VGPR arguments in fixed registers.2830void SITargetLowering::allocateSpecialInputVGPRsFixed(2831 CCState &CCInfo, MachineFunction &MF, const SIRegisterInfo &TRI,2832 SIMachineFunctionInfo &Info) const {2833 Register Reg = CCInfo.AllocateReg(AMDGPU::VGPR31);2834 if (!Reg)2835 report_fatal_error("failed to allocate VGPR for implicit arguments");2836 2837 const unsigned Mask = 0x3ff;2838 Info.setWorkItemIDX(ArgDescriptor::createRegister(Reg, Mask));2839 Info.setWorkItemIDY(ArgDescriptor::createRegister(Reg, Mask << 10));2840 Info.setWorkItemIDZ(ArgDescriptor::createRegister(Reg, Mask << 20));2841}2842 2843void SITargetLowering::allocateSpecialInputSGPRs(2844 CCState &CCInfo, MachineFunction &MF, const SIRegisterInfo &TRI,2845 SIMachineFunctionInfo &Info) const {2846 auto &ArgInfo = Info.getArgInfo();2847 const GCNUserSGPRUsageInfo &UserSGPRInfo = Info.getUserSGPRInfo();2848 2849 // TODO: Unify handling with private memory pointers.2850 if (UserSGPRInfo.hasDispatchPtr())2851 allocateSGPR64Input(CCInfo, ArgInfo.DispatchPtr);2852 2853 if (UserSGPRInfo.hasQueuePtr())2854 allocateSGPR64Input(CCInfo, ArgInfo.QueuePtr);2855 2856 // Implicit arg ptr takes the place of the kernarg segment pointer. This is a2857 // constant offset from the kernarg segment.2858 if (Info.hasImplicitArgPtr())2859 allocateSGPR64Input(CCInfo, ArgInfo.ImplicitArgPtr);2860 2861 if (UserSGPRInfo.hasDispatchID())2862 allocateSGPR64Input(CCInfo, ArgInfo.DispatchID);2863 2864 // flat_scratch_init is not applicable for non-kernel functions.2865 2866 if (Info.hasWorkGroupIDX())2867 allocateSGPR32Input(CCInfo, ArgInfo.WorkGroupIDX);2868 2869 if (Info.hasWorkGroupIDY())2870 allocateSGPR32Input(CCInfo, ArgInfo.WorkGroupIDY);2871 2872 if (Info.hasWorkGroupIDZ())2873 allocateSGPR32Input(CCInfo, ArgInfo.WorkGroupIDZ);2874 2875 if (Info.hasLDSKernelId())2876 allocateSGPR32Input(CCInfo, ArgInfo.LDSKernelId);2877}2878 2879// Allocate special inputs passed in user SGPRs.2880void SITargetLowering::allocateHSAUserSGPRs(CCState &CCInfo,2881 MachineFunction &MF,2882 const SIRegisterInfo &TRI,2883 SIMachineFunctionInfo &Info) const {2884 const GCNUserSGPRUsageInfo &UserSGPRInfo = Info.getUserSGPRInfo();2885 if (UserSGPRInfo.hasImplicitBufferPtr()) {2886 Register ImplicitBufferPtrReg = Info.addImplicitBufferPtr(TRI);2887 MF.addLiveIn(ImplicitBufferPtrReg, &AMDGPU::SGPR_64RegClass);2888 CCInfo.AllocateReg(ImplicitBufferPtrReg);2889 }2890 2891 // FIXME: How should these inputs interact with inreg / custom SGPR inputs?2892 if (UserSGPRInfo.hasPrivateSegmentBuffer()) {2893 Register PrivateSegmentBufferReg = Info.addPrivateSegmentBuffer(TRI);2894 MF.addLiveIn(PrivateSegmentBufferReg, &AMDGPU::SGPR_128RegClass);2895 CCInfo.AllocateReg(PrivateSegmentBufferReg);2896 }2897 2898 if (UserSGPRInfo.hasDispatchPtr()) {2899 Register DispatchPtrReg = Info.addDispatchPtr(TRI);2900 MF.addLiveIn(DispatchPtrReg, &AMDGPU::SGPR_64RegClass);2901 CCInfo.AllocateReg(DispatchPtrReg);2902 }2903 2904 if (UserSGPRInfo.hasQueuePtr()) {2905 Register QueuePtrReg = Info.addQueuePtr(TRI);2906 MF.addLiveIn(QueuePtrReg, &AMDGPU::SGPR_64RegClass);2907 CCInfo.AllocateReg(QueuePtrReg);2908 }2909 2910 if (UserSGPRInfo.hasKernargSegmentPtr()) {2911 MachineRegisterInfo &MRI = MF.getRegInfo();2912 Register InputPtrReg = Info.addKernargSegmentPtr(TRI);2913 CCInfo.AllocateReg(InputPtrReg);2914 2915 Register VReg = MF.addLiveIn(InputPtrReg, &AMDGPU::SGPR_64RegClass);2916 MRI.setType(VReg, LLT::pointer(AMDGPUAS::CONSTANT_ADDRESS, 64));2917 }2918 2919 if (UserSGPRInfo.hasDispatchID()) {2920 Register DispatchIDReg = Info.addDispatchID(TRI);2921 MF.addLiveIn(DispatchIDReg, &AMDGPU::SGPR_64RegClass);2922 CCInfo.AllocateReg(DispatchIDReg);2923 }2924 2925 if (UserSGPRInfo.hasFlatScratchInit() && !getSubtarget()->isAmdPalOS()) {2926 Register FlatScratchInitReg = Info.addFlatScratchInit(TRI);2927 MF.addLiveIn(FlatScratchInitReg, &AMDGPU::SGPR_64RegClass);2928 CCInfo.AllocateReg(FlatScratchInitReg);2929 }2930 2931 if (UserSGPRInfo.hasPrivateSegmentSize()) {2932 Register PrivateSegmentSizeReg = Info.addPrivateSegmentSize(TRI);2933 MF.addLiveIn(PrivateSegmentSizeReg, &AMDGPU::SGPR_32RegClass);2934 CCInfo.AllocateReg(PrivateSegmentSizeReg);2935 }2936 2937 // TODO: Add GridWorkGroupCount user SGPRs when used. For now with HSA we read2938 // these from the dispatch pointer.2939}2940 2941// Allocate pre-loaded kernel arguemtns. Arguments to be preloading must be2942// sequential starting from the first argument.2943void SITargetLowering::allocatePreloadKernArgSGPRs(2944 CCState &CCInfo, SmallVectorImpl<CCValAssign> &ArgLocs,2945 const SmallVectorImpl<ISD::InputArg> &Ins, MachineFunction &MF,2946 const SIRegisterInfo &TRI, SIMachineFunctionInfo &Info) const {2947 Function &F = MF.getFunction();2948 unsigned LastExplicitArgOffset = Subtarget->getExplicitKernelArgOffset();2949 GCNUserSGPRUsageInfo &SGPRInfo = Info.getUserSGPRInfo();2950 bool InPreloadSequence = true;2951 unsigned InIdx = 0;2952 bool AlignedForImplictArgs = false;2953 unsigned ImplicitArgOffset = 0;2954 for (auto &Arg : F.args()) {2955 if (!InPreloadSequence || !Arg.hasInRegAttr())2956 break;2957 2958 unsigned ArgIdx = Arg.getArgNo();2959 // Don't preload non-original args or parts not in the current preload2960 // sequence.2961 if (InIdx < Ins.size() &&2962 (!Ins[InIdx].isOrigArg() || Ins[InIdx].getOrigArgIndex() != ArgIdx))2963 break;2964 2965 for (; InIdx < Ins.size() && Ins[InIdx].isOrigArg() &&2966 Ins[InIdx].getOrigArgIndex() == ArgIdx;2967 InIdx++) {2968 assert(ArgLocs[ArgIdx].isMemLoc());2969 auto &ArgLoc = ArgLocs[InIdx];2970 const Align KernelArgBaseAlign = Align(16);2971 unsigned ArgOffset = ArgLoc.getLocMemOffset();2972 Align Alignment = commonAlignment(KernelArgBaseAlign, ArgOffset);2973 unsigned NumAllocSGPRs =2974 alignTo(ArgLoc.getLocVT().getFixedSizeInBits(), 32) / 32;2975 2976 // Fix alignment for hidden arguments.2977 if (Arg.hasAttribute("amdgpu-hidden-argument")) {2978 if (!AlignedForImplictArgs) {2979 ImplicitArgOffset =2980 alignTo(LastExplicitArgOffset,2981 Subtarget->getAlignmentForImplicitArgPtr()) -2982 LastExplicitArgOffset;2983 AlignedForImplictArgs = true;2984 }2985 ArgOffset += ImplicitArgOffset;2986 }2987 2988 // Arg is preloaded into the previous SGPR.2989 if (ArgLoc.getLocVT().getStoreSize() < 4 && Alignment < 4) {2990 assert(InIdx >= 1 && "No previous SGPR");2991 Info.getArgInfo().PreloadKernArgs[InIdx].Regs.push_back(2992 Info.getArgInfo().PreloadKernArgs[InIdx - 1].Regs[0]);2993 continue;2994 }2995 2996 unsigned Padding = ArgOffset - LastExplicitArgOffset;2997 unsigned PaddingSGPRs = alignTo(Padding, 4) / 4;2998 // Check for free user SGPRs for preloading.2999 if (PaddingSGPRs + NumAllocSGPRs > SGPRInfo.getNumFreeUserSGPRs()) {3000 InPreloadSequence = false;3001 break;3002 }3003 3004 // Preload this argument.3005 const TargetRegisterClass *RC =3006 TRI.getSGPRClassForBitWidth(NumAllocSGPRs * 32);3007 SmallVectorImpl<MCRegister> *PreloadRegs =3008 Info.addPreloadedKernArg(TRI, RC, NumAllocSGPRs, InIdx, PaddingSGPRs);3009 3010 if (PreloadRegs->size() > 1)3011 RC = &AMDGPU::SGPR_32RegClass;3012 for (auto &Reg : *PreloadRegs) {3013 assert(Reg);3014 MF.addLiveIn(Reg, RC);3015 CCInfo.AllocateReg(Reg);3016 }3017 3018 LastExplicitArgOffset = NumAllocSGPRs * 4 + ArgOffset;3019 }3020 }3021}3022 3023void SITargetLowering::allocateLDSKernelId(CCState &CCInfo, MachineFunction &MF,3024 const SIRegisterInfo &TRI,3025 SIMachineFunctionInfo &Info) const {3026 // Always allocate this last since it is a synthetic preload.3027 if (Info.hasLDSKernelId()) {3028 Register Reg = Info.addLDSKernelId();3029 MF.addLiveIn(Reg, &AMDGPU::SGPR_32RegClass);3030 CCInfo.AllocateReg(Reg);3031 }3032}3033 3034// Allocate special input registers that are initialized per-wave.3035void SITargetLowering::allocateSystemSGPRs(CCState &CCInfo, MachineFunction &MF,3036 SIMachineFunctionInfo &Info,3037 CallingConv::ID CallConv,3038 bool IsShader) const {3039 bool HasArchitectedSGPRs = Subtarget->hasArchitectedSGPRs();3040 if (Subtarget->hasUserSGPRInit16Bug() && !IsShader) {3041 // Note: user SGPRs are handled by the front-end for graphics shaders3042 // Pad up the used user SGPRs with dead inputs.3043 3044 // TODO: NumRequiredSystemSGPRs computation should be adjusted appropriately3045 // before enabling architected SGPRs for workgroup IDs.3046 assert(!HasArchitectedSGPRs && "Unhandled feature for the subtarget");3047 3048 unsigned CurrentUserSGPRs = Info.getNumUserSGPRs();3049 // Note we do not count the PrivateSegmentWaveByteOffset. We do not want to3050 // rely on it to reach 16 since if we end up having no stack usage, it will3051 // not really be added.3052 unsigned NumRequiredSystemSGPRs =3053 Info.hasWorkGroupIDX() + Info.hasWorkGroupIDY() +3054 Info.hasWorkGroupIDZ() + Info.hasWorkGroupInfo();3055 for (unsigned i = NumRequiredSystemSGPRs + CurrentUserSGPRs; i < 16; ++i) {3056 Register Reg = Info.addReservedUserSGPR();3057 MF.addLiveIn(Reg, &AMDGPU::SGPR_32RegClass);3058 CCInfo.AllocateReg(Reg);3059 }3060 }3061 3062 if (!HasArchitectedSGPRs) {3063 if (Info.hasWorkGroupIDX()) {3064 Register Reg = Info.addWorkGroupIDX();3065 MF.addLiveIn(Reg, &AMDGPU::SGPR_32RegClass);3066 CCInfo.AllocateReg(Reg);3067 }3068 3069 if (Info.hasWorkGroupIDY()) {3070 Register Reg = Info.addWorkGroupIDY();3071 MF.addLiveIn(Reg, &AMDGPU::SGPR_32RegClass);3072 CCInfo.AllocateReg(Reg);3073 }3074 3075 if (Info.hasWorkGroupIDZ()) {3076 Register Reg = Info.addWorkGroupIDZ();3077 MF.addLiveIn(Reg, &AMDGPU::SGPR_32RegClass);3078 CCInfo.AllocateReg(Reg);3079 }3080 }3081 3082 if (Info.hasWorkGroupInfo()) {3083 Register Reg = Info.addWorkGroupInfo();3084 MF.addLiveIn(Reg, &AMDGPU::SGPR_32RegClass);3085 CCInfo.AllocateReg(Reg);3086 }3087 3088 if (Info.hasPrivateSegmentWaveByteOffset()) {3089 // Scratch wave offset passed in system SGPR.3090 unsigned PrivateSegmentWaveByteOffsetReg;3091 3092 if (IsShader) {3093 PrivateSegmentWaveByteOffsetReg =3094 Info.getPrivateSegmentWaveByteOffsetSystemSGPR();3095 3096 // This is true if the scratch wave byte offset doesn't have a fixed3097 // location.3098 if (PrivateSegmentWaveByteOffsetReg == AMDGPU::NoRegister) {3099 PrivateSegmentWaveByteOffsetReg = findFirstFreeSGPR(CCInfo);3100 Info.setPrivateSegmentWaveByteOffset(PrivateSegmentWaveByteOffsetReg);3101 }3102 } else3103 PrivateSegmentWaveByteOffsetReg = Info.addPrivateSegmentWaveByteOffset();3104 3105 MF.addLiveIn(PrivateSegmentWaveByteOffsetReg, &AMDGPU::SGPR_32RegClass);3106 CCInfo.AllocateReg(PrivateSegmentWaveByteOffsetReg);3107 }3108 3109 assert(!Subtarget->hasUserSGPRInit16Bug() || IsShader ||3110 Info.getNumPreloadedSGPRs() >= 16);3111}3112 3113static void reservePrivateMemoryRegs(const TargetMachine &TM,3114 MachineFunction &MF,3115 const SIRegisterInfo &TRI,3116 SIMachineFunctionInfo &Info) {3117 // Now that we've figured out where the scratch register inputs are, see if3118 // should reserve the arguments and use them directly.3119 MachineFrameInfo &MFI = MF.getFrameInfo();3120 bool HasStackObjects = MFI.hasStackObjects();3121 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();3122 3123 // Record that we know we have non-spill stack objects so we don't need to3124 // check all stack objects later.3125 if (HasStackObjects)3126 Info.setHasNonSpillStackObjects(true);3127 3128 // Everything live out of a block is spilled with fast regalloc, so it's3129 // almost certain that spilling will be required.3130 if (TM.getOptLevel() == CodeGenOptLevel::None)3131 HasStackObjects = true;3132 3133 // For now assume stack access is needed in any callee functions, so we need3134 // the scratch registers to pass in.3135 bool RequiresStackAccess = HasStackObjects || MFI.hasCalls();3136 3137 if (!ST.enableFlatScratch()) {3138 if (RequiresStackAccess && ST.isAmdHsaOrMesa(MF.getFunction())) {3139 // If we have stack objects, we unquestionably need the private buffer3140 // resource. For the Code Object V2 ABI, this will be the first 4 user3141 // SGPR inputs. We can reserve those and use them directly.3142 3143 Register PrivateSegmentBufferReg =3144 Info.getPreloadedReg(AMDGPUFunctionArgInfo::PRIVATE_SEGMENT_BUFFER);3145 Info.setScratchRSrcReg(PrivateSegmentBufferReg);3146 } else {3147 unsigned ReservedBufferReg = TRI.reservedPrivateSegmentBufferReg(MF);3148 // We tentatively reserve the last registers (skipping the last registers3149 // which may contain VCC, FLAT_SCR, and XNACK). After register allocation,3150 // we'll replace these with the ones immediately after those which were3151 // really allocated. In the prologue copies will be inserted from the3152 // argument to these reserved registers.3153 3154 // Without HSA, relocations are used for the scratch pointer and the3155 // buffer resource setup is always inserted in the prologue. Scratch wave3156 // offset is still in an input SGPR.3157 Info.setScratchRSrcReg(ReservedBufferReg);3158 }3159 }3160 3161 MachineRegisterInfo &MRI = MF.getRegInfo();3162 3163 // For entry functions we have to set up the stack pointer if we use it,3164 // whereas non-entry functions get this "for free". This means there is no3165 // intrinsic advantage to using S32 over S34 in cases where we do not have3166 // calls but do need a frame pointer (i.e. if we are requested to have one3167 // because frame pointer elimination is disabled). To keep things simple we3168 // only ever use S32 as the call ABI stack pointer, and so using it does not3169 // imply we need a separate frame pointer.3170 //3171 // Try to use s32 as the SP, but move it if it would interfere with input3172 // arguments. This won't work with calls though.3173 //3174 // FIXME: Move SP to avoid any possible inputs, or find a way to spill input3175 // registers.3176 if (!MRI.isLiveIn(AMDGPU::SGPR32)) {3177 Info.setStackPtrOffsetReg(AMDGPU::SGPR32);3178 } else {3179 assert(AMDGPU::isShader(MF.getFunction().getCallingConv()));3180 3181 if (MFI.hasCalls())3182 report_fatal_error("call in graphics shader with too many input SGPRs");3183 3184 for (unsigned Reg : AMDGPU::SGPR_32RegClass) {3185 if (!MRI.isLiveIn(Reg)) {3186 Info.setStackPtrOffsetReg(Reg);3187 break;3188 }3189 }3190 3191 if (Info.getStackPtrOffsetReg() == AMDGPU::SP_REG)3192 report_fatal_error("failed to find register for SP");3193 }3194 3195 // hasFP should be accurate for entry functions even before the frame is3196 // finalized, because it does not rely on the known stack size, only3197 // properties like whether variable sized objects are present.3198 if (ST.getFrameLowering()->hasFP(MF)) {3199 Info.setFrameOffsetReg(AMDGPU::SGPR33);3200 }3201}3202 3203bool SITargetLowering::supportSplitCSR(MachineFunction *MF) const {3204 const SIMachineFunctionInfo *Info = MF->getInfo<SIMachineFunctionInfo>();3205 return !Info->isEntryFunction();3206}3207 3208void SITargetLowering::initializeSplitCSR(MachineBasicBlock *Entry) const {}3209 3210void SITargetLowering::insertCopiesSplitCSR(3211 MachineBasicBlock *Entry,3212 const SmallVectorImpl<MachineBasicBlock *> &Exits) const {3213 const SIRegisterInfo *TRI = getSubtarget()->getRegisterInfo();3214 3215 const MCPhysReg *IStart = TRI->getCalleeSavedRegsViaCopy(Entry->getParent());3216 if (!IStart)3217 return;3218 3219 const TargetInstrInfo *TII = Subtarget->getInstrInfo();3220 MachineRegisterInfo *MRI = &Entry->getParent()->getRegInfo();3221 MachineBasicBlock::iterator MBBI = Entry->begin();3222 for (const MCPhysReg *I = IStart; *I; ++I) {3223 const TargetRegisterClass *RC = nullptr;3224 if (AMDGPU::SReg_64RegClass.contains(*I))3225 RC = &AMDGPU::SGPR_64RegClass;3226 else if (AMDGPU::SReg_32RegClass.contains(*I))3227 RC = &AMDGPU::SGPR_32RegClass;3228 else3229 llvm_unreachable("Unexpected register class in CSRsViaCopy!");3230 3231 Register NewVR = MRI->createVirtualRegister(RC);3232 // Create copy from CSR to a virtual register.3233 Entry->addLiveIn(*I);3234 BuildMI(*Entry, MBBI, DebugLoc(), TII->get(TargetOpcode::COPY), NewVR)3235 .addReg(*I);3236 3237 // Insert the copy-back instructions right before the terminator.3238 for (auto *Exit : Exits)3239 BuildMI(*Exit, Exit->getFirstTerminator(), DebugLoc(),3240 TII->get(TargetOpcode::COPY), *I)3241 .addReg(NewVR);3242 }3243}3244 3245SDValue SITargetLowering::LowerFormalArguments(3246 SDValue Chain, CallingConv::ID CallConv, bool isVarArg,3247 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,3248 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {3249 const SIRegisterInfo *TRI = getSubtarget()->getRegisterInfo();3250 3251 MachineFunction &MF = DAG.getMachineFunction();3252 const Function &Fn = MF.getFunction();3253 FunctionType *FType = MF.getFunction().getFunctionType();3254 SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();3255 bool IsError = false;3256 3257 if (Subtarget->isAmdHsaOS() && AMDGPU::isGraphics(CallConv)) {3258 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(3259 Fn, "unsupported non-compute shaders with HSA", DL.getDebugLoc()));3260 IsError = true;3261 }3262 3263 SmallVector<ISD::InputArg, 16> Splits;3264 SmallVector<CCValAssign, 16> ArgLocs;3265 BitVector Skipped(Ins.size());3266 CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,3267 *DAG.getContext());3268 3269 bool IsGraphics = AMDGPU::isGraphics(CallConv);3270 bool IsKernel = AMDGPU::isKernel(CallConv);3271 bool IsEntryFunc = AMDGPU::isEntryFunctionCC(CallConv);3272 3273 if (IsGraphics) {3274 const GCNUserSGPRUsageInfo &UserSGPRInfo = Info->getUserSGPRInfo();3275 assert(!UserSGPRInfo.hasDispatchPtr() &&3276 !UserSGPRInfo.hasKernargSegmentPtr() && !Info->hasWorkGroupInfo() &&3277 !Info->hasLDSKernelId() && !Info->hasWorkItemIDX() &&3278 !Info->hasWorkItemIDY() && !Info->hasWorkItemIDZ());3279 (void)UserSGPRInfo;3280 if (!Subtarget->enableFlatScratch())3281 assert(!UserSGPRInfo.hasFlatScratchInit());3282 if ((CallConv != CallingConv::AMDGPU_CS &&3283 CallConv != CallingConv::AMDGPU_Gfx &&3284 CallConv != CallingConv::AMDGPU_Gfx_WholeWave) ||3285 !Subtarget->hasArchitectedSGPRs())3286 assert(!Info->hasWorkGroupIDX() && !Info->hasWorkGroupIDY() &&3287 !Info->hasWorkGroupIDZ());3288 }3289 3290 bool IsWholeWaveFunc = Info->isWholeWaveFunction();3291 3292 if (CallConv == CallingConv::AMDGPU_PS) {3293 processPSInputArgs(Splits, CallConv, Ins, Skipped, FType, Info);3294 3295 // At least one interpolation mode must be enabled or else the GPU will3296 // hang.3297 //3298 // Check PSInputAddr instead of PSInputEnable. The idea is that if the user3299 // set PSInputAddr, the user wants to enable some bits after the compilation3300 // based on run-time states. Since we can't know what the final PSInputEna3301 // will look like, so we shouldn't do anything here and the user should take3302 // responsibility for the correct programming.3303 //3304 // Otherwise, the following restrictions apply:3305 // - At least one of PERSP_* (0xF) or LINEAR_* (0x70) must be enabled.3306 // - If POS_W_FLOAT (11) is enabled, at least one of PERSP_* must be3307 // enabled too.3308 if ((Info->getPSInputAddr() & 0x7F) == 0 ||3309 ((Info->getPSInputAddr() & 0xF) == 0 && Info->isPSInputAllocated(11))) {3310 CCInfo.AllocateReg(AMDGPU::VGPR0);3311 CCInfo.AllocateReg(AMDGPU::VGPR1);3312 Info->markPSInputAllocated(0);3313 Info->markPSInputEnabled(0);3314 }3315 if (Subtarget->isAmdPalOS()) {3316 // For isAmdPalOS, the user does not enable some bits after compilation3317 // based on run-time states; the register values being generated here are3318 // the final ones set in hardware. Therefore we need to apply the3319 // workaround to PSInputAddr and PSInputEnable together. (The case where3320 // a bit is set in PSInputAddr but not PSInputEnable is where the3321 // frontend set up an input arg for a particular interpolation mode, but3322 // nothing uses that input arg. Really we should have an earlier pass3323 // that removes such an arg.)3324 unsigned PsInputBits = Info->getPSInputAddr() & Info->getPSInputEnable();3325 if ((PsInputBits & 0x7F) == 0 ||3326 ((PsInputBits & 0xF) == 0 && (PsInputBits >> 11 & 1)))3327 Info->markPSInputEnabled(llvm::countr_zero(Info->getPSInputAddr()));3328 }3329 } else if (IsKernel) {3330 assert(Info->hasWorkGroupIDX() && Info->hasWorkItemIDX());3331 } else {3332 Splits.append(IsWholeWaveFunc ? std::next(Ins.begin()) : Ins.begin(),3333 Ins.end());3334 }3335 3336 if (IsKernel)3337 analyzeFormalArgumentsCompute(CCInfo, Ins);3338 3339 if (IsEntryFunc) {3340 allocateSpecialEntryInputVGPRs(CCInfo, MF, *TRI, *Info);3341 allocateHSAUserSGPRs(CCInfo, MF, *TRI, *Info);3342 if (IsKernel && Subtarget->hasKernargPreload())3343 allocatePreloadKernArgSGPRs(CCInfo, ArgLocs, Ins, MF, *TRI, *Info);3344 3345 allocateLDSKernelId(CCInfo, MF, *TRI, *Info);3346 } else if (!IsGraphics) {3347 // For the fixed ABI, pass workitem IDs in the last argument register.3348 allocateSpecialInputVGPRsFixed(CCInfo, MF, *TRI, *Info);3349 3350 // FIXME: Sink this into allocateSpecialInputSGPRs3351 if (!Subtarget->enableFlatScratch())3352 CCInfo.AllocateReg(Info->getScratchRSrcReg());3353 3354 allocateSpecialInputSGPRs(CCInfo, MF, *TRI, *Info);3355 }3356 3357 if (!IsKernel) {3358 CCAssignFn *AssignFn = CCAssignFnForCall(CallConv, isVarArg);3359 CCInfo.AnalyzeFormalArguments(Splits, AssignFn);3360 3361 // This assumes the registers are allocated by CCInfo in ascending order3362 // with no gaps.3363 Info->setNumWaveDispatchSGPRs(3364 CCInfo.getFirstUnallocated(AMDGPU::SGPR_32RegClass.getRegisters()));3365 Info->setNumWaveDispatchVGPRs(3366 CCInfo.getFirstUnallocated(AMDGPU::VGPR_32RegClass.getRegisters()));3367 } else if (Info->getNumKernargPreloadedSGPRs()) {3368 Info->setNumWaveDispatchSGPRs(Info->getNumUserSGPRs());3369 }3370 3371 SmallVector<SDValue, 16> Chains;3372 3373 if (IsWholeWaveFunc) {3374 SDValue Setup = DAG.getNode(AMDGPUISD::WHOLE_WAVE_SETUP, DL,3375 {MVT::i1, MVT::Other}, Chain);3376 InVals.push_back(Setup.getValue(0));3377 Chains.push_back(Setup.getValue(1));3378 }3379 3380 // FIXME: This is the minimum kernel argument alignment. We should improve3381 // this to the maximum alignment of the arguments.3382 //3383 // FIXME: Alignment of explicit arguments totally broken with non-0 explicit3384 // kern arg offset.3385 const Align KernelArgBaseAlign = Align(16);3386 3387 for (unsigned i = IsWholeWaveFunc ? 1 : 0, e = Ins.size(), ArgIdx = 0; i != e;3388 ++i) {3389 const ISD::InputArg &Arg = Ins[i];3390 if ((Arg.isOrigArg() && Skipped[Arg.getOrigArgIndex()]) || IsError) {3391 InVals.push_back(DAG.getPOISON(Arg.VT));3392 continue;3393 }3394 3395 CCValAssign &VA = ArgLocs[ArgIdx++];3396 MVT VT = VA.getLocVT();3397 3398 if (IsEntryFunc && VA.isMemLoc()) {3399 VT = Ins[i].VT;3400 EVT MemVT = VA.getLocVT();3401 3402 const uint64_t Offset = VA.getLocMemOffset();3403 Align Alignment = commonAlignment(KernelArgBaseAlign, Offset);3404 3405 if (Arg.Flags.isByRef()) {3406 SDValue Ptr = lowerKernArgParameterPtr(DAG, DL, Chain, Offset);3407 3408 const GCNTargetMachine &TM =3409 static_cast<const GCNTargetMachine &>(getTargetMachine());3410 if (!TM.isNoopAddrSpaceCast(AMDGPUAS::CONSTANT_ADDRESS,3411 Arg.Flags.getPointerAddrSpace())) {3412 Ptr = DAG.getAddrSpaceCast(DL, VT, Ptr, AMDGPUAS::CONSTANT_ADDRESS,3413 Arg.Flags.getPointerAddrSpace());3414 }3415 3416 InVals.push_back(Ptr);3417 continue;3418 }3419 3420 SDValue NewArg;3421 if (Arg.isOrigArg() && Info->getArgInfo().PreloadKernArgs.count(i)) {3422 if (MemVT.getStoreSize() < 4 && Alignment < 4) {3423 // In this case the argument is packed into the previous preload SGPR.3424 int64_t AlignDownOffset = alignDown(Offset, 4);3425 int64_t OffsetDiff = Offset - AlignDownOffset;3426 EVT IntVT = MemVT.changeTypeToInteger();3427 3428 const SIMachineFunctionInfo *Info =3429 MF.getInfo<SIMachineFunctionInfo>();3430 MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();3431 Register Reg =3432 Info->getArgInfo().PreloadKernArgs.find(i)->getSecond().Regs[0];3433 3434 assert(Reg);3435 Register VReg = MRI.getLiveInVirtReg(Reg);3436 SDValue Copy = DAG.getCopyFromReg(Chain, DL, VReg, MVT::i32);3437 3438 SDValue ShiftAmt = DAG.getConstant(OffsetDiff * 8, DL, MVT::i32);3439 SDValue Extract = DAG.getNode(ISD::SRL, DL, MVT::i32, Copy, ShiftAmt);3440 3441 SDValue ArgVal = DAG.getNode(ISD::TRUNCATE, DL, IntVT, Extract);3442 ArgVal = DAG.getNode(ISD::BITCAST, DL, MemVT, ArgVal);3443 NewArg = convertArgType(DAG, VT, MemVT, DL, ArgVal,3444 Ins[i].Flags.isSExt(), &Ins[i]);3445 3446 NewArg = DAG.getMergeValues({NewArg, Copy.getValue(1)}, DL);3447 } else {3448 const SIMachineFunctionInfo *Info =3449 MF.getInfo<SIMachineFunctionInfo>();3450 MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();3451 const SmallVectorImpl<MCRegister> &PreloadRegs =3452 Info->getArgInfo().PreloadKernArgs.find(i)->getSecond().Regs;3453 3454 SDValue Copy;3455 if (PreloadRegs.size() == 1) {3456 Register VReg = MRI.getLiveInVirtReg(PreloadRegs[0]);3457 const TargetRegisterClass *RC = MRI.getRegClass(VReg);3458 NewArg = DAG.getCopyFromReg(3459 Chain, DL, VReg,3460 EVT::getIntegerVT(*DAG.getContext(),3461 TRI->getRegSizeInBits(*RC)));3462 3463 } else {3464 // If the kernarg alignment does not match the alignment of the SGPR3465 // tuple RC that can accommodate this argument, it will be built up3466 // via copies from from the individual SGPRs that the argument was3467 // preloaded to.3468 SmallVector<SDValue, 4> Elts;3469 for (auto Reg : PreloadRegs) {3470 Register VReg = MRI.getLiveInVirtReg(Reg);3471 Copy = DAG.getCopyFromReg(Chain, DL, VReg, MVT::i32);3472 Elts.push_back(Copy);3473 }3474 NewArg =3475 DAG.getBuildVector(EVT::getVectorVT(*DAG.getContext(), MVT::i32,3476 PreloadRegs.size()),3477 DL, Elts);3478 }3479 3480 // If the argument was preloaded to multiple consecutive 32-bit3481 // registers because of misalignment between addressable SGPR tuples3482 // and the argument size, we can still assume that because of kernarg3483 // segment alignment restrictions that NewArg's size is the same as3484 // MemVT and just do a bitcast. If MemVT is less than 32-bits we add a3485 // truncate since we cannot preload to less than a single SGPR and the3486 // MemVT may be smaller.3487 EVT MemVTInt =3488 EVT::getIntegerVT(*DAG.getContext(), MemVT.getSizeInBits());3489 if (MemVT.bitsLT(NewArg.getSimpleValueType()))3490 NewArg = DAG.getNode(ISD::TRUNCATE, DL, MemVTInt, NewArg);3491 3492 NewArg = DAG.getBitcast(MemVT, NewArg);3493 NewArg = convertArgType(DAG, VT, MemVT, DL, NewArg,3494 Ins[i].Flags.isSExt(), &Ins[i]);3495 NewArg = DAG.getMergeValues({NewArg, Chain}, DL);3496 }3497 } else {3498 // Hidden arguments that are in the kernel signature must be preloaded3499 // to user SGPRs. Print a diagnostic error if a hidden argument is in3500 // the argument list and is not preloaded.3501 if (Arg.isOrigArg()) {3502 Argument *OrigArg = Fn.getArg(Arg.getOrigArgIndex());3503 if (OrigArg->hasAttribute("amdgpu-hidden-argument")) {3504 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(3505 *OrigArg->getParent(),3506 "hidden argument in kernel signature was not preloaded",3507 DL.getDebugLoc()));3508 }3509 }3510 3511 NewArg =3512 lowerKernargMemParameter(DAG, VT, MemVT, DL, Chain, Offset,3513 Alignment, Ins[i].Flags.isSExt(), &Ins[i]);3514 }3515 Chains.push_back(NewArg.getValue(1));3516 3517 auto *ParamTy =3518 dyn_cast<PointerType>(FType->getParamType(Ins[i].getOrigArgIndex()));3519 if (Subtarget->getGeneration() == AMDGPUSubtarget::SOUTHERN_ISLANDS &&3520 ParamTy &&3521 (ParamTy->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS ||3522 ParamTy->getAddressSpace() == AMDGPUAS::REGION_ADDRESS)) {3523 // On SI local pointers are just offsets into LDS, so they are always3524 // less than 16-bits. On CI and newer they could potentially be3525 // real pointers, so we can't guarantee their size.3526 NewArg = DAG.getNode(ISD::AssertZext, DL, NewArg.getValueType(), NewArg,3527 DAG.getValueType(MVT::i16));3528 }3529 3530 InVals.push_back(NewArg);3531 continue;3532 }3533 if (!IsEntryFunc && VA.isMemLoc()) {3534 SDValue Val = lowerStackParameter(DAG, VA, DL, Chain, Arg);3535 InVals.push_back(Val);3536 if (!Arg.Flags.isByVal())3537 Chains.push_back(Val.getValue(1));3538 continue;3539 }3540 3541 assert(VA.isRegLoc() && "Parameter must be in a register!");3542 3543 Register Reg = VA.getLocReg();3544 const TargetRegisterClass *RC = nullptr;3545 if (AMDGPU::VGPR_32RegClass.contains(Reg))3546 RC = &AMDGPU::VGPR_32RegClass;3547 else if (AMDGPU::SGPR_32RegClass.contains(Reg))3548 RC = &AMDGPU::SGPR_32RegClass;3549 else3550 llvm_unreachable("Unexpected register class in LowerFormalArguments!");3551 3552 Reg = MF.addLiveIn(Reg, RC);3553 SDValue Val = DAG.getCopyFromReg(Chain, DL, Reg, VT);3554 3555 if (Arg.Flags.isSRet()) {3556 // The return object should be reasonably addressable.3557 3558 // FIXME: This helps when the return is a real sret. If it is a3559 // automatically inserted sret (i.e. CanLowerReturn returns false), an3560 // extra copy is inserted in SelectionDAGBuilder which obscures this.3561 unsigned NumBits =3562 32 - getSubtarget()->getKnownHighZeroBitsForFrameIndex();3563 Val = DAG.getNode(3564 ISD::AssertZext, DL, VT, Val,3565 DAG.getValueType(EVT::getIntegerVT(*DAG.getContext(), NumBits)));3566 }3567 3568 Val = convertABITypeToValueType(DAG, Val, VA, DL);3569 InVals.push_back(Val);3570 }3571 3572 // Start adding system SGPRs.3573 if (IsEntryFunc)3574 allocateSystemSGPRs(CCInfo, MF, *Info, CallConv, IsGraphics);3575 3576 // DAG.getPass() returns nullptr when using new pass manager.3577 // TODO: Use DAG.getMFAM() to access analysis result.3578 if (DAG.getPass()) {3579 auto &ArgUsageInfo = DAG.getPass()->getAnalysis<AMDGPUArgumentUsageInfo>();3580 ArgUsageInfo.setFuncArgInfo(Fn, Info->getArgInfo());3581 }3582 3583 unsigned StackArgSize = CCInfo.getStackSize();3584 Info->setBytesInStackArgArea(StackArgSize);3585 3586 return Chains.empty() ? Chain3587 : DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains);3588}3589 3590// TODO: If return values can't fit in registers, we should return as many as3591// possible in registers before passing on stack.3592bool SITargetLowering::CanLowerReturn(3593 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,3594 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,3595 const Type *RetTy) const {3596 // Replacing returns with sret/stack usage doesn't make sense for shaders.3597 // FIXME: Also sort of a workaround for custom vector splitting in LowerReturn3598 // for shaders. Vector types should be explicitly handled by CC.3599 if (AMDGPU::isEntryFunctionCC(CallConv))3600 return true;3601 3602 SmallVector<CCValAssign, 16> RVLocs;3603 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);3604 if (!CCInfo.CheckReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg)))3605 return false;3606 3607 // We must use the stack if return would require unavailable registers.3608 unsigned MaxNumVGPRs = Subtarget->getMaxNumVGPRs(MF);3609 unsigned TotalNumVGPRs = Subtarget->getAddressableNumArchVGPRs();3610 for (unsigned i = MaxNumVGPRs; i < TotalNumVGPRs; ++i)3611 if (CCInfo.isAllocated(AMDGPU::VGPR_32RegClass.getRegister(i)))3612 return false;3613 3614 return true;3615}3616 3617SDValue3618SITargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,3619 bool isVarArg,3620 const SmallVectorImpl<ISD::OutputArg> &Outs,3621 const SmallVectorImpl<SDValue> &OutVals,3622 const SDLoc &DL, SelectionDAG &DAG) const {3623 MachineFunction &MF = DAG.getMachineFunction();3624 SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();3625 const SIRegisterInfo *TRI = getSubtarget()->getRegisterInfo();3626 3627 if (AMDGPU::isKernel(CallConv)) {3628 return AMDGPUTargetLowering::LowerReturn(Chain, CallConv, isVarArg, Outs,3629 OutVals, DL, DAG);3630 }3631 3632 bool IsShader = AMDGPU::isShader(CallConv);3633 3634 Info->setIfReturnsVoid(Outs.empty());3635 bool IsWaveEnd = Info->returnsVoid() && IsShader;3636 3637 // CCValAssign - represent the assignment of the return value to a location.3638 SmallVector<CCValAssign, 48> RVLocs;3639 3640 // CCState - Info about the registers and stack slots.3641 CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,3642 *DAG.getContext());3643 3644 // Analyze outgoing return values.3645 CCInfo.AnalyzeReturn(Outs, CCAssignFnForReturn(CallConv, isVarArg));3646 3647 SDValue Glue;3648 SmallVector<SDValue, 48> RetOps;3649 RetOps.push_back(Chain); // Operand #0 = Chain (updated below)3650 3651 SDValue ReadFirstLane =3652 DAG.getTargetConstant(Intrinsic::amdgcn_readfirstlane, DL, MVT::i32);3653 // Copy the result values into the output registers.3654 for (unsigned I = 0, RealRVLocIdx = 0, E = RVLocs.size(); I != E;3655 ++I, ++RealRVLocIdx) {3656 CCValAssign &VA = RVLocs[I];3657 assert(VA.isRegLoc() && "Can only return in registers!");3658 // TODO: Partially return in registers if return values don't fit.3659 SDValue Arg = OutVals[RealRVLocIdx];3660 3661 // Copied from other backends.3662 switch (VA.getLocInfo()) {3663 case CCValAssign::Full:3664 break;3665 case CCValAssign::BCvt:3666 Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg);3667 break;3668 case CCValAssign::SExt:3669 Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg);3670 break;3671 case CCValAssign::ZExt:3672 Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg);3673 break;3674 case CCValAssign::AExt:3675 Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg);3676 break;3677 default:3678 llvm_unreachable("Unknown loc info!");3679 }3680 if (TRI->isSGPRPhysReg(VA.getLocReg()))3681 Arg = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, Arg.getValueType(),3682 ReadFirstLane, Arg);3683 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Arg, Glue);3684 Glue = Chain.getValue(1);3685 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));3686 }3687 3688 // FIXME: Does sret work properly?3689 if (!Info->isEntryFunction()) {3690 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();3691 const MCPhysReg *I =3692 TRI->getCalleeSavedRegsViaCopy(&DAG.getMachineFunction());3693 if (I) {3694 for (; *I; ++I) {3695 if (AMDGPU::SReg_64RegClass.contains(*I))3696 RetOps.push_back(DAG.getRegister(*I, MVT::i64));3697 else if (AMDGPU::SReg_32RegClass.contains(*I))3698 RetOps.push_back(DAG.getRegister(*I, MVT::i32));3699 else3700 llvm_unreachable("Unexpected register class in CSRsViaCopy!");3701 }3702 }3703 }3704 3705 // Update chain and glue.3706 RetOps[0] = Chain;3707 if (Glue.getNode())3708 RetOps.push_back(Glue);3709 3710 unsigned Opc = AMDGPUISD::ENDPGM;3711 if (!IsWaveEnd)3712 Opc = Info->isWholeWaveFunction() ? AMDGPUISD::WHOLE_WAVE_RETURN3713 : IsShader ? AMDGPUISD::RETURN_TO_EPILOG3714 : AMDGPUISD::RET_GLUE;3715 return DAG.getNode(Opc, DL, MVT::Other, RetOps);3716}3717 3718SDValue SITargetLowering::LowerCallResult(3719 SDValue Chain, SDValue InGlue, CallingConv::ID CallConv, bool IsVarArg,3720 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,3721 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals, bool IsThisReturn,3722 SDValue ThisVal) const {3723 CCAssignFn *RetCC = CCAssignFnForReturn(CallConv, IsVarArg);3724 3725 // Assign locations to each value returned by this call.3726 SmallVector<CCValAssign, 16> RVLocs;3727 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,3728 *DAG.getContext());3729 CCInfo.AnalyzeCallResult(Ins, RetCC);3730 3731 // Copy all of the result registers out of their specified physreg.3732 for (CCValAssign VA : RVLocs) {3733 SDValue Val;3734 3735 if (VA.isRegLoc()) {3736 Val =3737 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), InGlue);3738 Chain = Val.getValue(1);3739 InGlue = Val.getValue(2);3740 } else if (VA.isMemLoc()) {3741 report_fatal_error("TODO: return values in memory");3742 } else3743 llvm_unreachable("unknown argument location type");3744 3745 switch (VA.getLocInfo()) {3746 case CCValAssign::Full:3747 break;3748 case CCValAssign::BCvt:3749 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);3750 break;3751 case CCValAssign::ZExt:3752 Val = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Val,3753 DAG.getValueType(VA.getValVT()));3754 Val = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Val);3755 break;3756 case CCValAssign::SExt:3757 Val = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Val,3758 DAG.getValueType(VA.getValVT()));3759 Val = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Val);3760 break;3761 case CCValAssign::AExt:3762 Val = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Val);3763 break;3764 default:3765 llvm_unreachable("Unknown loc info!");3766 }3767 3768 InVals.push_back(Val);3769 }3770 3771 return Chain;3772}3773 3774// Add code to pass special inputs required depending on used features separate3775// from the explicit user arguments present in the IR.3776void SITargetLowering::passSpecialInputs(3777 CallLoweringInfo &CLI, CCState &CCInfo, const SIMachineFunctionInfo &Info,3778 SmallVectorImpl<std::pair<unsigned, SDValue>> &RegsToPass,3779 SmallVectorImpl<SDValue> &MemOpChains, SDValue Chain) const {3780 // If we don't have a call site, this was a call inserted by3781 // legalization. These can never use special inputs.3782 if (!CLI.CB)3783 return;3784 3785 SelectionDAG &DAG = CLI.DAG;3786 const SDLoc &DL = CLI.DL;3787 const Function &F = DAG.getMachineFunction().getFunction();3788 3789 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();3790 const AMDGPUFunctionArgInfo &CallerArgInfo = Info.getArgInfo();3791 3792 const AMDGPUFunctionArgInfo *CalleeArgInfo =3793 &AMDGPUArgumentUsageInfo::FixedABIFunctionInfo;3794 if (const Function *CalleeFunc = CLI.CB->getCalledFunction()) {3795 // DAG.getPass() returns nullptr when using new pass manager.3796 // TODO: Use DAG.getMFAM() to access analysis result.3797 if (DAG.getPass()) {3798 auto &ArgUsageInfo =3799 DAG.getPass()->getAnalysis<AMDGPUArgumentUsageInfo>();3800 CalleeArgInfo = &ArgUsageInfo.lookupFuncArgInfo(*CalleeFunc);3801 }3802 }3803 3804 // TODO: Unify with private memory register handling. This is complicated by3805 // the fact that at least in kernels, the input argument is not necessarily3806 // in the same location as the input.3807 // clang-format off3808 static constexpr std::pair<AMDGPUFunctionArgInfo::PreloadedValue,3809 std::array<StringLiteral, 2>> ImplicitAttrs[] = {3810 {AMDGPUFunctionArgInfo::DISPATCH_PTR, {"amdgpu-no-dispatch-ptr", ""}},3811 {AMDGPUFunctionArgInfo::QUEUE_PTR, {"amdgpu-no-queue-ptr", ""}},3812 {AMDGPUFunctionArgInfo::IMPLICIT_ARG_PTR, {"amdgpu-no-implicitarg-ptr", ""}},3813 {AMDGPUFunctionArgInfo::DISPATCH_ID, {"amdgpu-no-dispatch-id", ""}},3814 {AMDGPUFunctionArgInfo::WORKGROUP_ID_X, {"amdgpu-no-workgroup-id-x", "amdgpu-no-cluster-id-x"}},3815 {AMDGPUFunctionArgInfo::WORKGROUP_ID_Y, {"amdgpu-no-workgroup-id-y", "amdgpu-no-cluster-id-y"}},3816 {AMDGPUFunctionArgInfo::WORKGROUP_ID_Z, {"amdgpu-no-workgroup-id-z", "amdgpu-no-cluster-id-z"}},3817 {AMDGPUFunctionArgInfo::LDS_KERNEL_ID, {"amdgpu-no-lds-kernel-id", ""}},3818 };3819 // clang-format on3820 3821 for (auto [InputID, Attrs] : ImplicitAttrs) {3822 // If the callee does not use the attribute value, skip copying the value.3823 if (all_of(Attrs, [&](StringRef Attr) {3824 return Attr.empty() || CLI.CB->hasFnAttr(Attr);3825 }))3826 continue;3827 3828 const auto [OutgoingArg, ArgRC, ArgTy] =3829 CalleeArgInfo->getPreloadedValue(InputID);3830 if (!OutgoingArg)3831 continue;3832 3833 const auto [IncomingArg, IncomingArgRC, Ty] =3834 CallerArgInfo.getPreloadedValue(InputID);3835 assert(IncomingArgRC == ArgRC);3836 3837 // All special arguments are ints for now.3838 EVT ArgVT = TRI->getSpillSize(*ArgRC) == 8 ? MVT::i64 : MVT::i32;3839 SDValue InputReg;3840 3841 if (IncomingArg) {3842 InputReg = loadInputValue(DAG, ArgRC, ArgVT, DL, *IncomingArg);3843 } else if (InputID == AMDGPUFunctionArgInfo::IMPLICIT_ARG_PTR) {3844 // The implicit arg ptr is special because it doesn't have a corresponding3845 // input for kernels, and is computed from the kernarg segment pointer.3846 InputReg = getImplicitArgPtr(DAG, DL);3847 } else if (InputID == AMDGPUFunctionArgInfo::LDS_KERNEL_ID) {3848 std::optional<uint32_t> Id =3849 AMDGPUMachineFunction::getLDSKernelIdMetadata(F);3850 if (Id.has_value()) {3851 InputReg = DAG.getConstant(*Id, DL, ArgVT);3852 } else {3853 InputReg = DAG.getPOISON(ArgVT);3854 }3855 } else {3856 // We may have proven the input wasn't needed, although the ABI is3857 // requiring it. We just need to allocate the register appropriately.3858 InputReg = DAG.getPOISON(ArgVT);3859 }3860 3861 if (OutgoingArg->isRegister()) {3862 RegsToPass.emplace_back(OutgoingArg->getRegister(), InputReg);3863 if (!CCInfo.AllocateReg(OutgoingArg->getRegister()))3864 report_fatal_error("failed to allocate implicit input argument");3865 } else {3866 unsigned SpecialArgOffset =3867 CCInfo.AllocateStack(ArgVT.getStoreSize(), Align(4));3868 SDValue ArgStore =3869 storeStackInputValue(DAG, DL, Chain, InputReg, SpecialArgOffset);3870 MemOpChains.push_back(ArgStore);3871 }3872 }3873 3874 // Pack workitem IDs into a single register or pass it as is if already3875 // packed.3876 3877 auto [OutgoingArg, ArgRC, Ty] =3878 CalleeArgInfo->getPreloadedValue(AMDGPUFunctionArgInfo::WORKITEM_ID_X);3879 if (!OutgoingArg)3880 std::tie(OutgoingArg, ArgRC, Ty) =3881 CalleeArgInfo->getPreloadedValue(AMDGPUFunctionArgInfo::WORKITEM_ID_Y);3882 if (!OutgoingArg)3883 std::tie(OutgoingArg, ArgRC, Ty) =3884 CalleeArgInfo->getPreloadedValue(AMDGPUFunctionArgInfo::WORKITEM_ID_Z);3885 if (!OutgoingArg)3886 return;3887 3888 const ArgDescriptor *IncomingArgX = std::get<0>(3889 CallerArgInfo.getPreloadedValue(AMDGPUFunctionArgInfo::WORKITEM_ID_X));3890 const ArgDescriptor *IncomingArgY = std::get<0>(3891 CallerArgInfo.getPreloadedValue(AMDGPUFunctionArgInfo::WORKITEM_ID_Y));3892 const ArgDescriptor *IncomingArgZ = std::get<0>(3893 CallerArgInfo.getPreloadedValue(AMDGPUFunctionArgInfo::WORKITEM_ID_Z));3894 3895 SDValue InputReg;3896 SDLoc SL;3897 3898 const bool NeedWorkItemIDX = !CLI.CB->hasFnAttr("amdgpu-no-workitem-id-x");3899 const bool NeedWorkItemIDY = !CLI.CB->hasFnAttr("amdgpu-no-workitem-id-y");3900 const bool NeedWorkItemIDZ = !CLI.CB->hasFnAttr("amdgpu-no-workitem-id-z");3901 3902 // If incoming ids are not packed we need to pack them.3903 if (IncomingArgX && !IncomingArgX->isMasked() && CalleeArgInfo->WorkItemIDX &&3904 NeedWorkItemIDX) {3905 if (Subtarget->getMaxWorkitemID(F, 0) != 0) {3906 InputReg = loadInputValue(DAG, ArgRC, MVT::i32, DL, *IncomingArgX);3907 } else {3908 InputReg = DAG.getConstant(0, DL, MVT::i32);3909 }3910 }3911 3912 if (IncomingArgY && !IncomingArgY->isMasked() && CalleeArgInfo->WorkItemIDY &&3913 NeedWorkItemIDY && Subtarget->getMaxWorkitemID(F, 1) != 0) {3914 SDValue Y = loadInputValue(DAG, ArgRC, MVT::i32, DL, *IncomingArgY);3915 Y = DAG.getNode(ISD::SHL, SL, MVT::i32, Y,3916 DAG.getShiftAmountConstant(10, MVT::i32, SL));3917 InputReg = InputReg.getNode()3918 ? DAG.getNode(ISD::OR, SL, MVT::i32, InputReg, Y)3919 : Y;3920 }3921 3922 if (IncomingArgZ && !IncomingArgZ->isMasked() && CalleeArgInfo->WorkItemIDZ &&3923 NeedWorkItemIDZ && Subtarget->getMaxWorkitemID(F, 2) != 0) {3924 SDValue Z = loadInputValue(DAG, ArgRC, MVT::i32, DL, *IncomingArgZ);3925 Z = DAG.getNode(ISD::SHL, SL, MVT::i32, Z,3926 DAG.getShiftAmountConstant(20, MVT::i32, SL));3927 InputReg = InputReg.getNode()3928 ? DAG.getNode(ISD::OR, SL, MVT::i32, InputReg, Z)3929 : Z;3930 }3931 3932 if (!InputReg && (NeedWorkItemIDX || NeedWorkItemIDY || NeedWorkItemIDZ)) {3933 if (!IncomingArgX && !IncomingArgY && !IncomingArgZ) {3934 // We're in a situation where the outgoing function requires the workitem3935 // ID, but the calling function does not have it (e.g a graphics function3936 // calling a C calling convention function). This is illegal, but we need3937 // to produce something.3938 InputReg = DAG.getPOISON(MVT::i32);3939 } else {3940 // Workitem ids are already packed, any of present incoming arguments3941 // will carry all required fields.3942 ArgDescriptor IncomingArg =3943 ArgDescriptor::createArg(IncomingArgX ? *IncomingArgX3944 : IncomingArgY ? *IncomingArgY3945 : *IncomingArgZ,3946 ~0u);3947 InputReg = loadInputValue(DAG, ArgRC, MVT::i32, DL, IncomingArg);3948 }3949 }3950 3951 if (OutgoingArg->isRegister()) {3952 if (InputReg)3953 RegsToPass.emplace_back(OutgoingArg->getRegister(), InputReg);3954 3955 CCInfo.AllocateReg(OutgoingArg->getRegister());3956 } else {3957 unsigned SpecialArgOffset = CCInfo.AllocateStack(4, Align(4));3958 if (InputReg) {3959 SDValue ArgStore =3960 storeStackInputValue(DAG, DL, Chain, InputReg, SpecialArgOffset);3961 MemOpChains.push_back(ArgStore);3962 }3963 }3964}3965 3966bool SITargetLowering::isEligibleForTailCallOptimization(3967 SDValue Callee, CallingConv::ID CalleeCC, bool IsVarArg,3968 const SmallVectorImpl<ISD::OutputArg> &Outs,3969 const SmallVectorImpl<SDValue> &OutVals,3970 const SmallVectorImpl<ISD::InputArg> &Ins, SelectionDAG &DAG) const {3971 if (AMDGPU::isChainCC(CalleeCC))3972 return true;3973 3974 if (!AMDGPU::mayTailCallThisCC(CalleeCC))3975 return false;3976 3977 // For a divergent call target, we need to do a waterfall loop over the3978 // possible callees which precludes us from using a simple jump.3979 if (Callee->isDivergent())3980 return false;3981 3982 MachineFunction &MF = DAG.getMachineFunction();3983 const Function &CallerF = MF.getFunction();3984 CallingConv::ID CallerCC = CallerF.getCallingConv();3985 const SIRegisterInfo *TRI = getSubtarget()->getRegisterInfo();3986 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);3987 3988 // Kernels aren't callable, and don't have a live in return address so it3989 // doesn't make sense to do a tail call with entry functions.3990 if (!CallerPreserved)3991 return false;3992 3993 bool CCMatch = CallerCC == CalleeCC;3994 3995 if (DAG.getTarget().Options.GuaranteedTailCallOpt) {3996 if (AMDGPU::canGuaranteeTCO(CalleeCC) && CCMatch)3997 return true;3998 return false;3999 }4000 4001 // TODO: Can we handle var args?4002 if (IsVarArg)4003 return false;4004 4005 for (const Argument &Arg : CallerF.args()) {4006 if (Arg.hasByValAttr())4007 return false;4008 }4009 4010 LLVMContext &Ctx = *DAG.getContext();4011 4012 // Check that the call results are passed in the same way.4013 if (!CCState::resultsCompatible(CalleeCC, CallerCC, MF, Ctx, Ins,4014 CCAssignFnForCall(CalleeCC, IsVarArg),4015 CCAssignFnForCall(CallerCC, IsVarArg)))4016 return false;4017 4018 // The callee has to preserve all registers the caller needs to preserve.4019 if (!CCMatch) {4020 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);4021 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))4022 return false;4023 }4024 4025 // Nothing more to check if the callee is taking no arguments.4026 if (Outs.empty())4027 return true;4028 4029 SmallVector<CCValAssign, 16> ArgLocs;4030 CCState CCInfo(CalleeCC, IsVarArg, MF, ArgLocs, Ctx);4031 4032 // FIXME: We are not allocating special input registers, so we will be4033 // deciding based on incorrect register assignments.4034 CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForCall(CalleeCC, IsVarArg));4035 4036 const SIMachineFunctionInfo *FuncInfo = MF.getInfo<SIMachineFunctionInfo>();4037 // If the stack arguments for this call do not fit into our own save area then4038 // the call cannot be made tail.4039 // TODO: Is this really necessary?4040 if (CCInfo.getStackSize() > FuncInfo->getBytesInStackArgArea())4041 return false;4042 4043 for (const auto &[CCVA, ArgVal] : zip_equal(ArgLocs, OutVals)) {4044 // FIXME: What about inreg arguments that end up passed in memory?4045 if (!CCVA.isRegLoc())4046 continue;4047 4048 // If we are passing an argument in an SGPR, and the value is divergent,4049 // this call requires a waterfall loop.4050 if (ArgVal->isDivergent() && TRI->isSGPRPhysReg(CCVA.getLocReg())) {4051 LLVM_DEBUG(4052 dbgs() << "Cannot tail call due to divergent outgoing argument in "4053 << printReg(CCVA.getLocReg(), TRI) << '\n');4054 return false;4055 }4056 }4057 4058 const MachineRegisterInfo &MRI = MF.getRegInfo();4059 return parametersInCSRMatch(MRI, CallerPreserved, ArgLocs, OutVals);4060}4061 4062bool SITargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {4063 if (!CI->isTailCall())4064 return false;4065 4066 const Function *ParentFn = CI->getFunction();4067 if (AMDGPU::isEntryFunctionCC(ParentFn->getCallingConv()))4068 return false;4069 return true;4070}4071 4072namespace {4073// Chain calls have special arguments that we need to handle. These are4074// tagging along at the end of the arguments list(s), after the SGPR and VGPR4075// arguments (index 0 and 1 respectively).4076enum ChainCallArgIdx {4077 Exec = 2,4078 Flags,4079 NumVGPRs,4080 FallbackExec,4081 FallbackCallee4082};4083} // anonymous namespace4084 4085// The wave scratch offset register is used as the global base pointer.4086SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI,4087 SmallVectorImpl<SDValue> &InVals) const {4088 CallingConv::ID CallConv = CLI.CallConv;4089 bool IsChainCallConv = AMDGPU::isChainCC(CallConv);4090 4091 SelectionDAG &DAG = CLI.DAG;4092 4093 const SDLoc &DL = CLI.DL;4094 SDValue Chain = CLI.Chain;4095 SDValue Callee = CLI.Callee;4096 4097 llvm::SmallVector<SDValue, 6> ChainCallSpecialArgs;4098 bool UsesDynamicVGPRs = false;4099 if (IsChainCallConv) {4100 // The last arguments should be the value that we need to put in EXEC,4101 // followed by the flags and any other arguments with special meanings.4102 // Pop them out of CLI.Outs and CLI.OutVals before we do any processing so4103 // we don't treat them like the "real" arguments.4104 auto RequestedExecIt =4105 llvm::find_if(CLI.Outs, [](const ISD::OutputArg &Arg) {4106 return Arg.OrigArgIndex == 2;4107 });4108 assert(RequestedExecIt != CLI.Outs.end() && "No node for EXEC");4109 4110 size_t SpecialArgsBeginIdx = RequestedExecIt - CLI.Outs.begin();4111 CLI.OutVals.erase(CLI.OutVals.begin() + SpecialArgsBeginIdx,4112 CLI.OutVals.end());4113 CLI.Outs.erase(RequestedExecIt, CLI.Outs.end());4114 4115 assert(CLI.Outs.back().OrigArgIndex < 2 &&4116 "Haven't popped all the special args");4117 4118 TargetLowering::ArgListEntry RequestedExecArg =4119 CLI.Args[ChainCallArgIdx::Exec];4120 if (!RequestedExecArg.Ty->isIntegerTy(Subtarget->getWavefrontSize()))4121 return lowerUnhandledCall(CLI, InVals, "Invalid value for EXEC");4122 4123 // Convert constants into TargetConstants, so they become immediate operands4124 // instead of being selected into S_MOV.4125 auto PushNodeOrTargetConstant = [&](TargetLowering::ArgListEntry Arg) {4126 if (const auto *ArgNode = dyn_cast<ConstantSDNode>(Arg.Node)) {4127 ChainCallSpecialArgs.push_back(DAG.getTargetConstant(4128 ArgNode->getAPIntValue(), DL, ArgNode->getValueType(0)));4129 } else4130 ChainCallSpecialArgs.push_back(Arg.Node);4131 };4132 4133 PushNodeOrTargetConstant(RequestedExecArg);4134 4135 // Process any other special arguments depending on the value of the flags.4136 TargetLowering::ArgListEntry Flags = CLI.Args[ChainCallArgIdx::Flags];4137 4138 const APInt &FlagsValue = cast<ConstantSDNode>(Flags.Node)->getAPIntValue();4139 if (FlagsValue.isZero()) {4140 if (CLI.Args.size() > ChainCallArgIdx::Flags + 1)4141 return lowerUnhandledCall(CLI, InVals,4142 "no additional args allowed if flags == 0");4143 } else if (FlagsValue.isOneBitSet(0)) {4144 if (CLI.Args.size() != ChainCallArgIdx::FallbackCallee + 1) {4145 return lowerUnhandledCall(CLI, InVals, "expected 3 additional args");4146 }4147 4148 if (!Subtarget->isWave32()) {4149 return lowerUnhandledCall(4150 CLI, InVals, "dynamic VGPR mode is only supported for wave32");4151 }4152 4153 UsesDynamicVGPRs = true;4154 std::for_each(CLI.Args.begin() + ChainCallArgIdx::NumVGPRs,4155 CLI.Args.end(), PushNodeOrTargetConstant);4156 }4157 }4158 4159 SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs;4160 SmallVector<SDValue, 32> &OutVals = CLI.OutVals;4161 SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins;4162 bool &IsTailCall = CLI.IsTailCall;4163 bool IsVarArg = CLI.IsVarArg;4164 bool IsSibCall = false;4165 MachineFunction &MF = DAG.getMachineFunction();4166 4167 if (Callee.isUndef() || isNullConstant(Callee)) {4168 if (!CLI.IsTailCall) {4169 for (ISD::InputArg &Arg : CLI.Ins)4170 InVals.push_back(DAG.getPOISON(Arg.VT));4171 }4172 4173 return Chain;4174 }4175 4176 if (IsVarArg) {4177 return lowerUnhandledCall(CLI, InVals,4178 "unsupported call to variadic function ");4179 }4180 4181 if (!CLI.CB)4182 return lowerUnhandledCall(CLI, InVals, "unsupported libcall legalization");4183 4184 if (IsTailCall && MF.getTarget().Options.GuaranteedTailCallOpt) {4185 return lowerUnhandledCall(CLI, InVals,4186 "unsupported required tail call to function ");4187 }4188 4189 if (IsTailCall) {4190 IsTailCall = isEligibleForTailCallOptimization(Callee, CallConv, IsVarArg,4191 Outs, OutVals, Ins, DAG);4192 if (!IsTailCall &&4193 ((CLI.CB && CLI.CB->isMustTailCall()) || IsChainCallConv)) {4194 report_fatal_error("failed to perform tail call elimination on a call "4195 "site marked musttail or on llvm.amdgcn.cs.chain");4196 }4197 4198 bool TailCallOpt = MF.getTarget().Options.GuaranteedTailCallOpt;4199 4200 // A sibling call is one where we're under the usual C ABI and not planning4201 // to change that but can still do a tail call:4202 if (!TailCallOpt && IsTailCall)4203 IsSibCall = true;4204 4205 if (IsTailCall)4206 ++NumTailCalls;4207 }4208 4209 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();4210 SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;4211 SmallVector<SDValue, 8> MemOpChains;4212 4213 // Analyze operands of the call, assigning locations to each operand.4214 SmallVector<CCValAssign, 16> ArgLocs;4215 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());4216 CCAssignFn *AssignFn = CCAssignFnForCall(CallConv, IsVarArg);4217 4218 if (CallConv != CallingConv::AMDGPU_Gfx && !AMDGPU::isChainCC(CallConv) &&4219 CallConv != CallingConv::AMDGPU_Gfx_WholeWave) {4220 // With a fixed ABI, allocate fixed registers before user arguments.4221 passSpecialInputs(CLI, CCInfo, *Info, RegsToPass, MemOpChains, Chain);4222 }4223 4224 CCInfo.AnalyzeCallOperands(Outs, AssignFn);4225 4226 // Get a count of how many bytes are to be pushed on the stack.4227 unsigned NumBytes = CCInfo.getStackSize();4228 4229 if (IsSibCall) {4230 // Since we're not changing the ABI to make this a tail call, the memory4231 // operands are already available in the caller's incoming argument space.4232 NumBytes = 0;4233 }4234 4235 // FPDiff is the byte offset of the call's argument area from the callee's.4236 // Stores to callee stack arguments will be placed in FixedStackSlots offset4237 // by this amount for a tail call. In a sibling call it must be 0 because the4238 // caller will deallocate the entire stack and the callee still expects its4239 // arguments to begin at SP+0. Completely unused for non-tail calls.4240 int32_t FPDiff = 0;4241 MachineFrameInfo &MFI = MF.getFrameInfo();4242 auto *TRI = Subtarget->getRegisterInfo();4243 4244 // Adjust the stack pointer for the new arguments...4245 // These operations are automatically eliminated by the prolog/epilog pass4246 if (!IsSibCall)4247 Chain = DAG.getCALLSEQ_START(Chain, 0, 0, DL);4248 4249 if (!IsSibCall || IsChainCallConv) {4250 if (!Subtarget->enableFlatScratch()) {4251 SmallVector<SDValue, 4> CopyFromChains;4252 4253 // In the HSA case, this should be an identity copy.4254 SDValue ScratchRSrcReg =4255 DAG.getCopyFromReg(Chain, DL, Info->getScratchRSrcReg(), MVT::v4i32);4256 RegsToPass.emplace_back(IsChainCallConv4257 ? AMDGPU::SGPR48_SGPR49_SGPR50_SGPR514258 : AMDGPU::SGPR0_SGPR1_SGPR2_SGPR3,4259 ScratchRSrcReg);4260 CopyFromChains.push_back(ScratchRSrcReg.getValue(1));4261 Chain = DAG.getTokenFactor(DL, CopyFromChains);4262 }4263 }4264 4265 const unsigned NumSpecialInputs = RegsToPass.size();4266 4267 MVT PtrVT = MVT::i32;4268 4269 // Walk the register/memloc assignments, inserting copies/loads.4270 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {4271 CCValAssign &VA = ArgLocs[i];4272 SDValue Arg = OutVals[i];4273 4274 // Promote the value if needed.4275 switch (VA.getLocInfo()) {4276 case CCValAssign::Full:4277 break;4278 case CCValAssign::BCvt:4279 Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg);4280 break;4281 case CCValAssign::ZExt:4282 Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg);4283 break;4284 case CCValAssign::SExt:4285 Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg);4286 break;4287 case CCValAssign::AExt:4288 Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg);4289 break;4290 case CCValAssign::FPExt:4291 Arg = DAG.getNode(ISD::FP_EXTEND, DL, VA.getLocVT(), Arg);4292 break;4293 default:4294 llvm_unreachable("Unknown loc info!");4295 }4296 4297 if (VA.isRegLoc()) {4298 RegsToPass.push_back(std::pair(VA.getLocReg(), Arg));4299 } else {4300 assert(VA.isMemLoc());4301 4302 SDValue DstAddr;4303 MachinePointerInfo DstInfo;4304 4305 unsigned LocMemOffset = VA.getLocMemOffset();4306 int32_t Offset = LocMemOffset;4307 4308 SDValue PtrOff = DAG.getConstant(Offset, DL, PtrVT);4309 MaybeAlign Alignment;4310 4311 if (IsTailCall) {4312 ISD::ArgFlagsTy Flags = Outs[i].Flags;4313 unsigned OpSize = Flags.isByVal() ? Flags.getByValSize()4314 : VA.getValVT().getStoreSize();4315 4316 // FIXME: We can have better than the minimum byval required alignment.4317 Alignment =4318 Flags.isByVal()4319 ? Flags.getNonZeroByValAlign()4320 : commonAlignment(Subtarget->getStackAlignment(), Offset);4321 4322 Offset = Offset + FPDiff;4323 int FI = MFI.CreateFixedObject(OpSize, Offset, true);4324 4325 DstAddr = DAG.getFrameIndex(FI, PtrVT);4326 DstInfo = MachinePointerInfo::getFixedStack(MF, FI);4327 4328 // Make sure any stack arguments overlapping with where we're storing4329 // are loaded before this eventual operation. Otherwise they'll be4330 // clobbered.4331 4332 // FIXME: Why is this really necessary? This seems to just result in a4333 // lot of code to copy the stack and write them back to the same4334 // locations, which are supposed to be immutable?4335 Chain = addTokenForArgument(Chain, DAG, MFI, FI);4336 } else {4337 // Stores to the argument stack area are relative to the stack pointer.4338 SDValue SP = DAG.getCopyFromReg(Chain, DL, Info->getStackPtrOffsetReg(),4339 MVT::i32);4340 DstAddr = DAG.getNode(ISD::ADD, DL, MVT::i32, SP, PtrOff);4341 DstInfo = MachinePointerInfo::getStack(MF, LocMemOffset);4342 Alignment =4343 commonAlignment(Subtarget->getStackAlignment(), LocMemOffset);4344 }4345 4346 if (Outs[i].Flags.isByVal()) {4347 SDValue SizeNode =4348 DAG.getConstant(Outs[i].Flags.getByValSize(), DL, MVT::i32);4349 SDValue Cpy =4350 DAG.getMemcpy(Chain, DL, DstAddr, Arg, SizeNode,4351 Outs[i].Flags.getNonZeroByValAlign(),4352 /*isVol = */ false, /*AlwaysInline = */ true,4353 /*CI=*/nullptr, std::nullopt, DstInfo,4354 MachinePointerInfo(AMDGPUAS::PRIVATE_ADDRESS));4355 4356 MemOpChains.push_back(Cpy);4357 } else {4358 SDValue Store =4359 DAG.getStore(Chain, DL, Arg, DstAddr, DstInfo, Alignment);4360 MemOpChains.push_back(Store);4361 }4362 }4363 }4364 4365 if (!MemOpChains.empty())4366 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);4367 4368 SDValue ReadFirstLaneID =4369 DAG.getTargetConstant(Intrinsic::amdgcn_readfirstlane, DL, MVT::i32);4370 4371 SDValue TokenGlue;4372 if (CLI.ConvergenceControlToken) {4373 TokenGlue = DAG.getNode(ISD::CONVERGENCECTRL_GLUE, DL, MVT::Glue,4374 CLI.ConvergenceControlToken);4375 }4376 4377 // Build a sequence of copy-to-reg nodes chained together with token chain4378 // and flag operands which copy the outgoing args into the appropriate regs.4379 SDValue InGlue;4380 4381 unsigned ArgIdx = 0;4382 for (auto [Reg, Val] : RegsToPass) {4383 if (ArgIdx++ >= NumSpecialInputs &&4384 (IsChainCallConv || !Val->isDivergent()) && TRI->isSGPRPhysReg(Reg)) {4385 // For chain calls, the inreg arguments are required to be4386 // uniform. Speculatively Insert a readfirstlane in case we cannot prove4387 // they are uniform.4388 //4389 // For other calls, if an inreg arguments is known to be uniform,4390 // speculatively insert a readfirstlane in case it is in a VGPR.4391 //4392 // FIXME: We need to execute this in a waterfall loop if it is a divergent4393 // value, so let that continue to produce invalid code.4394 4395 SmallVector<SDValue, 3> ReadfirstlaneArgs({ReadFirstLaneID, Val});4396 if (TokenGlue)4397 ReadfirstlaneArgs.push_back(TokenGlue);4398 Val = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, Val.getValueType(),4399 ReadfirstlaneArgs);4400 }4401 4402 Chain = DAG.getCopyToReg(Chain, DL, Reg, Val, InGlue);4403 InGlue = Chain.getValue(1);4404 }4405 4406 // We don't usually want to end the call-sequence here because we would tidy4407 // the frame up *after* the call, however in the ABI-changing tail-call case4408 // we've carefully laid out the parameters so that when sp is reset they'll be4409 // in the correct location.4410 if (IsTailCall && !IsSibCall) {4411 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, InGlue, DL);4412 InGlue = Chain.getValue(1);4413 }4414 4415 std::vector<SDValue> Ops({Chain});4416 4417 // Add a redundant copy of the callee global which will not be legalized, as4418 // we need direct access to the callee later.4419 if (GlobalAddressSDNode *GSD = dyn_cast<GlobalAddressSDNode>(Callee)) {4420 const GlobalValue *GV = GSD->getGlobal();4421 Ops.push_back(Callee);4422 Ops.push_back(DAG.getTargetGlobalAddress(GV, DL, MVT::i64));4423 } else {4424 if (IsTailCall) {4425 // isEligibleForTailCallOptimization considered whether the call target is4426 // divergent, but we may still end up with a uniform value in a VGPR.4427 // Insert a readfirstlane just in case.4428 SDValue ReadFirstLaneID =4429 DAG.getTargetConstant(Intrinsic::amdgcn_readfirstlane, DL, MVT::i32);4430 4431 SmallVector<SDValue, 3> ReadfirstlaneArgs({ReadFirstLaneID, Callee});4432 if (TokenGlue)4433 ReadfirstlaneArgs.push_back(TokenGlue); // Wire up convergence token.4434 Callee = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, Callee.getValueType(),4435 ReadfirstlaneArgs);4436 }4437 4438 Ops.push_back(Callee);4439 Ops.push_back(DAG.getTargetConstant(0, DL, MVT::i64));4440 }4441 4442 if (IsTailCall) {4443 // Each tail call may have to adjust the stack by a different amount, so4444 // this information must travel along with the operation for eventual4445 // consumption by emitEpilogue.4446 Ops.push_back(DAG.getTargetConstant(FPDiff, DL, MVT::i32));4447 }4448 4449 if (IsChainCallConv)4450 llvm::append_range(Ops, ChainCallSpecialArgs);4451 4452 // Add argument registers to the end of the list so that they are known live4453 // into the call.4454 for (auto &[Reg, Val] : RegsToPass)4455 Ops.push_back(DAG.getRegister(Reg, Val.getValueType()));4456 4457 // Add a register mask operand representing the call-preserved registers.4458 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);4459 assert(Mask && "Missing call preserved mask for calling convention");4460 Ops.push_back(DAG.getRegisterMask(Mask));4461 4462 if (SDValue Token = CLI.ConvergenceControlToken) {4463 SmallVector<SDValue, 2> GlueOps;4464 GlueOps.push_back(Token);4465 if (InGlue)4466 GlueOps.push_back(InGlue);4467 4468 InGlue = SDValue(DAG.getMachineNode(TargetOpcode::CONVERGENCECTRL_GLUE, DL,4469 MVT::Glue, GlueOps),4470 0);4471 }4472 4473 if (InGlue)4474 Ops.push_back(InGlue);4475 4476 // If we're doing a tall call, use a TC_RETURN here rather than an4477 // actual call instruction.4478 if (IsTailCall) {4479 MFI.setHasTailCall();4480 unsigned OPC = AMDGPUISD::TC_RETURN;4481 switch (CallConv) {4482 case CallingConv::AMDGPU_Gfx:4483 OPC = AMDGPUISD::TC_RETURN_GFX;4484 break;4485 case CallingConv::AMDGPU_CS_Chain:4486 case CallingConv::AMDGPU_CS_ChainPreserve:4487 OPC = UsesDynamicVGPRs ? AMDGPUISD::TC_RETURN_CHAIN_DVGPR4488 : AMDGPUISD::TC_RETURN_CHAIN;4489 break;4490 }4491 4492 // If the caller is a whole wave function, we need to use a special opcode4493 // so we can patch up EXEC.4494 if (Info->isWholeWaveFunction())4495 OPC = AMDGPUISD::TC_RETURN_GFX_WholeWave;4496 4497 return DAG.getNode(OPC, DL, MVT::Other, Ops);4498 }4499 4500 // Returns a chain and a flag for retval copy to use.4501 SDValue Call = DAG.getNode(AMDGPUISD::CALL, DL, {MVT::Other, MVT::Glue}, Ops);4502 Chain = Call.getValue(0);4503 InGlue = Call.getValue(1);4504 4505 uint64_t CalleePopBytes = NumBytes;4506 Chain = DAG.getCALLSEQ_END(Chain, 0, CalleePopBytes, InGlue, DL);4507 if (!Ins.empty())4508 InGlue = Chain.getValue(1);4509 4510 // Handle result values, copying them out of physregs into vregs that we4511 // return.4512 return LowerCallResult(Chain, InGlue, CallConv, IsVarArg, Ins, DL, DAG,4513 InVals, /*IsThisReturn=*/false, SDValue());4514}4515 4516// This is similar to the default implementation in ExpandDYNAMIC_STACKALLOC,4517// except for:4518// 1. Stack growth direction(default: downwards, AMDGPU: upwards), and4519// 2. Scale size where, scale = wave-reduction(alloca-size) * wave-size4520SDValue SITargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,4521 SelectionDAG &DAG) const {4522 const MachineFunction &MF = DAG.getMachineFunction();4523 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();4524 4525 SDLoc dl(Op);4526 EVT VT = Op.getValueType();4527 SDValue Chain = Op.getOperand(0);4528 Register SPReg = Info->getStackPtrOffsetReg();4529 4530 // Chain the dynamic stack allocation so that it doesn't modify the stack4531 // pointer when other instructions are using the stack.4532 Chain = DAG.getCALLSEQ_START(Chain, 0, 0, dl);4533 4534 SDValue Size = Op.getOperand(1);4535 SDValue BaseAddr = DAG.getCopyFromReg(Chain, dl, SPReg, VT);4536 Align Alignment = cast<ConstantSDNode>(Op.getOperand(2))->getAlignValue();4537 4538 const TargetFrameLowering *TFL = Subtarget->getFrameLowering();4539 assert(TFL->getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp &&4540 "Stack grows upwards for AMDGPU");4541 4542 Chain = BaseAddr.getValue(1);4543 Align StackAlign = TFL->getStackAlign();4544 if (Alignment > StackAlign) {4545 uint64_t ScaledAlignment = Alignment.value()4546 << Subtarget->getWavefrontSizeLog2();4547 uint64_t StackAlignMask = ScaledAlignment - 1;4548 SDValue TmpAddr = DAG.getNode(ISD::ADD, dl, VT, BaseAddr,4549 DAG.getConstant(StackAlignMask, dl, VT));4550 BaseAddr = DAG.getNode(ISD::AND, dl, VT, TmpAddr,4551 DAG.getSignedConstant(-ScaledAlignment, dl, VT));4552 }4553 4554 assert(Size.getValueType() == MVT::i32 && "Size must be 32-bit");4555 SDValue NewSP;4556 if (isa<ConstantSDNode>(Size)) {4557 // For constant sized alloca, scale alloca size by wave-size4558 SDValue ScaledSize = DAG.getNode(4559 ISD::SHL, dl, VT, Size,4560 DAG.getConstant(Subtarget->getWavefrontSizeLog2(), dl, MVT::i32));4561 NewSP = DAG.getNode(ISD::ADD, dl, VT, BaseAddr, ScaledSize); // Value4562 } else {4563 // For dynamic sized alloca, perform wave-wide reduction to get max of4564 // alloca size(divergent) and then scale it by wave-size4565 SDValue WaveReduction =4566 DAG.getTargetConstant(Intrinsic::amdgcn_wave_reduce_umax, dl, MVT::i32);4567 Size = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::i32, WaveReduction,4568 Size, DAG.getConstant(0, dl, MVT::i32));4569 SDValue ScaledSize = DAG.getNode(4570 ISD::SHL, dl, VT, Size,4571 DAG.getConstant(Subtarget->getWavefrontSizeLog2(), dl, MVT::i32));4572 NewSP =4573 DAG.getNode(ISD::ADD, dl, VT, BaseAddr, ScaledSize); // Value in vgpr.4574 SDValue ReadFirstLaneID =4575 DAG.getTargetConstant(Intrinsic::amdgcn_readfirstlane, dl, MVT::i32);4576 NewSP = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::i32, ReadFirstLaneID,4577 NewSP);4578 }4579 4580 Chain = DAG.getCopyToReg(Chain, dl, SPReg, NewSP); // Output chain4581 SDValue CallSeqEnd = DAG.getCALLSEQ_END(Chain, 0, 0, SDValue(), dl);4582 4583 return DAG.getMergeValues({BaseAddr, CallSeqEnd}, dl);4584}4585 4586SDValue SITargetLowering::LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const {4587 if (Op.getValueType() != MVT::i32)4588 return Op; // Defer to cannot select error.4589 4590 Register SP = getStackPointerRegisterToSaveRestore();4591 SDLoc SL(Op);4592 4593 SDValue CopyFromSP = DAG.getCopyFromReg(Op->getOperand(0), SL, SP, MVT::i32);4594 4595 // Convert from wave uniform to swizzled vector address. This should protect4596 // from any edge cases where the stacksave result isn't directly used with4597 // stackrestore.4598 SDValue VectorAddress =4599 DAG.getNode(AMDGPUISD::WAVE_ADDRESS, SL, MVT::i32, CopyFromSP);4600 return DAG.getMergeValues({VectorAddress, CopyFromSP.getValue(1)}, SL);4601}4602 4603SDValue SITargetLowering::lowerGET_ROUNDING(SDValue Op,4604 SelectionDAG &DAG) const {4605 SDLoc SL(Op);4606 assert(Op.getValueType() == MVT::i32);4607 4608 uint32_t BothRoundHwReg =4609 AMDGPU::Hwreg::HwregEncoding::encode(AMDGPU::Hwreg::ID_MODE, 0, 4);4610 SDValue GetRoundBothImm = DAG.getTargetConstant(BothRoundHwReg, SL, MVT::i32);4611 4612 SDValue IntrinID =4613 DAG.getTargetConstant(Intrinsic::amdgcn_s_getreg, SL, MVT::i32);4614 SDValue GetReg = DAG.getNode(ISD::INTRINSIC_W_CHAIN, SL, Op->getVTList(),4615 Op.getOperand(0), IntrinID, GetRoundBothImm);4616 4617 // There are two rounding modes, one for f32 and one for f64/f16. We only4618 // report in the standard value range if both are the same.4619 //4620 // The raw values also differ from the expected FLT_ROUNDS values. Nearest4621 // ties away from zero is not supported, and the other values are rotated by4622 // 1.4623 //4624 // If the two rounding modes are not the same, report a target defined value.4625 4626 // Mode register rounding mode fields:4627 //4628 // [1:0] Single-precision round mode.4629 // [3:2] Double/Half-precision round mode.4630 //4631 // 0=nearest even; 1= +infinity; 2= -infinity, 3= toward zero.4632 //4633 // Hardware Spec4634 // Toward-0 3 04635 // Nearest Even 0 14636 // +Inf 1 24637 // -Inf 2 34638 // NearestAway0 N/A 44639 //4640 // We have to handle 16 permutations of a 4-bit value, so we create a 64-bit4641 // table we can index by the raw hardware mode.4642 //4643 // (trunc (FltRoundConversionTable >> MODE.fp_round)) & 0xf4644 4645 SDValue BitTable =4646 DAG.getConstant(AMDGPU::FltRoundConversionTable, SL, MVT::i64);4647 4648 SDValue Two = DAG.getConstant(2, SL, MVT::i32);4649 SDValue RoundModeTimesNumBits =4650 DAG.getNode(ISD::SHL, SL, MVT::i32, GetReg, Two);4651 4652 // TODO: We could possibly avoid a 64-bit shift and use a simpler table if we4653 // knew only one mode was demanded.4654 SDValue TableValue =4655 DAG.getNode(ISD::SRL, SL, MVT::i64, BitTable, RoundModeTimesNumBits);4656 SDValue TruncTable = DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, TableValue);4657 4658 SDValue EntryMask = DAG.getConstant(0xf, SL, MVT::i32);4659 SDValue TableEntry =4660 DAG.getNode(ISD::AND, SL, MVT::i32, TruncTable, EntryMask);4661 4662 // There's a gap in the 4-bit encoded table and actual enum values, so offset4663 // if it's an extended value.4664 SDValue Four = DAG.getConstant(4, SL, MVT::i32);4665 SDValue IsStandardValue =4666 DAG.getSetCC(SL, MVT::i1, TableEntry, Four, ISD::SETULT);4667 SDValue EnumOffset = DAG.getNode(ISD::ADD, SL, MVT::i32, TableEntry, Four);4668 SDValue Result = DAG.getNode(ISD::SELECT, SL, MVT::i32, IsStandardValue,4669 TableEntry, EnumOffset);4670 4671 return DAG.getMergeValues({Result, GetReg.getValue(1)}, SL);4672}4673 4674SDValue SITargetLowering::lowerSET_ROUNDING(SDValue Op,4675 SelectionDAG &DAG) const {4676 SDLoc SL(Op);4677 4678 SDValue NewMode = Op.getOperand(1);4679 assert(NewMode.getValueType() == MVT::i32);4680 4681 // Index a table of 4-bit entries mapping from the C FLT_ROUNDS values to the4682 // hardware MODE.fp_round values.4683 if (auto *ConstMode = dyn_cast<ConstantSDNode>(NewMode)) {4684 uint32_t ClampedVal = std::min(4685 static_cast<uint32_t>(ConstMode->getZExtValue()),4686 static_cast<uint32_t>(AMDGPU::TowardZeroF32_TowardNegativeF64));4687 NewMode = DAG.getConstant(4688 AMDGPU::decodeFltRoundToHWConversionTable(ClampedVal), SL, MVT::i32);4689 } else {4690 // If we know the input can only be one of the supported standard modes in4691 // the range 0-3, we can use a simplified mapping to hardware values.4692 KnownBits KB = DAG.computeKnownBits(NewMode);4693 const bool UseReducedTable = KB.countMinLeadingZeros() >= 30;4694 // The supported standard values are 0-3. The extended values start at 8. We4695 // need to offset by 4 if the value is in the extended range.4696 4697 if (UseReducedTable) {4698 // Truncate to the low 32-bits.4699 SDValue BitTable = DAG.getConstant(4700 AMDGPU::FltRoundToHWConversionTable & 0xffff, SL, MVT::i32);4701 4702 SDValue Two = DAG.getConstant(2, SL, MVT::i32);4703 SDValue RoundModeTimesNumBits =4704 DAG.getNode(ISD::SHL, SL, MVT::i32, NewMode, Two);4705 4706 NewMode =4707 DAG.getNode(ISD::SRL, SL, MVT::i32, BitTable, RoundModeTimesNumBits);4708 4709 // TODO: SimplifyDemandedBits on the setreg source here can likely reduce4710 // the table extracted bits into inline immediates.4711 } else {4712 // table_index = umin(value, value - 4)4713 // MODE.fp_round = (bit_table >> (table_index << 2)) & 0xf4714 SDValue BitTable =4715 DAG.getConstant(AMDGPU::FltRoundToHWConversionTable, SL, MVT::i64);4716 4717 SDValue Four = DAG.getConstant(4, SL, MVT::i32);4718 SDValue OffsetEnum = DAG.getNode(ISD::SUB, SL, MVT::i32, NewMode, Four);4719 SDValue IndexVal =4720 DAG.getNode(ISD::UMIN, SL, MVT::i32, NewMode, OffsetEnum);4721 4722 SDValue Two = DAG.getConstant(2, SL, MVT::i32);4723 SDValue RoundModeTimesNumBits =4724 DAG.getNode(ISD::SHL, SL, MVT::i32, IndexVal, Two);4725 4726 SDValue TableValue =4727 DAG.getNode(ISD::SRL, SL, MVT::i64, BitTable, RoundModeTimesNumBits);4728 SDValue TruncTable = DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, TableValue);4729 4730 // No need to mask out the high bits since the setreg will ignore them4731 // anyway.4732 NewMode = TruncTable;4733 }4734 4735 // Insert a readfirstlane in case the value is a VGPR. We could do this4736 // earlier and keep more operations scalar, but that interferes with4737 // combining the source.4738 SDValue ReadFirstLaneID =4739 DAG.getTargetConstant(Intrinsic::amdgcn_readfirstlane, SL, MVT::i32);4740 NewMode = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, MVT::i32,4741 ReadFirstLaneID, NewMode);4742 }4743 4744 // N.B. The setreg will be later folded into s_round_mode on supported4745 // targets.4746 SDValue IntrinID =4747 DAG.getTargetConstant(Intrinsic::amdgcn_s_setreg, SL, MVT::i32);4748 uint32_t BothRoundHwReg =4749 AMDGPU::Hwreg::HwregEncoding::encode(AMDGPU::Hwreg::ID_MODE, 0, 4);4750 SDValue RoundBothImm = DAG.getTargetConstant(BothRoundHwReg, SL, MVT::i32);4751 4752 SDValue SetReg =4753 DAG.getNode(ISD::INTRINSIC_VOID, SL, Op->getVTList(), Op.getOperand(0),4754 IntrinID, RoundBothImm, NewMode);4755 4756 return SetReg;4757}4758 4759SDValue SITargetLowering::lowerPREFETCH(SDValue Op, SelectionDAG &DAG) const {4760 if (Op->isDivergent() &&4761 (!Subtarget->hasVmemPrefInsts() || !Op.getConstantOperandVal(4)))4762 // Cannot do I$ prefetch with divergent pointer.4763 return SDValue();4764 4765 switch (cast<MemSDNode>(Op)->getAddressSpace()) {4766 case AMDGPUAS::FLAT_ADDRESS:4767 case AMDGPUAS::GLOBAL_ADDRESS:4768 case AMDGPUAS::CONSTANT_ADDRESS:4769 break;4770 case AMDGPUAS::CONSTANT_ADDRESS_32BIT:4771 if (Subtarget->hasSafeSmemPrefetch())4772 break;4773 [[fallthrough]];4774 default:4775 return SDValue();4776 }4777 4778 // I$ prefetch4779 if (!Subtarget->hasSafeSmemPrefetch() && !Op.getConstantOperandVal(4))4780 return SDValue();4781 4782 return Op;4783}4784 4785// Work around DAG legality rules only based on the result type.4786SDValue SITargetLowering::lowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const {4787 bool IsStrict = Op.getOpcode() == ISD::STRICT_FP_EXTEND;4788 SDValue Src = Op.getOperand(IsStrict ? 1 : 0);4789 EVT SrcVT = Src.getValueType();4790 4791 if (SrcVT.getScalarType() != MVT::bf16)4792 return Op;4793 4794 SDLoc SL(Op);4795 SDValue BitCast =4796 DAG.getNode(ISD::BITCAST, SL, SrcVT.changeTypeToInteger(), Src);4797 4798 EVT DstVT = Op.getValueType();4799 if (IsStrict)4800 llvm_unreachable("Need STRICT_BF16_TO_FP");4801 4802 return DAG.getNode(ISD::BF16_TO_FP, SL, DstVT, BitCast);4803}4804 4805SDValue SITargetLowering::lowerGET_FPENV(SDValue Op, SelectionDAG &DAG) const {4806 SDLoc SL(Op);4807 if (Op.getValueType() != MVT::i64)4808 return Op;4809 4810 uint32_t ModeHwReg =4811 AMDGPU::Hwreg::HwregEncoding::encode(AMDGPU::Hwreg::ID_MODE, 0, 23);4812 SDValue ModeHwRegImm = DAG.getTargetConstant(ModeHwReg, SL, MVT::i32);4813 uint32_t TrapHwReg =4814 AMDGPU::Hwreg::HwregEncoding::encode(AMDGPU::Hwreg::ID_TRAPSTS, 0, 5);4815 SDValue TrapHwRegImm = DAG.getTargetConstant(TrapHwReg, SL, MVT::i32);4816 4817 SDVTList VTList = DAG.getVTList(MVT::i32, MVT::Other);4818 SDValue IntrinID =4819 DAG.getTargetConstant(Intrinsic::amdgcn_s_getreg, SL, MVT::i32);4820 SDValue GetModeReg = DAG.getNode(ISD::INTRINSIC_W_CHAIN, SL, VTList,4821 Op.getOperand(0), IntrinID, ModeHwRegImm);4822 SDValue GetTrapReg = DAG.getNode(ISD::INTRINSIC_W_CHAIN, SL, VTList,4823 Op.getOperand(0), IntrinID, TrapHwRegImm);4824 SDValue TokenReg =4825 DAG.getNode(ISD::TokenFactor, SL, MVT::Other, GetModeReg.getValue(1),4826 GetTrapReg.getValue(1));4827 4828 SDValue CvtPtr =4829 DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v2i32, GetModeReg, GetTrapReg);4830 SDValue Result = DAG.getNode(ISD::BITCAST, SL, MVT::i64, CvtPtr);4831 4832 return DAG.getMergeValues({Result, TokenReg}, SL);4833}4834 4835SDValue SITargetLowering::lowerSET_FPENV(SDValue Op, SelectionDAG &DAG) const {4836 SDLoc SL(Op);4837 if (Op.getOperand(1).getValueType() != MVT::i64)4838 return Op;4839 4840 SDValue Input = DAG.getNode(ISD::BITCAST, SL, MVT::v2i32, Op.getOperand(1));4841 SDValue NewModeReg = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, Input,4842 DAG.getConstant(0, SL, MVT::i32));4843 SDValue NewTrapReg = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, Input,4844 DAG.getConstant(1, SL, MVT::i32));4845 4846 SDValue ReadFirstLaneID =4847 DAG.getTargetConstant(Intrinsic::amdgcn_readfirstlane, SL, MVT::i32);4848 NewModeReg = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, MVT::i32,4849 ReadFirstLaneID, NewModeReg);4850 NewTrapReg = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, MVT::i32,4851 ReadFirstLaneID, NewTrapReg);4852 4853 unsigned ModeHwReg =4854 AMDGPU::Hwreg::HwregEncoding::encode(AMDGPU::Hwreg::ID_MODE, 0, 23);4855 SDValue ModeHwRegImm = DAG.getTargetConstant(ModeHwReg, SL, MVT::i32);4856 unsigned TrapHwReg =4857 AMDGPU::Hwreg::HwregEncoding::encode(AMDGPU::Hwreg::ID_TRAPSTS, 0, 5);4858 SDValue TrapHwRegImm = DAG.getTargetConstant(TrapHwReg, SL, MVT::i32);4859 4860 SDValue IntrinID =4861 DAG.getTargetConstant(Intrinsic::amdgcn_s_setreg, SL, MVT::i32);4862 SDValue SetModeReg =4863 DAG.getNode(ISD::INTRINSIC_VOID, SL, MVT::Other, Op.getOperand(0),4864 IntrinID, ModeHwRegImm, NewModeReg);4865 SDValue SetTrapReg =4866 DAG.getNode(ISD::INTRINSIC_VOID, SL, MVT::Other, Op.getOperand(0),4867 IntrinID, TrapHwRegImm, NewTrapReg);4868 return DAG.getNode(ISD::TokenFactor, SL, MVT::Other, SetTrapReg, SetModeReg);4869}4870 4871Register SITargetLowering::getRegisterByName(const char *RegName, LLT VT,4872 const MachineFunction &MF) const {4873 const Function &Fn = MF.getFunction();4874 4875 Register Reg = StringSwitch<Register>(RegName)4876 .Case("m0", AMDGPU::M0)4877 .Case("exec", AMDGPU::EXEC)4878 .Case("exec_lo", AMDGPU::EXEC_LO)4879 .Case("exec_hi", AMDGPU::EXEC_HI)4880 .Case("flat_scratch", AMDGPU::FLAT_SCR)4881 .Case("flat_scratch_lo", AMDGPU::FLAT_SCR_LO)4882 .Case("flat_scratch_hi", AMDGPU::FLAT_SCR_HI)4883 .Default(Register());4884 if (!Reg)4885 return Reg;4886 4887 if (!Subtarget->hasFlatScrRegister() &&4888 Subtarget->getRegisterInfo()->regsOverlap(Reg, AMDGPU::FLAT_SCR)) {4889 Fn.getContext().emitError(Twine("invalid register \"" + StringRef(RegName) +4890 "\" for subtarget."));4891 }4892 4893 switch (Reg) {4894 case AMDGPU::M0:4895 case AMDGPU::EXEC_LO:4896 case AMDGPU::EXEC_HI:4897 case AMDGPU::FLAT_SCR_LO:4898 case AMDGPU::FLAT_SCR_HI:4899 if (VT.getSizeInBits() == 32)4900 return Reg;4901 break;4902 case AMDGPU::EXEC:4903 case AMDGPU::FLAT_SCR:4904 if (VT.getSizeInBits() == 64)4905 return Reg;4906 break;4907 default:4908 llvm_unreachable("missing register type checking");4909 }4910 4911 report_fatal_error(4912 Twine("invalid type for register \"" + StringRef(RegName) + "\"."));4913}4914 4915// If kill is not the last instruction, split the block so kill is always a4916// proper terminator.4917MachineBasicBlock *4918SITargetLowering::splitKillBlock(MachineInstr &MI,4919 MachineBasicBlock *BB) const {4920 MachineBasicBlock *SplitBB = BB->splitAt(MI, /*UpdateLiveIns=*/true);4921 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();4922 MI.setDesc(TII->getKillTerminatorFromPseudo(MI.getOpcode()));4923 return SplitBB;4924}4925 4926// Split block \p MBB at \p MI, as to insert a loop. If \p InstInLoop is true,4927// \p MI will be the only instruction in the loop body block. Otherwise, it will4928// be the first instruction in the remainder block.4929//4930/// \returns { LoopBody, Remainder }4931static std::pair<MachineBasicBlock *, MachineBasicBlock *>4932splitBlockForLoop(MachineInstr &MI, MachineBasicBlock &MBB, bool InstInLoop) {4933 MachineFunction *MF = MBB.getParent();4934 MachineBasicBlock::iterator I(&MI);4935 4936 // To insert the loop we need to split the block. Move everything after this4937 // point to a new block, and insert a new empty block between the two.4938 MachineBasicBlock *LoopBB = MF->CreateMachineBasicBlock();4939 MachineBasicBlock *RemainderBB = MF->CreateMachineBasicBlock();4940 MachineFunction::iterator MBBI(MBB);4941 ++MBBI;4942 4943 MF->insert(MBBI, LoopBB);4944 MF->insert(MBBI, RemainderBB);4945 4946 LoopBB->addSuccessor(LoopBB);4947 LoopBB->addSuccessor(RemainderBB);4948 4949 // Move the rest of the block into a new block.4950 RemainderBB->transferSuccessorsAndUpdatePHIs(&MBB);4951 4952 if (InstInLoop) {4953 auto Next = std::next(I);4954 4955 // Move instruction to loop body.4956 LoopBB->splice(LoopBB->begin(), &MBB, I, Next);4957 4958 // Move the rest of the block.4959 RemainderBB->splice(RemainderBB->begin(), &MBB, Next, MBB.end());4960 } else {4961 RemainderBB->splice(RemainderBB->begin(), &MBB, I, MBB.end());4962 }4963 4964 MBB.addSuccessor(LoopBB);4965 4966 return std::pair(LoopBB, RemainderBB);4967}4968 4969/// Insert \p MI into a BUNDLE with an S_WAITCNT 0 immediately following it.4970void SITargetLowering::bundleInstWithWaitcnt(MachineInstr &MI) const {4971 MachineBasicBlock *MBB = MI.getParent();4972 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();4973 auto I = MI.getIterator();4974 auto E = std::next(I);4975 4976 // clang-format off4977 BuildMI(*MBB, E, MI.getDebugLoc(), TII->get(AMDGPU::S_WAITCNT))4978 .addImm(0);4979 // clang-format on4980 4981 MIBundleBuilder Bundler(*MBB, I, E);4982 finalizeBundle(*MBB, Bundler.begin());4983}4984 4985MachineBasicBlock *4986SITargetLowering::emitGWSMemViolTestLoop(MachineInstr &MI,4987 MachineBasicBlock *BB) const {4988 const DebugLoc &DL = MI.getDebugLoc();4989 4990 MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();4991 4992 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();4993 4994 // Apparently kill flags are only valid if the def is in the same block?4995 if (MachineOperand *Src = TII->getNamedOperand(MI, AMDGPU::OpName::data0))4996 Src->setIsKill(false);4997 4998 auto [LoopBB, RemainderBB] = splitBlockForLoop(MI, *BB, true);4999 5000 MachineBasicBlock::iterator I = LoopBB->end();5001 5002 const unsigned EncodedReg = AMDGPU::Hwreg::HwregEncoding::encode(5003 AMDGPU::Hwreg::ID_TRAPSTS, AMDGPU::Hwreg::OFFSET_MEM_VIOL, 1);5004 5005 // Clear TRAP_STS.MEM_VIOL5006 BuildMI(*LoopBB, LoopBB->begin(), DL, TII->get(AMDGPU::S_SETREG_IMM32_B32))5007 .addImm(0)5008 .addImm(EncodedReg);5009 5010 bundleInstWithWaitcnt(MI);5011 5012 Register Reg = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);5013 5014 // Load and check TRAP_STS.MEM_VIOL5015 BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::S_GETREG_B32), Reg)5016 .addImm(EncodedReg);5017 5018 // FIXME: Do we need to use an isel pseudo that may clobber scc?5019 BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::S_CMP_LG_U32))5020 .addReg(Reg, RegState::Kill)5021 .addImm(0);5022 // clang-format off5023 BuildMI(*LoopBB, I, DL, TII->get(AMDGPU::S_CBRANCH_SCC1))5024 .addMBB(LoopBB);5025 // clang-format on5026 5027 return RemainderBB;5028}5029 5030// Do a v_movrels_b32 or v_movreld_b32 for each unique value of \p IdxReg in the5031// wavefront. If the value is uniform and just happens to be in a VGPR, this5032// will only do one iteration. In the worst case, this will loop 64 times.5033//5034// TODO: Just use v_readlane_b32 if we know the VGPR has a uniform value.5035static MachineBasicBlock::iterator5036emitLoadM0FromVGPRLoop(const SIInstrInfo *TII, MachineRegisterInfo &MRI,5037 MachineBasicBlock &OrigBB, MachineBasicBlock &LoopBB,5038 const DebugLoc &DL, const MachineOperand &Idx,5039 unsigned InitReg, unsigned ResultReg, unsigned PhiReg,5040 unsigned InitSaveExecReg, int Offset, bool UseGPRIdxMode,5041 Register &SGPRIdxReg) {5042 5043 MachineFunction *MF = OrigBB.getParent();5044 const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>();5045 const SIRegisterInfo *TRI = ST.getRegisterInfo();5046 const AMDGPU::LaneMaskConstants &LMC = AMDGPU::LaneMaskConstants::get(ST);5047 MachineBasicBlock::iterator I = LoopBB.begin();5048 5049 const TargetRegisterClass *BoolRC = TRI->getBoolRC();5050 Register PhiExec = MRI.createVirtualRegister(BoolRC);5051 Register NewExec = MRI.createVirtualRegister(BoolRC);5052 Register CurrentIdxReg =5053 MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);5054 Register CondReg = MRI.createVirtualRegister(BoolRC);5055 5056 BuildMI(LoopBB, I, DL, TII->get(TargetOpcode::PHI), PhiReg)5057 .addReg(InitReg)5058 .addMBB(&OrigBB)5059 .addReg(ResultReg)5060 .addMBB(&LoopBB);5061 5062 BuildMI(LoopBB, I, DL, TII->get(TargetOpcode::PHI), PhiExec)5063 .addReg(InitSaveExecReg)5064 .addMBB(&OrigBB)5065 .addReg(NewExec)5066 .addMBB(&LoopBB);5067 5068 // Read the next variant <- also loop target.5069 BuildMI(LoopBB, I, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), CurrentIdxReg)5070 .addReg(Idx.getReg(), getUndefRegState(Idx.isUndef()));5071 5072 // Compare the just read M0 value to all possible Idx values.5073 BuildMI(LoopBB, I, DL, TII->get(AMDGPU::V_CMP_EQ_U32_e64), CondReg)5074 .addReg(CurrentIdxReg)5075 .addReg(Idx.getReg(), 0, Idx.getSubReg());5076 5077 // Update EXEC, save the original EXEC value to VCC.5078 BuildMI(LoopBB, I, DL, TII->get(LMC.AndSaveExecOpc), NewExec)5079 .addReg(CondReg, RegState::Kill);5080 5081 MRI.setSimpleHint(NewExec, CondReg);5082 5083 if (UseGPRIdxMode) {5084 if (Offset == 0) {5085 SGPRIdxReg = CurrentIdxReg;5086 } else {5087 SGPRIdxReg = MRI.createVirtualRegister(&AMDGPU::SGPR_32RegClass);5088 BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_ADD_I32), SGPRIdxReg)5089 .addReg(CurrentIdxReg, RegState::Kill)5090 .addImm(Offset);5091 }5092 } else {5093 // Move index from VCC into M05094 if (Offset == 0) {5095 BuildMI(LoopBB, I, DL, TII->get(AMDGPU::COPY), AMDGPU::M0)5096 .addReg(CurrentIdxReg, RegState::Kill);5097 } else {5098 BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_ADD_I32), AMDGPU::M0)5099 .addReg(CurrentIdxReg, RegState::Kill)5100 .addImm(Offset);5101 }5102 }5103 5104 // Update EXEC, switch all done bits to 0 and all todo bits to 1.5105 MachineInstr *InsertPt =5106 BuildMI(LoopBB, I, DL, TII->get(LMC.XorTermOpc), LMC.ExecReg)5107 .addReg(LMC.ExecReg)5108 .addReg(NewExec);5109 5110 // XXX - s_xor_b64 sets scc to 1 if the result is nonzero, so can we use5111 // s_cbranch_scc0?5112 5113 // Loop back to V_READFIRSTLANE_B32 if there are still variants to cover.5114 // clang-format off5115 BuildMI(LoopBB, I, DL, TII->get(AMDGPU::S_CBRANCH_EXECNZ))5116 .addMBB(&LoopBB);5117 // clang-format on5118 5119 return InsertPt->getIterator();5120}5121 5122// This has slightly sub-optimal regalloc when the source vector is killed by5123// the read. The register allocator does not understand that the kill is5124// per-workitem, so is kept alive for the whole loop so we end up not re-using a5125// subregister from it, using 1 more VGPR than necessary. This was saved when5126// this was expanded after register allocation.5127static MachineBasicBlock::iterator5128loadM0FromVGPR(const SIInstrInfo *TII, MachineBasicBlock &MBB, MachineInstr &MI,5129 unsigned InitResultReg, unsigned PhiReg, int Offset,5130 bool UseGPRIdxMode, Register &SGPRIdxReg) {5131 MachineFunction *MF = MBB.getParent();5132 const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>();5133 const SIRegisterInfo *TRI = ST.getRegisterInfo();5134 MachineRegisterInfo &MRI = MF->getRegInfo();5135 const DebugLoc &DL = MI.getDebugLoc();5136 MachineBasicBlock::iterator I(&MI);5137 5138 const auto *BoolXExecRC = TRI->getWaveMaskRegClass();5139 Register DstReg = MI.getOperand(0).getReg();5140 Register SaveExec = MRI.createVirtualRegister(BoolXExecRC);5141 Register TmpExec = MRI.createVirtualRegister(BoolXExecRC);5142 const AMDGPU::LaneMaskConstants &LMC = AMDGPU::LaneMaskConstants::get(ST);5143 5144 BuildMI(MBB, I, DL, TII->get(TargetOpcode::IMPLICIT_DEF), TmpExec);5145 5146 // Save the EXEC mask5147 // clang-format off5148 BuildMI(MBB, I, DL, TII->get(LMC.MovOpc), SaveExec)5149 .addReg(LMC.ExecReg);5150 // clang-format on5151 5152 auto [LoopBB, RemainderBB] = splitBlockForLoop(MI, MBB, false);5153 5154 const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);5155 5156 auto InsPt = emitLoadM0FromVGPRLoop(TII, MRI, MBB, *LoopBB, DL, *Idx,5157 InitResultReg, DstReg, PhiReg, TmpExec,5158 Offset, UseGPRIdxMode, SGPRIdxReg);5159 5160 MachineBasicBlock *LandingPad = MF->CreateMachineBasicBlock();5161 MachineFunction::iterator MBBI(LoopBB);5162 ++MBBI;5163 MF->insert(MBBI, LandingPad);5164 LoopBB->removeSuccessor(RemainderBB);5165 LandingPad->addSuccessor(RemainderBB);5166 LoopBB->addSuccessor(LandingPad);5167 MachineBasicBlock::iterator First = LandingPad->begin();5168 // clang-format off5169 BuildMI(*LandingPad, First, DL, TII->get(LMC.MovOpc), LMC.ExecReg)5170 .addReg(SaveExec);5171 // clang-format on5172 5173 return InsPt;5174}5175 5176// Returns subreg index, offset5177static std::pair<unsigned, int>5178computeIndirectRegAndOffset(const SIRegisterInfo &TRI,5179 const TargetRegisterClass *SuperRC, unsigned VecReg,5180 int Offset) {5181 int NumElts = TRI.getRegSizeInBits(*SuperRC) / 32;5182 5183 // Skip out of bounds offsets, or else we would end up using an undefined5184 // register.5185 if (Offset >= NumElts || Offset < 0)5186 return std::pair(AMDGPU::sub0, Offset);5187 5188 return std::pair(SIRegisterInfo::getSubRegFromChannel(Offset), 0);5189}5190 5191static void setM0ToIndexFromSGPR(const SIInstrInfo *TII,5192 MachineRegisterInfo &MRI, MachineInstr &MI,5193 int Offset) {5194 MachineBasicBlock *MBB = MI.getParent();5195 const DebugLoc &DL = MI.getDebugLoc();5196 MachineBasicBlock::iterator I(&MI);5197 5198 const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);5199 5200 assert(Idx->getReg() != AMDGPU::NoRegister);5201 5202 if (Offset == 0) {5203 // clang-format off5204 BuildMI(*MBB, I, DL, TII->get(AMDGPU::COPY), AMDGPU::M0)5205 .add(*Idx);5206 // clang-format on5207 } else {5208 BuildMI(*MBB, I, DL, TII->get(AMDGPU::S_ADD_I32), AMDGPU::M0)5209 .add(*Idx)5210 .addImm(Offset);5211 }5212}5213 5214static Register getIndirectSGPRIdx(const SIInstrInfo *TII,5215 MachineRegisterInfo &MRI, MachineInstr &MI,5216 int Offset) {5217 MachineBasicBlock *MBB = MI.getParent();5218 const DebugLoc &DL = MI.getDebugLoc();5219 MachineBasicBlock::iterator I(&MI);5220 5221 const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);5222 5223 if (Offset == 0)5224 return Idx->getReg();5225 5226 Register Tmp = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);5227 BuildMI(*MBB, I, DL, TII->get(AMDGPU::S_ADD_I32), Tmp)5228 .add(*Idx)5229 .addImm(Offset);5230 return Tmp;5231}5232 5233static MachineBasicBlock *emitIndirectSrc(MachineInstr &MI,5234 MachineBasicBlock &MBB,5235 const GCNSubtarget &ST) {5236 const SIInstrInfo *TII = ST.getInstrInfo();5237 const SIRegisterInfo &TRI = TII->getRegisterInfo();5238 MachineFunction *MF = MBB.getParent();5239 MachineRegisterInfo &MRI = MF->getRegInfo();5240 5241 Register Dst = MI.getOperand(0).getReg();5242 const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);5243 Register SrcReg = TII->getNamedOperand(MI, AMDGPU::OpName::src)->getReg();5244 int Offset = TII->getNamedOperand(MI, AMDGPU::OpName::offset)->getImm();5245 5246 const TargetRegisterClass *VecRC = MRI.getRegClass(SrcReg);5247 const TargetRegisterClass *IdxRC = MRI.getRegClass(Idx->getReg());5248 5249 unsigned SubReg;5250 std::tie(SubReg, Offset) =5251 computeIndirectRegAndOffset(TRI, VecRC, SrcReg, Offset);5252 5253 const bool UseGPRIdxMode = ST.useVGPRIndexMode();5254 5255 // Check for a SGPR index.5256 if (TII->getRegisterInfo().isSGPRClass(IdxRC)) {5257 MachineBasicBlock::iterator I(&MI);5258 const DebugLoc &DL = MI.getDebugLoc();5259 5260 if (UseGPRIdxMode) {5261 // TODO: Look at the uses to avoid the copy. This may require rescheduling5262 // to avoid interfering with other uses, so probably requires a new5263 // optimization pass.5264 Register Idx = getIndirectSGPRIdx(TII, MRI, MI, Offset);5265 5266 const MCInstrDesc &GPRIDXDesc =5267 TII->getIndirectGPRIDXPseudo(TRI.getRegSizeInBits(*VecRC), true);5268 BuildMI(MBB, I, DL, GPRIDXDesc, Dst)5269 .addReg(SrcReg)5270 .addReg(Idx)5271 .addImm(SubReg);5272 } else {5273 setM0ToIndexFromSGPR(TII, MRI, MI, Offset);5274 5275 BuildMI(MBB, I, DL, TII->get(AMDGPU::V_MOVRELS_B32_e32), Dst)5276 .addReg(SrcReg, 0, SubReg)5277 .addReg(SrcReg, RegState::Implicit);5278 }5279 5280 MI.eraseFromParent();5281 5282 return &MBB;5283 }5284 5285 // Control flow needs to be inserted if indexing with a VGPR.5286 const DebugLoc &DL = MI.getDebugLoc();5287 MachineBasicBlock::iterator I(&MI);5288 5289 Register PhiReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);5290 Register InitReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);5291 5292 BuildMI(MBB, I, DL, TII->get(TargetOpcode::IMPLICIT_DEF), InitReg);5293 5294 Register SGPRIdxReg;5295 auto InsPt = loadM0FromVGPR(TII, MBB, MI, InitReg, PhiReg, Offset,5296 UseGPRIdxMode, SGPRIdxReg);5297 5298 MachineBasicBlock *LoopBB = InsPt->getParent();5299 5300 if (UseGPRIdxMode) {5301 const MCInstrDesc &GPRIDXDesc =5302 TII->getIndirectGPRIDXPseudo(TRI.getRegSizeInBits(*VecRC), true);5303 5304 BuildMI(*LoopBB, InsPt, DL, GPRIDXDesc, Dst)5305 .addReg(SrcReg)5306 .addReg(SGPRIdxReg)5307 .addImm(SubReg);5308 } else {5309 BuildMI(*LoopBB, InsPt, DL, TII->get(AMDGPU::V_MOVRELS_B32_e32), Dst)5310 .addReg(SrcReg, 0, SubReg)5311 .addReg(SrcReg, RegState::Implicit);5312 }5313 5314 MI.eraseFromParent();5315 5316 return LoopBB;5317}5318 5319static MachineBasicBlock *emitIndirectDst(MachineInstr &MI,5320 MachineBasicBlock &MBB,5321 const GCNSubtarget &ST) {5322 const SIInstrInfo *TII = ST.getInstrInfo();5323 const SIRegisterInfo &TRI = TII->getRegisterInfo();5324 MachineFunction *MF = MBB.getParent();5325 MachineRegisterInfo &MRI = MF->getRegInfo();5326 5327 Register Dst = MI.getOperand(0).getReg();5328 const MachineOperand *SrcVec = TII->getNamedOperand(MI, AMDGPU::OpName::src);5329 const MachineOperand *Idx = TII->getNamedOperand(MI, AMDGPU::OpName::idx);5330 const MachineOperand *Val = TII->getNamedOperand(MI, AMDGPU::OpName::val);5331 int Offset = TII->getNamedOperand(MI, AMDGPU::OpName::offset)->getImm();5332 const TargetRegisterClass *VecRC = MRI.getRegClass(SrcVec->getReg());5333 const TargetRegisterClass *IdxRC = MRI.getRegClass(Idx->getReg());5334 5335 // This can be an immediate, but will be folded later.5336 assert(Val->getReg());5337 5338 unsigned SubReg;5339 std::tie(SubReg, Offset) =5340 computeIndirectRegAndOffset(TRI, VecRC, SrcVec->getReg(), Offset);5341 const bool UseGPRIdxMode = ST.useVGPRIndexMode();5342 5343 if (Idx->getReg() == AMDGPU::NoRegister) {5344 MachineBasicBlock::iterator I(&MI);5345 const DebugLoc &DL = MI.getDebugLoc();5346 5347 assert(Offset == 0);5348 5349 BuildMI(MBB, I, DL, TII->get(TargetOpcode::INSERT_SUBREG), Dst)5350 .add(*SrcVec)5351 .add(*Val)5352 .addImm(SubReg);5353 5354 MI.eraseFromParent();5355 return &MBB;5356 }5357 5358 // Check for a SGPR index.5359 if (TII->getRegisterInfo().isSGPRClass(IdxRC)) {5360 MachineBasicBlock::iterator I(&MI);5361 const DebugLoc &DL = MI.getDebugLoc();5362 5363 if (UseGPRIdxMode) {5364 Register Idx = getIndirectSGPRIdx(TII, MRI, MI, Offset);5365 5366 const MCInstrDesc &GPRIDXDesc =5367 TII->getIndirectGPRIDXPseudo(TRI.getRegSizeInBits(*VecRC), false);5368 BuildMI(MBB, I, DL, GPRIDXDesc, Dst)5369 .addReg(SrcVec->getReg())5370 .add(*Val)5371 .addReg(Idx)5372 .addImm(SubReg);5373 } else {5374 setM0ToIndexFromSGPR(TII, MRI, MI, Offset);5375 5376 const MCInstrDesc &MovRelDesc = TII->getIndirectRegWriteMovRelPseudo(5377 TRI.getRegSizeInBits(*VecRC), 32, false);5378 BuildMI(MBB, I, DL, MovRelDesc, Dst)5379 .addReg(SrcVec->getReg())5380 .add(*Val)5381 .addImm(SubReg);5382 }5383 MI.eraseFromParent();5384 return &MBB;5385 }5386 5387 // Control flow needs to be inserted if indexing with a VGPR.5388 if (Val->isReg())5389 MRI.clearKillFlags(Val->getReg());5390 5391 const DebugLoc &DL = MI.getDebugLoc();5392 5393 Register PhiReg = MRI.createVirtualRegister(VecRC);5394 5395 Register SGPRIdxReg;5396 auto InsPt = loadM0FromVGPR(TII, MBB, MI, SrcVec->getReg(), PhiReg, Offset,5397 UseGPRIdxMode, SGPRIdxReg);5398 MachineBasicBlock *LoopBB = InsPt->getParent();5399 5400 if (UseGPRIdxMode) {5401 const MCInstrDesc &GPRIDXDesc =5402 TII->getIndirectGPRIDXPseudo(TRI.getRegSizeInBits(*VecRC), false);5403 5404 BuildMI(*LoopBB, InsPt, DL, GPRIDXDesc, Dst)5405 .addReg(PhiReg)5406 .add(*Val)5407 .addReg(SGPRIdxReg)5408 .addImm(SubReg);5409 } else {5410 const MCInstrDesc &MovRelDesc = TII->getIndirectRegWriteMovRelPseudo(5411 TRI.getRegSizeInBits(*VecRC), 32, false);5412 BuildMI(*LoopBB, InsPt, DL, MovRelDesc, Dst)5413 .addReg(PhiReg)5414 .add(*Val)5415 .addImm(SubReg);5416 }5417 5418 MI.eraseFromParent();5419 return LoopBB;5420}5421 5422static MachineBasicBlock *Expand64BitScalarArithmetic(MachineInstr &MI,5423 MachineBasicBlock *BB) {5424 // For targets older than GFX12, we emit a sequence of 32-bit operations.5425 // For GFX12, we emit s_add_u64 and s_sub_u64.5426 MachineFunction *MF = BB->getParent();5427 const SIInstrInfo *TII = MF->getSubtarget<GCNSubtarget>().getInstrInfo();5428 const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>();5429 MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();5430 const DebugLoc &DL = MI.getDebugLoc();5431 MachineOperand &Dest = MI.getOperand(0);5432 MachineOperand &Src0 = MI.getOperand(1);5433 MachineOperand &Src1 = MI.getOperand(2);5434 bool IsAdd = (MI.getOpcode() == AMDGPU::S_ADD_U64_PSEUDO);5435 if (ST.hasScalarAddSub64()) {5436 unsigned Opc = IsAdd ? AMDGPU::S_ADD_U64 : AMDGPU::S_SUB_U64;5437 // clang-format off5438 BuildMI(*BB, MI, DL, TII->get(Opc), Dest.getReg())5439 .add(Src0)5440 .add(Src1);5441 // clang-format on5442 } else {5443 const SIRegisterInfo *TRI = ST.getRegisterInfo();5444 const TargetRegisterClass *BoolRC = TRI->getBoolRC();5445 5446 Register DestSub0 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5447 Register DestSub1 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5448 5449 MachineOperand Src0Sub0 = TII->buildExtractSubRegOrImm(5450 MI, MRI, Src0, BoolRC, AMDGPU::sub0, &AMDGPU::SReg_32RegClass);5451 MachineOperand Src0Sub1 = TII->buildExtractSubRegOrImm(5452 MI, MRI, Src0, BoolRC, AMDGPU::sub1, &AMDGPU::SReg_32RegClass);5453 5454 MachineOperand Src1Sub0 = TII->buildExtractSubRegOrImm(5455 MI, MRI, Src1, BoolRC, AMDGPU::sub0, &AMDGPU::SReg_32RegClass);5456 MachineOperand Src1Sub1 = TII->buildExtractSubRegOrImm(5457 MI, MRI, Src1, BoolRC, AMDGPU::sub1, &AMDGPU::SReg_32RegClass);5458 5459 unsigned LoOpc = IsAdd ? AMDGPU::S_ADD_U32 : AMDGPU::S_SUB_U32;5460 unsigned HiOpc = IsAdd ? AMDGPU::S_ADDC_U32 : AMDGPU::S_SUBB_U32;5461 BuildMI(*BB, MI, DL, TII->get(LoOpc), DestSub0).add(Src0Sub0).add(Src1Sub0);5462 BuildMI(*BB, MI, DL, TII->get(HiOpc), DestSub1).add(Src0Sub1).add(Src1Sub1);5463 BuildMI(*BB, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), Dest.getReg())5464 .addReg(DestSub0)5465 .addImm(AMDGPU::sub0)5466 .addReg(DestSub1)5467 .addImm(AMDGPU::sub1);5468 }5469 MI.eraseFromParent();5470 return BB;5471}5472 5473static uint32_t getIdentityValueFor32BitWaveReduction(unsigned Opc) {5474 switch (Opc) {5475 case AMDGPU::S_MIN_U32:5476 return std::numeric_limits<uint32_t>::max();5477 case AMDGPU::S_MIN_I32:5478 return std::numeric_limits<int32_t>::max();5479 case AMDGPU::S_MAX_U32:5480 return std::numeric_limits<uint32_t>::min();5481 case AMDGPU::S_MAX_I32:5482 return std::numeric_limits<int32_t>::min();5483 case AMDGPU::V_ADD_F32_e64: // -0.05484 return 0x80000000;5485 case AMDGPU::V_SUB_F32_e64: // +0.05486 return 0x0;5487 case AMDGPU::S_ADD_I32:5488 case AMDGPU::S_SUB_I32:5489 case AMDGPU::S_OR_B32:5490 case AMDGPU::S_XOR_B32:5491 return std::numeric_limits<uint32_t>::min();5492 case AMDGPU::S_AND_B32:5493 return std::numeric_limits<uint32_t>::max();5494 case AMDGPU::V_MIN_F32_e64:5495 case AMDGPU::V_MAX_F32_e64:5496 return 0x7fc00000; // qNAN5497 default:5498 llvm_unreachable(5499 "Unexpected opcode in getIdentityValueFor32BitWaveReduction");5500 }5501}5502 5503static uint64_t getIdentityValueFor64BitWaveReduction(unsigned Opc) {5504 switch (Opc) {5505 case AMDGPU::V_CMP_LT_U64_e64: // umin.u645506 return std::numeric_limits<uint64_t>::max();5507 case AMDGPU::V_CMP_LT_I64_e64: // min.i645508 return std::numeric_limits<int64_t>::max();5509 case AMDGPU::V_CMP_GT_U64_e64: // umax.u645510 return std::numeric_limits<uint64_t>::min();5511 case AMDGPU::V_CMP_GT_I64_e64: // max.i645512 return std::numeric_limits<int64_t>::min();5513 case AMDGPU::S_ADD_U64_PSEUDO:5514 case AMDGPU::S_SUB_U64_PSEUDO:5515 case AMDGPU::S_OR_B64:5516 case AMDGPU::S_XOR_B64:5517 return std::numeric_limits<uint64_t>::min();5518 case AMDGPU::S_AND_B64:5519 return std::numeric_limits<uint64_t>::max();5520 default:5521 llvm_unreachable(5522 "Unexpected opcode in getIdentityValueFor64BitWaveReduction");5523 }5524}5525 5526static bool is32bitWaveReduceOperation(unsigned Opc) {5527 return Opc == AMDGPU::S_MIN_U32 || Opc == AMDGPU::S_MIN_I32 ||5528 Opc == AMDGPU::S_MAX_U32 || Opc == AMDGPU::S_MAX_I32 ||5529 Opc == AMDGPU::S_ADD_I32 || Opc == AMDGPU::S_SUB_I32 ||5530 Opc == AMDGPU::S_AND_B32 || Opc == AMDGPU::S_OR_B32 ||5531 Opc == AMDGPU::S_XOR_B32 || Opc == AMDGPU::V_MIN_F32_e64 ||5532 Opc == AMDGPU::V_MAX_F32_e64 || Opc == AMDGPU::V_ADD_F32_e64 ||5533 Opc == AMDGPU::V_SUB_F32_e64;5534}5535 5536static bool isFloatingPointWaveReduceOperation(unsigned Opc) {5537 return Opc == AMDGPU::V_MIN_F32_e64 || Opc == AMDGPU::V_MAX_F32_e64 ||5538 Opc == AMDGPU::V_ADD_F32_e64 || Opc == AMDGPU::V_SUB_F32_e64;5539}5540 5541static MachineBasicBlock *lowerWaveReduce(MachineInstr &MI,5542 MachineBasicBlock &BB,5543 const GCNSubtarget &ST,5544 unsigned Opc) {5545 MachineRegisterInfo &MRI = BB.getParent()->getRegInfo();5546 const SIRegisterInfo *TRI = ST.getRegisterInfo();5547 const DebugLoc &DL = MI.getDebugLoc();5548 const SIInstrInfo *TII = ST.getInstrInfo();5549 5550 // Reduction operations depend on whether the input operand is SGPR or VGPR.5551 Register SrcReg = MI.getOperand(1).getReg();5552 bool isSGPR = TRI->isSGPRClass(MRI.getRegClass(SrcReg));5553 Register DstReg = MI.getOperand(0).getReg();5554 MachineBasicBlock *RetBB = nullptr;5555 if (isSGPR) {5556 switch (Opc) {5557 case AMDGPU::S_MIN_U32:5558 case AMDGPU::S_MIN_I32:5559 case AMDGPU::V_MIN_F32_e64:5560 case AMDGPU::S_MAX_U32:5561 case AMDGPU::S_MAX_I32:5562 case AMDGPU::V_MAX_F32_e64:5563 case AMDGPU::S_AND_B32:5564 case AMDGPU::S_OR_B32: {5565 // Idempotent operations.5566 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B32), DstReg).addReg(SrcReg);5567 RetBB = &BB;5568 break;5569 }5570 case AMDGPU::V_CMP_LT_U64_e64: // umin5571 case AMDGPU::V_CMP_LT_I64_e64: // min5572 case AMDGPU::V_CMP_GT_U64_e64: // umax5573 case AMDGPU::V_CMP_GT_I64_e64: // max5574 case AMDGPU::S_AND_B64:5575 case AMDGPU::S_OR_B64: {5576 // Idempotent operations.5577 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B64), DstReg).addReg(SrcReg);5578 RetBB = &BB;5579 break;5580 }5581 case AMDGPU::S_XOR_B32:5582 case AMDGPU::S_XOR_B64:5583 case AMDGPU::S_ADD_I32:5584 case AMDGPU::S_ADD_U64_PSEUDO:5585 case AMDGPU::V_ADD_F32_e64:5586 case AMDGPU::S_SUB_I32:5587 case AMDGPU::S_SUB_U64_PSEUDO:5588 case AMDGPU::V_SUB_F32_e64: {5589 const TargetRegisterClass *WaveMaskRegClass = TRI->getWaveMaskRegClass();5590 const TargetRegisterClass *DstRegClass = MRI.getRegClass(DstReg);5591 Register ExecMask = MRI.createVirtualRegister(WaveMaskRegClass);5592 Register NumActiveLanes =5593 MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5594 5595 bool IsWave32 = ST.isWave32();5596 unsigned MovOpc = IsWave32 ? AMDGPU::S_MOV_B32 : AMDGPU::S_MOV_B64;5597 MCRegister ExecReg = IsWave32 ? AMDGPU::EXEC_LO : AMDGPU::EXEC;5598 unsigned BitCountOpc =5599 IsWave32 ? AMDGPU::S_BCNT1_I32_B32 : AMDGPU::S_BCNT1_I32_B64;5600 5601 BuildMI(BB, MI, DL, TII->get(MovOpc), ExecMask).addReg(ExecReg);5602 5603 auto NewAccumulator =5604 BuildMI(BB, MI, DL, TII->get(BitCountOpc), NumActiveLanes)5605 .addReg(ExecMask);5606 5607 switch (Opc) {5608 case AMDGPU::S_XOR_B32:5609 case AMDGPU::S_XOR_B64: {5610 // Performing an XOR operation on a uniform value5611 // depends on the parity of the number of active lanes.5612 // For even parity, the result will be 0, for odd5613 // parity the result will be the same as the input value.5614 Register ParityRegister =5615 MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5616 5617 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_AND_B32), ParityRegister)5618 .addReg(NewAccumulator->getOperand(0).getReg())5619 .addImm(1)5620 .setOperandDead(3); // Dead scc5621 if (Opc == AMDGPU::S_XOR_B32) {5622 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DstReg)5623 .addReg(SrcReg)5624 .addReg(ParityRegister);5625 } else {5626 Register DestSub0 =5627 MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5628 Register DestSub1 =5629 MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5630 5631 const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg);5632 const TargetRegisterClass *SrcSubRC =5633 TRI->getSubRegisterClass(SrcRC, AMDGPU::sub0);5634 5635 MachineOperand Op1L = TII->buildExtractSubRegOrImm(5636 MI, MRI, MI.getOperand(1), SrcRC, AMDGPU::sub0, SrcSubRC);5637 MachineOperand Op1H = TII->buildExtractSubRegOrImm(5638 MI, MRI, MI.getOperand(1), SrcRC, AMDGPU::sub1, SrcSubRC);5639 5640 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DestSub0)5641 .add(Op1L)5642 .addReg(ParityRegister);5643 5644 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DestSub1)5645 .add(Op1H)5646 .addReg(ParityRegister);5647 5648 BuildMI(BB, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), DstReg)5649 .addReg(DestSub0)5650 .addImm(AMDGPU::sub0)5651 .addReg(DestSub1)5652 .addImm(AMDGPU::sub1);5653 }5654 break;5655 }5656 case AMDGPU::S_SUB_I32: {5657 Register NegatedVal = MRI.createVirtualRegister(DstRegClass);5658 5659 // Take the negation of the source operand.5660 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_SUB_I32), NegatedVal)5661 .addImm(0)5662 .addReg(SrcReg);5663 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DstReg)5664 .addReg(NegatedVal)5665 .addReg(NewAccumulator->getOperand(0).getReg());5666 break;5667 }5668 case AMDGPU::S_ADD_I32: {5669 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DstReg)5670 .addReg(SrcReg)5671 .addReg(NewAccumulator->getOperand(0).getReg());5672 break;5673 }5674 case AMDGPU::S_ADD_U64_PSEUDO:5675 case AMDGPU::S_SUB_U64_PSEUDO: {5676 Register DestSub0 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5677 Register DestSub1 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5678 Register Op1H_Op0L_Reg =5679 MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5680 Register Op1L_Op0H_Reg =5681 MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5682 Register CarryReg = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5683 Register AddReg = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5684 Register NegatedValLo =5685 MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5686 Register NegatedValHi =5687 MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5688 5689 const TargetRegisterClass *Src1RC = MRI.getRegClass(SrcReg);5690 const TargetRegisterClass *Src1SubRC =5691 TRI->getSubRegisterClass(Src1RC, AMDGPU::sub0);5692 5693 MachineOperand Op1L = TII->buildExtractSubRegOrImm(5694 MI, MRI, MI.getOperand(1), Src1RC, AMDGPU::sub0, Src1SubRC);5695 MachineOperand Op1H = TII->buildExtractSubRegOrImm(5696 MI, MRI, MI.getOperand(1), Src1RC, AMDGPU::sub1, Src1SubRC);5697 5698 if (Opc == AMDGPU::S_SUB_U64_PSEUDO) {5699 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_SUB_I32), NegatedValLo)5700 .addImm(0)5701 .addReg(NewAccumulator->getOperand(0).getReg())5702 .setOperandDead(3); // Dead scc5703 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_ASHR_I32), NegatedValHi)5704 .addReg(NegatedValLo)5705 .addImm(31)5706 .setOperandDead(3); // Dead scc5707 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), Op1L_Op0H_Reg)5708 .add(Op1L)5709 .addReg(NegatedValHi);5710 }5711 Register LowOpcode = Opc == AMDGPU::S_SUB_U64_PSEUDO5712 ? NegatedValLo5713 : NewAccumulator->getOperand(0).getReg();5714 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DestSub0)5715 .add(Op1L)5716 .addReg(LowOpcode);5717 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_HI_U32), CarryReg)5718 .add(Op1L)5719 .addReg(LowOpcode);5720 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), Op1H_Op0L_Reg)5721 .add(Op1H)5722 .addReg(LowOpcode);5723 5724 Register HiVal = Opc == AMDGPU::S_SUB_U64_PSEUDO ? AddReg : DestSub1;5725 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_ADD_U32), HiVal)5726 .addReg(CarryReg)5727 .addReg(Op1H_Op0L_Reg)5728 .setOperandDead(3); // Dead scc5729 5730 if (Opc == AMDGPU::S_SUB_U64_PSEUDO) {5731 BuildMI(BB, MI, DL, TII->get(AMDGPU::S_ADD_U32), DestSub1)5732 .addReg(HiVal)5733 .addReg(Op1L_Op0H_Reg)5734 .setOperandDead(3); // Dead scc5735 }5736 BuildMI(BB, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), DstReg)5737 .addReg(DestSub0)5738 .addImm(AMDGPU::sub0)5739 .addReg(DestSub1)5740 .addImm(AMDGPU::sub1);5741 break;5742 }5743 case AMDGPU::V_ADD_F32_e64:5744 case AMDGPU::V_SUB_F32_e64: {5745 Register ActiveLanesVreg =5746 MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);5747 Register DstVreg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);5748 // Get number of active lanes as a float val.5749 BuildMI(BB, MI, DL, TII->get(AMDGPU::V_CVT_F32_I32_e64),5750 ActiveLanesVreg)5751 .addReg(NewAccumulator->getOperand(0).getReg())5752 .addImm(0) // clamp5753 .addImm(0); // output-modifier5754 5755 // Take negation of input for SUB reduction5756 unsigned srcMod = Opc == AMDGPU::V_SUB_F32_e64 ? 1 : 0;5757 BuildMI(BB, MI, DL, TII->get(AMDGPU::V_MUL_F32_e64), DstVreg)5758 .addImm(srcMod) // src0 modifier5759 .addReg(SrcReg)5760 .addImm(0) // src1 modifier5761 .addReg(ActiveLanesVreg)5762 .addImm(0) // clamp5763 .addImm(0); // output-mod5764 BuildMI(BB, MI, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), DstReg)5765 .addReg(DstVreg);5766 }5767 }5768 RetBB = &BB;5769 }5770 }5771 } else {5772 // TODO: Implement DPP Strategy and switch based on immediate strategy5773 // operand. For now, for all the cases (default, Iterative and DPP we use5774 // iterative approach by default.)5775 5776 // To reduce the VGPR using iterative approach, we need to iterate5777 // over all the active lanes. Lowering consists of ComputeLoop,5778 // which iterate over only active lanes. We use copy of EXEC register5779 // as induction variable and every active lane modifies it using bitset05780 // so that we will get the next active lane for next iteration.5781 MachineBasicBlock::iterator I = BB.end();5782 Register SrcReg = MI.getOperand(1).getReg();5783 bool is32BitOpc = is32bitWaveReduceOperation(Opc);5784 bool isFPOp = isFloatingPointWaveReduceOperation(Opc);5785 5786 // Create Control flow for loop5787 // Split MI's Machine Basic block into For loop5788 auto [ComputeLoop, ComputeEnd] = splitBlockForLoop(MI, BB, true);5789 5790 // Create virtual registers required for lowering.5791 const TargetRegisterClass *WaveMaskRegClass = TRI->getWaveMaskRegClass();5792 const TargetRegisterClass *DstRegClass = MRI.getRegClass(DstReg);5793 Register LoopIterator = MRI.createVirtualRegister(WaveMaskRegClass);5794 Register IdentityValReg = MRI.createVirtualRegister(DstRegClass);5795 Register AccumulatorReg = MRI.createVirtualRegister(DstRegClass);5796 Register ActiveBitsReg = MRI.createVirtualRegister(WaveMaskRegClass);5797 Register NewActiveBitsReg = MRI.createVirtualRegister(WaveMaskRegClass);5798 Register FF1Reg = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);5799 Register LaneValueReg = MRI.createVirtualRegister(DstRegClass);5800 5801 bool IsWave32 = ST.isWave32();5802 unsigned MovOpcForExec = IsWave32 ? AMDGPU::S_MOV_B32 : AMDGPU::S_MOV_B64;5803 unsigned ExecReg = IsWave32 ? AMDGPU::EXEC_LO : AMDGPU::EXEC;5804 5805 // Create initial values of induction variable from Exec, Accumulator and5806 // insert branch instr to newly created ComputeBlock5807 BuildMI(BB, I, DL, TII->get(MovOpcForExec), LoopIterator).addReg(ExecReg);5808 if (is32BitOpc) {5809 uint32_t IdentityValue = getIdentityValueFor32BitWaveReduction(Opc);5810 BuildMI(BB, I, DL, TII->get(AMDGPU::S_MOV_B32), IdentityValReg)5811 .addImm(IdentityValue);5812 } else {5813 uint64_t IdentityValue = getIdentityValueFor64BitWaveReduction(Opc);5814 BuildMI(BB, I, DL, TII->get(AMDGPU::S_MOV_B64_IMM_PSEUDO), IdentityValReg)5815 .addImm(IdentityValue);5816 }5817 // clang-format off5818 BuildMI(BB, I, DL, TII->get(AMDGPU::S_BRANCH))5819 .addMBB(ComputeLoop);5820 // clang-format on5821 5822 // Start constructing ComputeLoop5823 I = ComputeLoop->begin();5824 auto Accumulator =5825 BuildMI(*ComputeLoop, I, DL, TII->get(AMDGPU::PHI), AccumulatorReg)5826 .addReg(IdentityValReg)5827 .addMBB(&BB);5828 auto ActiveBits =5829 BuildMI(*ComputeLoop, I, DL, TII->get(AMDGPU::PHI), ActiveBitsReg)5830 .addReg(LoopIterator)5831 .addMBB(&BB);5832 5833 I = ComputeLoop->end();5834 MachineInstr *NewAccumulator;5835 // Perform the computations5836 unsigned SFFOpc = IsWave32 ? AMDGPU::S_FF1_I32_B32 : AMDGPU::S_FF1_I32_B64;5837 BuildMI(*ComputeLoop, I, DL, TII->get(SFFOpc), FF1Reg)5838 .addReg(ActiveBitsReg);5839 if (is32BitOpc) {5840 BuildMI(*ComputeLoop, I, DL, TII->get(AMDGPU::V_READLANE_B32),5841 LaneValueReg)5842 .addReg(SrcReg)5843 .addReg(FF1Reg);5844 if (isFPOp) {5845 Register LaneValVreg =5846 MRI.createVirtualRegister(MRI.getRegClass(SrcReg));5847 Register DstVreg = MRI.createVirtualRegister(MRI.getRegClass(SrcReg));5848 // Get the Lane Value in VGPR to avoid the Constant Bus Restriction5849 BuildMI(*ComputeLoop, I, DL, TII->get(AMDGPU::V_MOV_B32_e32),5850 LaneValVreg)5851 .addReg(LaneValueReg);5852 BuildMI(*ComputeLoop, I, DL, TII->get(Opc), DstVreg)5853 .addImm(0) // src0 modifier5854 .addReg(Accumulator->getOperand(0).getReg())5855 .addImm(0) // src1 modifier5856 .addReg(LaneValVreg)5857 .addImm(0) // clamp5858 .addImm(0); // omod5859 NewAccumulator = BuildMI(*ComputeLoop, I, DL,5860 TII->get(AMDGPU::V_READFIRSTLANE_B32), DstReg)5861 .addReg(DstVreg);5862 } else {5863 NewAccumulator = BuildMI(*ComputeLoop, I, DL, TII->get(Opc), DstReg)5864 .addReg(Accumulator->getOperand(0).getReg())5865 .addReg(LaneValueReg);5866 }5867 } else {5868 Register LaneValueLoReg =5869 MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);5870 Register LaneValueHiReg =5871 MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);5872 Register LaneValReg = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);5873 const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg);5874 const TargetRegisterClass *SrcSubRC =5875 TRI->getSubRegisterClass(SrcRC, AMDGPU::sub0);5876 MachineOperand Op1L = TII->buildExtractSubRegOrImm(5877 MI, MRI, MI.getOperand(1), SrcRC, AMDGPU::sub0, SrcSubRC);5878 MachineOperand Op1H = TII->buildExtractSubRegOrImm(5879 MI, MRI, MI.getOperand(1), SrcRC, AMDGPU::sub1, SrcSubRC);5880 // lane value input should be in an sgpr5881 BuildMI(*ComputeLoop, I, DL, TII->get(AMDGPU::V_READLANE_B32),5882 LaneValueLoReg)5883 .add(Op1L)5884 .addReg(FF1Reg);5885 BuildMI(*ComputeLoop, I, DL, TII->get(AMDGPU::V_READLANE_B32),5886 LaneValueHiReg)5887 .add(Op1H)5888 .addReg(FF1Reg);5889 auto LaneValue = BuildMI(*ComputeLoop, I, DL,5890 TII->get(TargetOpcode::REG_SEQUENCE), LaneValReg)5891 .addReg(LaneValueLoReg)5892 .addImm(AMDGPU::sub0)5893 .addReg(LaneValueHiReg)5894 .addImm(AMDGPU::sub1);5895 switch (Opc) {5896 case AMDGPU::S_OR_B64:5897 case AMDGPU::S_AND_B64:5898 case AMDGPU::S_XOR_B64: {5899 NewAccumulator = BuildMI(*ComputeLoop, I, DL, TII->get(Opc), DstReg)5900 .addReg(Accumulator->getOperand(0).getReg())5901 .addReg(LaneValue->getOperand(0).getReg())5902 .setOperandDead(3); // Dead scc5903 break;5904 }5905 case AMDGPU::V_CMP_GT_I64_e64:5906 case AMDGPU::V_CMP_GT_U64_e64:5907 case AMDGPU::V_CMP_LT_I64_e64:5908 case AMDGPU::V_CMP_LT_U64_e64: {5909 Register LaneMaskReg = MRI.createVirtualRegister(WaveMaskRegClass);5910 Register ComparisonResultReg =5911 MRI.createVirtualRegister(WaveMaskRegClass);5912 const TargetRegisterClass *VregClass = TRI->getVGPR64Class();5913 const TargetRegisterClass *VSubRegClass =5914 TRI->getSubRegisterClass(VregClass, AMDGPU::sub0);5915 Register AccumulatorVReg = MRI.createVirtualRegister(VregClass);5916 MachineOperand SrcReg0Sub0 =5917 TII->buildExtractSubRegOrImm(MI, MRI, Accumulator->getOperand(0),5918 VregClass, AMDGPU::sub0, VSubRegClass);5919 MachineOperand SrcReg0Sub1 =5920 TII->buildExtractSubRegOrImm(MI, MRI, Accumulator->getOperand(0),5921 VregClass, AMDGPU::sub1, VSubRegClass);5922 BuildMI(*ComputeLoop, I, DL, TII->get(TargetOpcode::REG_SEQUENCE),5923 AccumulatorVReg)5924 .add(SrcReg0Sub0)5925 .addImm(AMDGPU::sub0)5926 .add(SrcReg0Sub1)5927 .addImm(AMDGPU::sub1);5928 BuildMI(*ComputeLoop, I, DL, TII->get(Opc), LaneMaskReg)5929 .addReg(LaneValue->getOperand(0).getReg())5930 .addReg(AccumulatorVReg);5931 5932 unsigned AndOpc = IsWave32 ? AMDGPU::S_AND_B32 : AMDGPU::S_AND_B64;5933 BuildMI(*ComputeLoop, I, DL, TII->get(AndOpc), ComparisonResultReg)5934 .addReg(LaneMaskReg)5935 .addReg(ActiveBitsReg);5936 5937 NewAccumulator = BuildMI(*ComputeLoop, I, DL,5938 TII->get(AMDGPU::S_CSELECT_B64), DstReg)5939 .addReg(LaneValue->getOperand(0).getReg())5940 .addReg(Accumulator->getOperand(0).getReg());5941 break;5942 }5943 case AMDGPU::S_ADD_U64_PSEUDO:5944 case AMDGPU::S_SUB_U64_PSEUDO: {5945 NewAccumulator = BuildMI(*ComputeLoop, I, DL, TII->get(Opc), DstReg)5946 .addReg(Accumulator->getOperand(0).getReg())5947 .addReg(LaneValue->getOperand(0).getReg());5948 ComputeLoop = Expand64BitScalarArithmetic(*NewAccumulator, ComputeLoop);5949 break;5950 }5951 }5952 }5953 // Manipulate the iterator to get the next active lane5954 unsigned BITSETOpc =5955 IsWave32 ? AMDGPU::S_BITSET0_B32 : AMDGPU::S_BITSET0_B64;5956 BuildMI(*ComputeLoop, I, DL, TII->get(BITSETOpc), NewActiveBitsReg)5957 .addReg(FF1Reg)5958 .addReg(ActiveBitsReg);5959 5960 // Add phi nodes5961 Accumulator.addReg(DstReg).addMBB(ComputeLoop);5962 ActiveBits.addReg(NewActiveBitsReg).addMBB(ComputeLoop);5963 5964 // Creating branching5965 unsigned CMPOpc = IsWave32 ? AMDGPU::S_CMP_LG_U32 : AMDGPU::S_CMP_LG_U64;5966 BuildMI(*ComputeLoop, I, DL, TII->get(CMPOpc))5967 .addReg(NewActiveBitsReg)5968 .addImm(0);5969 BuildMI(*ComputeLoop, I, DL, TII->get(AMDGPU::S_CBRANCH_SCC1))5970 .addMBB(ComputeLoop);5971 5972 RetBB = ComputeEnd;5973 }5974 MI.eraseFromParent();5975 return RetBB;5976}5977 5978MachineBasicBlock *5979SITargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,5980 MachineBasicBlock *BB) const {5981 MachineFunction *MF = BB->getParent();5982 SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();5983 const GCNSubtarget &ST = MF->getSubtarget<GCNSubtarget>();5984 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();5985 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();5986 MachineRegisterInfo &MRI = MF->getRegInfo();5987 const DebugLoc &DL = MI.getDebugLoc();5988 5989 switch (MI.getOpcode()) {5990 case AMDGPU::WAVE_REDUCE_UMIN_PSEUDO_U32:5991 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_MIN_U32);5992 case AMDGPU::WAVE_REDUCE_UMIN_PSEUDO_U64:5993 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::V_CMP_LT_U64_e64);5994 case AMDGPU::WAVE_REDUCE_MIN_PSEUDO_I32:5995 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_MIN_I32);5996 case AMDGPU::WAVE_REDUCE_MIN_PSEUDO_I64:5997 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::V_CMP_LT_I64_e64);5998 case AMDGPU::WAVE_REDUCE_FMIN_PSEUDO_F32:5999 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::V_MIN_F32_e64);6000 case AMDGPU::WAVE_REDUCE_UMAX_PSEUDO_U32:6001 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_MAX_U32);6002 case AMDGPU::WAVE_REDUCE_UMAX_PSEUDO_U64:6003 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::V_CMP_GT_U64_e64);6004 case AMDGPU::WAVE_REDUCE_MAX_PSEUDO_I32:6005 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_MAX_I32);6006 case AMDGPU::WAVE_REDUCE_MAX_PSEUDO_I64:6007 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::V_CMP_GT_I64_e64);6008 case AMDGPU::WAVE_REDUCE_FMAX_PSEUDO_F32:6009 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::V_MAX_F32_e64);6010 case AMDGPU::WAVE_REDUCE_ADD_PSEUDO_I32:6011 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_ADD_I32);6012 case AMDGPU::WAVE_REDUCE_ADD_PSEUDO_U64:6013 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_ADD_U64_PSEUDO);6014 case AMDGPU::WAVE_REDUCE_FADD_PSEUDO_F32:6015 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::V_ADD_F32_e64);6016 case AMDGPU::WAVE_REDUCE_SUB_PSEUDO_I32:6017 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_SUB_I32);6018 case AMDGPU::WAVE_REDUCE_SUB_PSEUDO_U64:6019 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_SUB_U64_PSEUDO);6020 case AMDGPU::WAVE_REDUCE_FSUB_PSEUDO_F32:6021 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::V_SUB_F32_e64);6022 case AMDGPU::WAVE_REDUCE_AND_PSEUDO_B32:6023 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_AND_B32);6024 case AMDGPU::WAVE_REDUCE_AND_PSEUDO_B64:6025 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_AND_B64);6026 case AMDGPU::WAVE_REDUCE_OR_PSEUDO_B32:6027 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_OR_B32);6028 case AMDGPU::WAVE_REDUCE_OR_PSEUDO_B64:6029 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_OR_B64);6030 case AMDGPU::WAVE_REDUCE_XOR_PSEUDO_B32:6031 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_XOR_B32);6032 case AMDGPU::WAVE_REDUCE_XOR_PSEUDO_B64:6033 return lowerWaveReduce(MI, *BB, *getSubtarget(), AMDGPU::S_XOR_B64);6034 case AMDGPU::S_UADDO_PSEUDO:6035 case AMDGPU::S_USUBO_PSEUDO: {6036 MachineOperand &Dest0 = MI.getOperand(0);6037 MachineOperand &Dest1 = MI.getOperand(1);6038 MachineOperand &Src0 = MI.getOperand(2);6039 MachineOperand &Src1 = MI.getOperand(3);6040 6041 unsigned Opc = (MI.getOpcode() == AMDGPU::S_UADDO_PSEUDO)6042 ? AMDGPU::S_ADD_U326043 : AMDGPU::S_SUB_U32;6044 // clang-format off6045 BuildMI(*BB, MI, DL, TII->get(Opc), Dest0.getReg())6046 .add(Src0)6047 .add(Src1);6048 // clang-format on6049 6050 unsigned SelOpc =6051 Subtarget->isWave64() ? AMDGPU::S_CSELECT_B64 : AMDGPU::S_CSELECT_B32;6052 BuildMI(*BB, MI, DL, TII->get(SelOpc), Dest1.getReg()).addImm(-1).addImm(0);6053 6054 MI.eraseFromParent();6055 return BB;6056 }6057 case AMDGPU::S_ADD_U64_PSEUDO:6058 case AMDGPU::S_SUB_U64_PSEUDO: {6059 return Expand64BitScalarArithmetic(MI, BB);6060 }6061 case AMDGPU::V_ADD_U64_PSEUDO:6062 case AMDGPU::V_SUB_U64_PSEUDO: {6063 bool IsAdd = (MI.getOpcode() == AMDGPU::V_ADD_U64_PSEUDO);6064 6065 MachineOperand &Dest = MI.getOperand(0);6066 MachineOperand &Src0 = MI.getOperand(1);6067 MachineOperand &Src1 = MI.getOperand(2);6068 6069 if (ST.hasAddSubU64Insts()) {6070 auto I = BuildMI(*BB, MI, DL,6071 TII->get(IsAdd ? AMDGPU::V_ADD_U64_e646072 : AMDGPU::V_SUB_U64_e64),6073 Dest.getReg())6074 .add(Src0)6075 .add(Src1)6076 .addImm(0); // clamp6077 TII->legalizeOperands(*I);6078 MI.eraseFromParent();6079 return BB;6080 }6081 6082 if (IsAdd && ST.hasLshlAddU64Inst()) {6083 auto Add = BuildMI(*BB, MI, DL, TII->get(AMDGPU::V_LSHL_ADD_U64_e64),6084 Dest.getReg())6085 .add(Src0)6086 .addImm(0)6087 .add(Src1);6088 TII->legalizeOperands(*Add);6089 MI.eraseFromParent();6090 return BB;6091 }6092 6093 const auto *CarryRC = TRI->getWaveMaskRegClass();6094 6095 Register DestSub0 = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);6096 Register DestSub1 = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);6097 6098 Register CarryReg = MRI.createVirtualRegister(CarryRC);6099 Register DeadCarryReg = MRI.createVirtualRegister(CarryRC);6100 6101 const TargetRegisterClass *Src0RC = Src0.isReg()6102 ? MRI.getRegClass(Src0.getReg())6103 : &AMDGPU::VReg_64RegClass;6104 const TargetRegisterClass *Src1RC = Src1.isReg()6105 ? MRI.getRegClass(Src1.getReg())6106 : &AMDGPU::VReg_64RegClass;6107 6108 const TargetRegisterClass *Src0SubRC =6109 TRI->getSubRegisterClass(Src0RC, AMDGPU::sub0);6110 const TargetRegisterClass *Src1SubRC =6111 TRI->getSubRegisterClass(Src1RC, AMDGPU::sub1);6112 6113 MachineOperand SrcReg0Sub0 = TII->buildExtractSubRegOrImm(6114 MI, MRI, Src0, Src0RC, AMDGPU::sub0, Src0SubRC);6115 MachineOperand SrcReg1Sub0 = TII->buildExtractSubRegOrImm(6116 MI, MRI, Src1, Src1RC, AMDGPU::sub0, Src1SubRC);6117 6118 MachineOperand SrcReg0Sub1 = TII->buildExtractSubRegOrImm(6119 MI, MRI, Src0, Src0RC, AMDGPU::sub1, Src0SubRC);6120 MachineOperand SrcReg1Sub1 = TII->buildExtractSubRegOrImm(6121 MI, MRI, Src1, Src1RC, AMDGPU::sub1, Src1SubRC);6122 6123 unsigned LoOpc =6124 IsAdd ? AMDGPU::V_ADD_CO_U32_e64 : AMDGPU::V_SUB_CO_U32_e64;6125 MachineInstr *LoHalf = BuildMI(*BB, MI, DL, TII->get(LoOpc), DestSub0)6126 .addReg(CarryReg, RegState::Define)6127 .add(SrcReg0Sub0)6128 .add(SrcReg1Sub0)6129 .addImm(0); // clamp bit6130 6131 unsigned HiOpc = IsAdd ? AMDGPU::V_ADDC_U32_e64 : AMDGPU::V_SUBB_U32_e64;6132 MachineInstr *HiHalf =6133 BuildMI(*BB, MI, DL, TII->get(HiOpc), DestSub1)6134 .addReg(DeadCarryReg, RegState::Define | RegState::Dead)6135 .add(SrcReg0Sub1)6136 .add(SrcReg1Sub1)6137 .addReg(CarryReg, RegState::Kill)6138 .addImm(0); // clamp bit6139 6140 BuildMI(*BB, MI, DL, TII->get(TargetOpcode::REG_SEQUENCE), Dest.getReg())6141 .addReg(DestSub0)6142 .addImm(AMDGPU::sub0)6143 .addReg(DestSub1)6144 .addImm(AMDGPU::sub1);6145 TII->legalizeOperands(*LoHalf);6146 TII->legalizeOperands(*HiHalf);6147 MI.eraseFromParent();6148 return BB;6149 }6150 case AMDGPU::S_ADD_CO_PSEUDO:6151 case AMDGPU::S_SUB_CO_PSEUDO: {6152 // This pseudo has a chance to be selected6153 // only from uniform add/subcarry node. All the VGPR operands6154 // therefore assumed to be splat vectors.6155 MachineBasicBlock::iterator MII = MI;6156 MachineOperand &Dest = MI.getOperand(0);6157 MachineOperand &CarryDest = MI.getOperand(1);6158 MachineOperand &Src0 = MI.getOperand(2);6159 MachineOperand &Src1 = MI.getOperand(3);6160 MachineOperand &Src2 = MI.getOperand(4);6161 if (Src0.isReg() && TRI->isVectorRegister(MRI, Src0.getReg())) {6162 Register RegOp0 = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);6163 BuildMI(*BB, MII, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), RegOp0)6164 .addReg(Src0.getReg());6165 Src0.setReg(RegOp0);6166 }6167 if (Src1.isReg() && TRI->isVectorRegister(MRI, Src1.getReg())) {6168 Register RegOp1 = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);6169 BuildMI(*BB, MII, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), RegOp1)6170 .addReg(Src1.getReg());6171 Src1.setReg(RegOp1);6172 }6173 Register RegOp2 = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass);6174 if (TRI->isVectorRegister(MRI, Src2.getReg())) {6175 BuildMI(*BB, MII, DL, TII->get(AMDGPU::V_READFIRSTLANE_B32), RegOp2)6176 .addReg(Src2.getReg());6177 Src2.setReg(RegOp2);6178 }6179 6180 if (ST.isWave64()) {6181 if (ST.hasScalarCompareEq64()) {6182 BuildMI(*BB, MII, DL, TII->get(AMDGPU::S_CMP_LG_U64))6183 .addReg(Src2.getReg())6184 .addImm(0);6185 } else {6186 const TargetRegisterClass *Src2RC = MRI.getRegClass(Src2.getReg());6187 const TargetRegisterClass *SubRC =6188 TRI->getSubRegisterClass(Src2RC, AMDGPU::sub0);6189 MachineOperand Src2Sub0 = TII->buildExtractSubRegOrImm(6190 MII, MRI, Src2, Src2RC, AMDGPU::sub0, SubRC);6191 MachineOperand Src2Sub1 = TII->buildExtractSubRegOrImm(6192 MII, MRI, Src2, Src2RC, AMDGPU::sub1, SubRC);6193 Register Src2_32 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);6194 6195 BuildMI(*BB, MII, DL, TII->get(AMDGPU::S_OR_B32), Src2_32)6196 .add(Src2Sub0)6197 .add(Src2Sub1);6198 6199 BuildMI(*BB, MII, DL, TII->get(AMDGPU::S_CMP_LG_U32))6200 .addReg(Src2_32, RegState::Kill)6201 .addImm(0);6202 }6203 } else {6204 BuildMI(*BB, MII, DL, TII->get(AMDGPU::S_CMP_LG_U32))6205 .addReg(Src2.getReg())6206 .addImm(0);6207 }6208 6209 unsigned Opc = MI.getOpcode() == AMDGPU::S_ADD_CO_PSEUDO6210 ? AMDGPU::S_ADDC_U326211 : AMDGPU::S_SUBB_U32;6212 6213 BuildMI(*BB, MII, DL, TII->get(Opc), Dest.getReg()).add(Src0).add(Src1);6214 6215 unsigned SelOpc =6216 ST.isWave64() ? AMDGPU::S_CSELECT_B64 : AMDGPU::S_CSELECT_B32;6217 6218 BuildMI(*BB, MII, DL, TII->get(SelOpc), CarryDest.getReg())6219 .addImm(-1)6220 .addImm(0);6221 6222 MI.eraseFromParent();6223 return BB;6224 }6225 case AMDGPU::SI_INIT_M0: {6226 MachineOperand &M0Init = MI.getOperand(0);6227 BuildMI(*BB, MI.getIterator(), MI.getDebugLoc(),6228 TII->get(M0Init.isReg() ? AMDGPU::COPY : AMDGPU::S_MOV_B32),6229 AMDGPU::M0)6230 .add(M0Init);6231 MI.eraseFromParent();6232 return BB;6233 }6234 case AMDGPU::S_BARRIER_SIGNAL_ISFIRST_IMM: {6235 // Set SCC to true, in case the barrier instruction gets converted to a NOP.6236 BuildMI(*BB, MI.getIterator(), MI.getDebugLoc(),6237 TII->get(AMDGPU::S_CMP_EQ_U32))6238 .addImm(0)6239 .addImm(0);6240 return BB;6241 }6242 case AMDGPU::GET_GROUPSTATICSIZE: {6243 assert(getTargetMachine().getTargetTriple().getOS() == Triple::AMDHSA ||6244 getTargetMachine().getTargetTriple().getOS() == Triple::AMDPAL);6245 BuildMI(*BB, MI, DL, TII->get(AMDGPU::S_MOV_B32))6246 .add(MI.getOperand(0))6247 .addImm(MFI->getLDSSize());6248 MI.eraseFromParent();6249 return BB;6250 }6251 case AMDGPU::GET_SHADERCYCLESHILO: {6252 assert(MF->getSubtarget<GCNSubtarget>().hasShaderCyclesHiLoRegisters());6253 // The algorithm is:6254 //6255 // hi1 = getreg(SHADER_CYCLES_HI)6256 // lo1 = getreg(SHADER_CYCLES_LO)6257 // hi2 = getreg(SHADER_CYCLES_HI)6258 //6259 // If hi1 == hi2 then there was no overflow and the result is hi2:lo1.6260 // Otherwise there was overflow and the result is hi2:0. In both cases the6261 // result should represent the actual time at some point during the sequence6262 // of three getregs.6263 using namespace AMDGPU::Hwreg;6264 Register RegHi1 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);6265 BuildMI(*BB, MI, DL, TII->get(AMDGPU::S_GETREG_B32), RegHi1)6266 .addImm(HwregEncoding::encode(ID_SHADER_CYCLES_HI, 0, 32));6267 Register RegLo1 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);6268 BuildMI(*BB, MI, DL, TII->get(AMDGPU::S_GETREG_B32), RegLo1)6269 .addImm(HwregEncoding::encode(ID_SHADER_CYCLES, 0, 32));6270 Register RegHi2 = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);6271 BuildMI(*BB, MI, DL, TII->get(AMDGPU::S_GETREG_B32), RegHi2)6272 .addImm(HwregEncoding::encode(ID_SHADER_CYCLES_HI, 0, 32));6273 BuildMI(*BB, MI, DL, TII->get(AMDGPU::S_CMP_EQ_U32))6274 .addReg(RegHi1)6275 .addReg(RegHi2);6276 Register RegLo = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);6277 BuildMI(*BB, MI, DL, TII->get(AMDGPU::S_CSELECT_B32), RegLo)6278 .addReg(RegLo1)6279 .addImm(0);6280 BuildMI(*BB, MI, DL, TII->get(AMDGPU::REG_SEQUENCE))6281 .add(MI.getOperand(0))6282 .addReg(RegLo)6283 .addImm(AMDGPU::sub0)6284 .addReg(RegHi2)6285 .addImm(AMDGPU::sub1);6286 MI.eraseFromParent();6287 return BB;6288 }6289 case AMDGPU::SI_INDIRECT_SRC_V1:6290 case AMDGPU::SI_INDIRECT_SRC_V2:6291 case AMDGPU::SI_INDIRECT_SRC_V4:6292 case AMDGPU::SI_INDIRECT_SRC_V8:6293 case AMDGPU::SI_INDIRECT_SRC_V9:6294 case AMDGPU::SI_INDIRECT_SRC_V10:6295 case AMDGPU::SI_INDIRECT_SRC_V11:6296 case AMDGPU::SI_INDIRECT_SRC_V12:6297 case AMDGPU::SI_INDIRECT_SRC_V16:6298 case AMDGPU::SI_INDIRECT_SRC_V32:6299 return emitIndirectSrc(MI, *BB, *getSubtarget());6300 case AMDGPU::SI_INDIRECT_DST_V1:6301 case AMDGPU::SI_INDIRECT_DST_V2:6302 case AMDGPU::SI_INDIRECT_DST_V4:6303 case AMDGPU::SI_INDIRECT_DST_V8:6304 case AMDGPU::SI_INDIRECT_DST_V9:6305 case AMDGPU::SI_INDIRECT_DST_V10:6306 case AMDGPU::SI_INDIRECT_DST_V11:6307 case AMDGPU::SI_INDIRECT_DST_V12:6308 case AMDGPU::SI_INDIRECT_DST_V16:6309 case AMDGPU::SI_INDIRECT_DST_V32:6310 return emitIndirectDst(MI, *BB, *getSubtarget());6311 case AMDGPU::SI_KILL_F32_COND_IMM_PSEUDO:6312 case AMDGPU::SI_KILL_I1_PSEUDO:6313 return splitKillBlock(MI, BB);6314 case AMDGPU::V_CNDMASK_B64_PSEUDO: {6315 Register Dst = MI.getOperand(0).getReg();6316 const MachineOperand &Src0 = MI.getOperand(1);6317 const MachineOperand &Src1 = MI.getOperand(2);6318 Register SrcCond = MI.getOperand(3).getReg();6319 6320 Register DstLo = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);6321 Register DstHi = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);6322 const auto *CondRC = TRI->getWaveMaskRegClass();6323 Register SrcCondCopy = MRI.createVirtualRegister(CondRC);6324 6325 const TargetRegisterClass *Src0RC = Src0.isReg()6326 ? MRI.getRegClass(Src0.getReg())6327 : &AMDGPU::VReg_64RegClass;6328 const TargetRegisterClass *Src1RC = Src1.isReg()6329 ? MRI.getRegClass(Src1.getReg())6330 : &AMDGPU::VReg_64RegClass;6331 6332 const TargetRegisterClass *Src0SubRC =6333 TRI->getSubRegisterClass(Src0RC, AMDGPU::sub0);6334 const TargetRegisterClass *Src1SubRC =6335 TRI->getSubRegisterClass(Src1RC, AMDGPU::sub1);6336 6337 MachineOperand Src0Sub0 = TII->buildExtractSubRegOrImm(6338 MI, MRI, Src0, Src0RC, AMDGPU::sub0, Src0SubRC);6339 MachineOperand Src1Sub0 = TII->buildExtractSubRegOrImm(6340 MI, MRI, Src1, Src1RC, AMDGPU::sub0, Src1SubRC);6341 6342 MachineOperand Src0Sub1 = TII->buildExtractSubRegOrImm(6343 MI, MRI, Src0, Src0RC, AMDGPU::sub1, Src0SubRC);6344 MachineOperand Src1Sub1 = TII->buildExtractSubRegOrImm(6345 MI, MRI, Src1, Src1RC, AMDGPU::sub1, Src1SubRC);6346 6347 BuildMI(*BB, MI, DL, TII->get(AMDGPU::COPY), SrcCondCopy).addReg(SrcCond);6348 BuildMI(*BB, MI, DL, TII->get(AMDGPU::V_CNDMASK_B32_e64), DstLo)6349 .addImm(0)6350 .add(Src0Sub0)6351 .addImm(0)6352 .add(Src1Sub0)6353 .addReg(SrcCondCopy);6354 BuildMI(*BB, MI, DL, TII->get(AMDGPU::V_CNDMASK_B32_e64), DstHi)6355 .addImm(0)6356 .add(Src0Sub1)6357 .addImm(0)6358 .add(Src1Sub1)6359 .addReg(SrcCondCopy);6360 6361 BuildMI(*BB, MI, DL, TII->get(AMDGPU::REG_SEQUENCE), Dst)6362 .addReg(DstLo)6363 .addImm(AMDGPU::sub0)6364 .addReg(DstHi)6365 .addImm(AMDGPU::sub1);6366 MI.eraseFromParent();6367 return BB;6368 }6369 case AMDGPU::SI_BR_UNDEF: {6370 MachineInstr *Br = BuildMI(*BB, MI, DL, TII->get(AMDGPU::S_CBRANCH_SCC1))6371 .add(MI.getOperand(0));6372 Br->getOperand(1).setIsUndef(); // read undef SCC6373 MI.eraseFromParent();6374 return BB;6375 }6376 case AMDGPU::ADJCALLSTACKUP:6377 case AMDGPU::ADJCALLSTACKDOWN: {6378 const SIMachineFunctionInfo *Info = MF->getInfo<SIMachineFunctionInfo>();6379 MachineInstrBuilder MIB(*MF, &MI);6380 MIB.addReg(Info->getStackPtrOffsetReg(), RegState::ImplicitDefine)6381 .addReg(Info->getStackPtrOffsetReg(), RegState::Implicit);6382 return BB;6383 }6384 case AMDGPU::SI_CALL_ISEL: {6385 unsigned ReturnAddrReg = TII->getRegisterInfo().getReturnAddressReg(*MF);6386 6387 MachineInstrBuilder MIB;6388 MIB = BuildMI(*BB, MI, DL, TII->get(AMDGPU::SI_CALL), ReturnAddrReg);6389 6390 for (const MachineOperand &MO : MI.operands())6391 MIB.add(MO);6392 6393 MIB.cloneMemRefs(MI);6394 MI.eraseFromParent();6395 return BB;6396 }6397 case AMDGPU::V_ADD_CO_U32_e32:6398 case AMDGPU::V_SUB_CO_U32_e32:6399 case AMDGPU::V_SUBREV_CO_U32_e32: {6400 // TODO: Define distinct V_*_I32_Pseudo instructions instead.6401 unsigned Opc = MI.getOpcode();6402 6403 bool NeedClampOperand = false;6404 if (TII->pseudoToMCOpcode(Opc) == -1) {6405 Opc = AMDGPU::getVOPe64(Opc);6406 NeedClampOperand = true;6407 }6408 6409 auto I = BuildMI(*BB, MI, DL, TII->get(Opc), MI.getOperand(0).getReg());6410 if (TII->isVOP3(*I)) {6411 I.addReg(TRI->getVCC(), RegState::Define);6412 }6413 I.add(MI.getOperand(1)).add(MI.getOperand(2));6414 if (NeedClampOperand)6415 I.addImm(0); // clamp bit for e64 encoding6416 6417 TII->legalizeOperands(*I);6418 6419 MI.eraseFromParent();6420 return BB;6421 }6422 case AMDGPU::V_ADDC_U32_e32:6423 case AMDGPU::V_SUBB_U32_e32:6424 case AMDGPU::V_SUBBREV_U32_e32:6425 // These instructions have an implicit use of vcc which counts towards the6426 // constant bus limit.6427 TII->legalizeOperands(MI);6428 return BB;6429 case AMDGPU::DS_GWS_INIT:6430 case AMDGPU::DS_GWS_SEMA_BR:6431 case AMDGPU::DS_GWS_BARRIER:6432 case AMDGPU::DS_GWS_SEMA_V:6433 case AMDGPU::DS_GWS_SEMA_P:6434 case AMDGPU::DS_GWS_SEMA_RELEASE_ALL:6435 // A s_waitcnt 0 is required to be the instruction immediately following.6436 if (getSubtarget()->hasGWSAutoReplay()) {6437 bundleInstWithWaitcnt(MI);6438 return BB;6439 }6440 6441 return emitGWSMemViolTestLoop(MI, BB);6442 case AMDGPU::S_SETREG_B32: {6443 // Try to optimize cases that only set the denormal mode or rounding mode.6444 //6445 // If the s_setreg_b32 fully sets all of the bits in the rounding mode or6446 // denormal mode to a constant, we can use s_round_mode or s_denorm_mode6447 // instead.6448 //6449 // FIXME: This could be predicates on the immediate, but tablegen doesn't6450 // allow you to have a no side effect instruction in the output of a6451 // sideeffecting pattern.6452 auto [ID, Offset, Width] =6453 AMDGPU::Hwreg::HwregEncoding::decode(MI.getOperand(1).getImm());6454 if (ID != AMDGPU::Hwreg::ID_MODE)6455 return BB;6456 6457 const unsigned WidthMask = maskTrailingOnes<unsigned>(Width);6458 const unsigned SetMask = WidthMask << Offset;6459 6460 if (getSubtarget()->hasDenormModeInst()) {6461 unsigned SetDenormOp = 0;6462 unsigned SetRoundOp = 0;6463 6464 // The dedicated instructions can only set the whole denorm or round mode6465 // at once, not a subset of bits in either.6466 if (SetMask ==6467 (AMDGPU::Hwreg::FP_ROUND_MASK | AMDGPU::Hwreg::FP_DENORM_MASK)) {6468 // If this fully sets both the round and denorm mode, emit the two6469 // dedicated instructions for these.6470 SetRoundOp = AMDGPU::S_ROUND_MODE;6471 SetDenormOp = AMDGPU::S_DENORM_MODE;6472 } else if (SetMask == AMDGPU::Hwreg::FP_ROUND_MASK) {6473 SetRoundOp = AMDGPU::S_ROUND_MODE;6474 } else if (SetMask == AMDGPU::Hwreg::FP_DENORM_MASK) {6475 SetDenormOp = AMDGPU::S_DENORM_MODE;6476 }6477 6478 if (SetRoundOp || SetDenormOp) {6479 MachineInstr *Def = MRI.getVRegDef(MI.getOperand(0).getReg());6480 if (Def && Def->isMoveImmediate() && Def->getOperand(1).isImm()) {6481 unsigned ImmVal = Def->getOperand(1).getImm();6482 if (SetRoundOp) {6483 BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(SetRoundOp))6484 .addImm(ImmVal & 0xf);6485 6486 // If we also have the denorm mode, get just the denorm mode bits.6487 ImmVal >>= 4;6488 }6489 6490 if (SetDenormOp) {6491 BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(SetDenormOp))6492 .addImm(ImmVal & 0xf);6493 }6494 6495 MI.eraseFromParent();6496 return BB;6497 }6498 }6499 }6500 6501 // If only FP bits are touched, used the no side effects pseudo.6502 if ((SetMask & (AMDGPU::Hwreg::FP_ROUND_MASK |6503 AMDGPU::Hwreg::FP_DENORM_MASK)) == SetMask)6504 MI.setDesc(TII->get(AMDGPU::S_SETREG_B32_mode));6505 6506 return BB;6507 }6508 case AMDGPU::S_INVERSE_BALLOT_U32:6509 case AMDGPU::S_INVERSE_BALLOT_U64:6510 // These opcodes only exist to let SIFixSGPRCopies insert a readfirstlane if6511 // necessary. After that they are equivalent to a COPY.6512 MI.setDesc(TII->get(AMDGPU::COPY));6513 return BB;6514 case AMDGPU::ENDPGM_TRAP: {6515 if (BB->succ_empty() && std::next(MI.getIterator()) == BB->end()) {6516 MI.setDesc(TII->get(AMDGPU::S_ENDPGM));6517 MI.addOperand(MachineOperand::CreateImm(0));6518 return BB;6519 }6520 6521 // We need a block split to make the real endpgm a terminator. We also don't6522 // want to break phis in successor blocks, so we can't just delete to the6523 // end of the block.6524 6525 MachineBasicBlock *SplitBB = BB->splitAt(MI, false /*UpdateLiveIns*/);6526 MachineBasicBlock *TrapBB = MF->CreateMachineBasicBlock();6527 MF->push_back(TrapBB);6528 // clang-format off6529 BuildMI(*TrapBB, TrapBB->end(), DL, TII->get(AMDGPU::S_ENDPGM))6530 .addImm(0);6531 BuildMI(*BB, &MI, DL, TII->get(AMDGPU::S_CBRANCH_EXECNZ))6532 .addMBB(TrapBB);6533 // clang-format on6534 6535 BB->addSuccessor(TrapBB);6536 MI.eraseFromParent();6537 return SplitBB;6538 }6539 case AMDGPU::SIMULATED_TRAP: {6540 assert(Subtarget->hasPrivEnabledTrap2NopBug());6541 MachineBasicBlock *SplitBB =6542 TII->insertSimulatedTrap(MRI, *BB, MI, MI.getDebugLoc());6543 MI.eraseFromParent();6544 return SplitBB;6545 }6546 case AMDGPU::SI_TCRETURN_GFX_WholeWave:6547 case AMDGPU::SI_WHOLE_WAVE_FUNC_RETURN: {6548 assert(MFI->isWholeWaveFunction());6549 6550 // During ISel, it's difficult to propagate the original EXEC mask to use as6551 // an input to SI_WHOLE_WAVE_FUNC_RETURN. Set it up here instead.6552 MachineInstr *Setup = TII->getWholeWaveFunctionSetup(*BB->getParent());6553 assert(Setup && "Couldn't find SI_SETUP_WHOLE_WAVE_FUNC");6554 Register OriginalExec = Setup->getOperand(0).getReg();6555 MF->getRegInfo().clearKillFlags(OriginalExec);6556 MI.getOperand(0).setReg(OriginalExec);6557 return BB;6558 }6559 default:6560 if (TII->isImage(MI) || TII->isMUBUF(MI)) {6561 if (!MI.mayStore())6562 AddMemOpInit(MI);6563 return BB;6564 }6565 return AMDGPUTargetLowering::EmitInstrWithCustomInserter(MI, BB);6566 }6567}6568 6569bool SITargetLowering::enableAggressiveFMAFusion(EVT VT) const {6570 // This currently forces unfolding various combinations of fsub into fma with6571 // free fneg'd operands. As long as we have fast FMA (controlled by6572 // isFMAFasterThanFMulAndFAdd), we should perform these.6573 6574 // When fma is quarter rate, for f64 where add / sub are at best half rate,6575 // most of these combines appear to be cycle neutral but save on instruction6576 // count / code size.6577 return true;6578}6579 6580bool SITargetLowering::enableAggressiveFMAFusion(LLT Ty) const { return true; }6581 6582EVT SITargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &Ctx,6583 EVT VT) const {6584 if (!VT.isVector()) {6585 return MVT::i1;6586 }6587 return EVT::getVectorVT(Ctx, MVT::i1, VT.getVectorNumElements());6588}6589 6590MVT SITargetLowering::getScalarShiftAmountTy(const DataLayout &, EVT VT) const {6591 // TODO: Should i16 be used always if legal? For now it would force VALU6592 // shifts.6593 return (VT == MVT::i16) ? MVT::i16 : MVT::i32;6594}6595 6596LLT SITargetLowering::getPreferredShiftAmountTy(LLT Ty) const {6597 return (Ty.getScalarSizeInBits() <= 16 && Subtarget->has16BitInsts())6598 ? Ty.changeElementSize(16)6599 : Ty.changeElementSize(32);6600}6601 6602// Answering this is somewhat tricky and depends on the specific device which6603// have different rates for fma or all f64 operations.6604//6605// v_fma_f64 and v_mul_f64 always take the same number of cycles as each other6606// regardless of which device (although the number of cycles differs between6607// devices), so it is always profitable for f64.6608//6609// v_fma_f32 takes 4 or 16 cycles depending on the device, so it is profitable6610// only on full rate devices. Normally, we should prefer selecting v_mad_f326611// which we can always do even without fused FP ops since it returns the same6612// result as the separate operations and since it is always full6613// rate. Therefore, we lie and report that it is not faster for f32. v_mad_f326614// however does not support denormals, so we do report fma as faster if we have6615// a fast fma device and require denormals.6616//6617bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,6618 EVT VT) const {6619 VT = VT.getScalarType();6620 6621 switch (VT.getSimpleVT().SimpleTy) {6622 case MVT::f32: {6623 // If mad is not available this depends only on if f32 fma is full rate.6624 if (!Subtarget->hasMadMacF32Insts())6625 return Subtarget->hasFastFMAF32();6626 6627 // Otherwise f32 mad is always full rate and returns the same result as6628 // the separate operations so should be preferred over fma.6629 // However does not support denormals.6630 if (!denormalModeIsFlushAllF32(MF))6631 return Subtarget->hasFastFMAF32() || Subtarget->hasDLInsts();6632 6633 // If the subtarget has v_fmac_f32, that's just as good as v_mac_f32.6634 return Subtarget->hasFastFMAF32() && Subtarget->hasDLInsts();6635 }6636 case MVT::f64:6637 return true;6638 case MVT::f16:6639 case MVT::bf16:6640 return Subtarget->has16BitInsts() && !denormalModeIsFlushAllF64F16(MF);6641 default:6642 break;6643 }6644 6645 return false;6646}6647 6648bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,6649 LLT Ty) const {6650 switch (Ty.getScalarSizeInBits()) {6651 case 16:6652 return isFMAFasterThanFMulAndFAdd(MF, MVT::f16);6653 case 32:6654 return isFMAFasterThanFMulAndFAdd(MF, MVT::f32);6655 case 64:6656 return isFMAFasterThanFMulAndFAdd(MF, MVT::f64);6657 default:6658 break;6659 }6660 6661 return false;6662}6663 6664bool SITargetLowering::isFMADLegal(const MachineInstr &MI, LLT Ty) const {6665 if (!Ty.isScalar())6666 return false;6667 6668 if (Ty.getScalarSizeInBits() == 16)6669 return Subtarget->hasMadF16() && denormalModeIsFlushAllF64F16(*MI.getMF());6670 if (Ty.getScalarSizeInBits() == 32)6671 return Subtarget->hasMadMacF32Insts() &&6672 denormalModeIsFlushAllF32(*MI.getMF());6673 6674 return false;6675}6676 6677bool SITargetLowering::isFMADLegal(const SelectionDAG &DAG,6678 const SDNode *N) const {6679 // TODO: Check future ftz flag6680 // v_mad_f32/v_mac_f32 do not support denormals.6681 EVT VT = N->getValueType(0);6682 if (VT == MVT::f32)6683 return Subtarget->hasMadMacF32Insts() &&6684 denormalModeIsFlushAllF32(DAG.getMachineFunction());6685 if (VT == MVT::f16) {6686 return Subtarget->hasMadF16() &&6687 denormalModeIsFlushAllF64F16(DAG.getMachineFunction());6688 }6689 6690 return false;6691}6692 6693//===----------------------------------------------------------------------===//6694// Custom DAG Lowering Operations6695//===----------------------------------------------------------------------===//6696 6697// Work around LegalizeDAG doing the wrong thing and fully scalarizing if the6698// wider vector type is legal.6699SDValue SITargetLowering::splitUnaryVectorOp(SDValue Op,6700 SelectionDAG &DAG) const {6701 unsigned Opc = Op.getOpcode();6702 EVT VT = Op.getValueType();6703 assert(VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16 ||6704 VT == MVT::v4f32 || VT == MVT::v8i16 || VT == MVT::v8f16 ||6705 VT == MVT::v8bf16 || VT == MVT::v16i16 || VT == MVT::v16f16 ||6706 VT == MVT::v16bf16 || VT == MVT::v8f32 || VT == MVT::v16f32 ||6707 VT == MVT::v32f32 || VT == MVT::v32i16 || VT == MVT::v32f16 ||6708 VT == MVT::v32bf16);6709 6710 auto [Lo, Hi] = DAG.SplitVectorOperand(Op.getNode(), 0);6711 6712 SDLoc SL(Op);6713 SDValue OpLo = DAG.getNode(Opc, SL, Lo.getValueType(), Lo, Op->getFlags());6714 SDValue OpHi = DAG.getNode(Opc, SL, Hi.getValueType(), Hi, Op->getFlags());6715 6716 return DAG.getNode(ISD::CONCAT_VECTORS, SDLoc(Op), VT, OpLo, OpHi);6717}6718 6719// Enable lowering of ROTR for vxi32 types. This is a workaround for a6720// regression whereby extra unnecessary instructions were added to codegen6721// for rotr operations, casued by legalising v2i32 or. This resulted in extra6722// instructions to extract the result from the vector.6723SDValue SITargetLowering::lowerROTR(SDValue Op, SelectionDAG &DAG) const {6724 [[maybe_unused]] EVT VT = Op.getValueType();6725 6726 assert((VT == MVT::v2i32 || VT == MVT::v4i32 || VT == MVT::v8i32 ||6727 VT == MVT::v16i32) &&6728 "Unexpected ValueType.");6729 6730 return DAG.UnrollVectorOp(Op.getNode());6731}6732 6733// Work around LegalizeDAG doing the wrong thing and fully scalarizing if the6734// wider vector type is legal.6735SDValue SITargetLowering::splitBinaryVectorOp(SDValue Op,6736 SelectionDAG &DAG) const {6737 unsigned Opc = Op.getOpcode();6738 EVT VT = Op.getValueType();6739 assert(VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4bf16 ||6740 VT == MVT::v4f32 || VT == MVT::v8i16 || VT == MVT::v8f16 ||6741 VT == MVT::v8bf16 || VT == MVT::v16i16 || VT == MVT::v16f16 ||6742 VT == MVT::v16bf16 || VT == MVT::v8f32 || VT == MVT::v16f32 ||6743 VT == MVT::v32f32 || VT == MVT::v32i16 || VT == MVT::v32f16 ||6744 VT == MVT::v32bf16);6745 6746 auto [Lo0, Hi0] = DAG.SplitVectorOperand(Op.getNode(), 0);6747 auto [Lo1, Hi1] = DAG.SplitVectorOperand(Op.getNode(), 1);6748 6749 SDLoc SL(Op);6750 6751 SDValue OpLo =6752 DAG.getNode(Opc, SL, Lo0.getValueType(), Lo0, Lo1, Op->getFlags());6753 SDValue OpHi =6754 DAG.getNode(Opc, SL, Hi0.getValueType(), Hi0, Hi1, Op->getFlags());6755 6756 return DAG.getNode(ISD::CONCAT_VECTORS, SDLoc(Op), VT, OpLo, OpHi);6757}6758 6759SDValue SITargetLowering::splitTernaryVectorOp(SDValue Op,6760 SelectionDAG &DAG) const {6761 unsigned Opc = Op.getOpcode();6762 EVT VT = Op.getValueType();6763 assert(VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v8i16 ||6764 VT == MVT::v8f16 || VT == MVT::v4f32 || VT == MVT::v16i16 ||6765 VT == MVT::v16f16 || VT == MVT::v8f32 || VT == MVT::v16f32 ||6766 VT == MVT::v32f32 || VT == MVT::v32f16 || VT == MVT::v32i16 ||6767 VT == MVT::v4bf16 || VT == MVT::v8bf16 || VT == MVT::v16bf16 ||6768 VT == MVT::v32bf16);6769 6770 SDValue Op0 = Op.getOperand(0);6771 auto [Lo0, Hi0] = Op0.getValueType().isVector()6772 ? DAG.SplitVectorOperand(Op.getNode(), 0)6773 : std::pair(Op0, Op0);6774 6775 auto [Lo1, Hi1] = DAG.SplitVectorOperand(Op.getNode(), 1);6776 auto [Lo2, Hi2] = DAG.SplitVectorOperand(Op.getNode(), 2);6777 6778 SDLoc SL(Op);6779 auto ResVT = DAG.GetSplitDestVTs(VT);6780 6781 SDValue OpLo =6782 DAG.getNode(Opc, SL, ResVT.first, Lo0, Lo1, Lo2, Op->getFlags());6783 SDValue OpHi =6784 DAG.getNode(Opc, SL, ResVT.second, Hi0, Hi1, Hi2, Op->getFlags());6785 6786 return DAG.getNode(ISD::CONCAT_VECTORS, SDLoc(Op), VT, OpLo, OpHi);6787}6788 6789SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {6790 switch (Op.getOpcode()) {6791 default:6792 return AMDGPUTargetLowering::LowerOperation(Op, DAG);6793 case ISD::BRCOND:6794 return LowerBRCOND(Op, DAG);6795 case ISD::RETURNADDR:6796 return LowerRETURNADDR(Op, DAG);6797 case ISD::LOAD: {6798 SDValue Result = LowerLOAD(Op, DAG);6799 assert((!Result.getNode() || Result.getNode()->getNumValues() == 2) &&6800 "Load should return a value and a chain");6801 return Result;6802 }6803 case ISD::FSQRT: {6804 EVT VT = Op.getValueType();6805 if (VT == MVT::f32)6806 return lowerFSQRTF32(Op, DAG);6807 if (VT == MVT::f64)6808 return lowerFSQRTF64(Op, DAG);6809 return SDValue();6810 }6811 case ISD::FSIN:6812 case ISD::FCOS:6813 return LowerTrig(Op, DAG);6814 case ISD::SELECT:6815 return LowerSELECT(Op, DAG);6816 case ISD::FDIV:6817 return LowerFDIV(Op, DAG);6818 case ISD::FFREXP:6819 return LowerFFREXP(Op, DAG);6820 case ISD::ATOMIC_CMP_SWAP:6821 return LowerATOMIC_CMP_SWAP(Op, DAG);6822 case ISD::STORE:6823 return LowerSTORE(Op, DAG);6824 case ISD::GlobalAddress: {6825 MachineFunction &MF = DAG.getMachineFunction();6826 SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();6827 return LowerGlobalAddress(MFI, Op, DAG);6828 }6829 case ISD::INTRINSIC_WO_CHAIN:6830 return LowerINTRINSIC_WO_CHAIN(Op, DAG);6831 case ISD::INTRINSIC_W_CHAIN:6832 return LowerINTRINSIC_W_CHAIN(Op, DAG);6833 case ISD::INTRINSIC_VOID:6834 return LowerINTRINSIC_VOID(Op, DAG);6835 case ISD::ADDRSPACECAST:6836 return lowerADDRSPACECAST(Op, DAG);6837 case ISD::INSERT_SUBVECTOR:6838 return lowerINSERT_SUBVECTOR(Op, DAG);6839 case ISD::INSERT_VECTOR_ELT:6840 return lowerINSERT_VECTOR_ELT(Op, DAG);6841 case ISD::EXTRACT_VECTOR_ELT:6842 return lowerEXTRACT_VECTOR_ELT(Op, DAG);6843 case ISD::VECTOR_SHUFFLE:6844 return lowerVECTOR_SHUFFLE(Op, DAG);6845 case ISD::SCALAR_TO_VECTOR:6846 return lowerSCALAR_TO_VECTOR(Op, DAG);6847 case ISD::BUILD_VECTOR:6848 return lowerBUILD_VECTOR(Op, DAG);6849 case ISD::FP_ROUND:6850 case ISD::STRICT_FP_ROUND:6851 return lowerFP_ROUND(Op, DAG);6852 case ISD::TRAP:6853 return lowerTRAP(Op, DAG);6854 case ISD::DEBUGTRAP:6855 return lowerDEBUGTRAP(Op, DAG);6856 case ISD::ABS:6857 case ISD::FABS:6858 case ISD::FNEG:6859 case ISD::FCANONICALIZE:6860 case ISD::BSWAP:6861 return splitUnaryVectorOp(Op, DAG);6862 case ISD::FMINNUM:6863 case ISD::FMAXNUM:6864 return lowerFMINNUM_FMAXNUM(Op, DAG);6865 case ISD::FMINIMUMNUM:6866 case ISD::FMAXIMUMNUM:6867 return lowerFMINIMUMNUM_FMAXIMUMNUM(Op, DAG);6868 case ISD::FMINIMUM:6869 case ISD::FMAXIMUM:6870 return lowerFMINIMUM_FMAXIMUM(Op, DAG);6871 case ISD::FLDEXP:6872 case ISD::STRICT_FLDEXP:6873 return lowerFLDEXP(Op, DAG);6874 case ISD::FMA:6875 return splitTernaryVectorOp(Op, DAG);6876 case ISD::FP_TO_SINT:6877 case ISD::FP_TO_UINT:6878 return LowerFP_TO_INT(Op, DAG);6879 case ISD::SHL:6880 case ISD::SRA:6881 case ISD::SRL:6882 case ISD::ADD:6883 case ISD::SUB:6884 case ISD::SMIN:6885 case ISD::SMAX:6886 case ISD::UMIN:6887 case ISD::UMAX:6888 case ISD::FADD:6889 case ISD::FMUL:6890 case ISD::FMINNUM_IEEE:6891 case ISD::FMAXNUM_IEEE:6892 case ISD::UADDSAT:6893 case ISD::USUBSAT:6894 case ISD::SADDSAT:6895 case ISD::SSUBSAT:6896 return splitBinaryVectorOp(Op, DAG);6897 case ISD::FCOPYSIGN:6898 return lowerFCOPYSIGN(Op, DAG);6899 case ISD::MUL:6900 return lowerMUL(Op, DAG);6901 case ISD::SMULO:6902 case ISD::UMULO:6903 return lowerXMULO(Op, DAG);6904 case ISD::SMUL_LOHI:6905 case ISD::UMUL_LOHI:6906 return lowerXMUL_LOHI(Op, DAG);6907 case ISD::DYNAMIC_STACKALLOC:6908 return LowerDYNAMIC_STACKALLOC(Op, DAG);6909 case ISD::STACKSAVE:6910 return LowerSTACKSAVE(Op, DAG);6911 case ISD::GET_ROUNDING:6912 return lowerGET_ROUNDING(Op, DAG);6913 case ISD::SET_ROUNDING:6914 return lowerSET_ROUNDING(Op, DAG);6915 case ISD::PREFETCH:6916 return lowerPREFETCH(Op, DAG);6917 case ISD::FP_EXTEND:6918 case ISD::STRICT_FP_EXTEND:6919 return lowerFP_EXTEND(Op, DAG);6920 case ISD::GET_FPENV:6921 return lowerGET_FPENV(Op, DAG);6922 case ISD::SET_FPENV:6923 return lowerSET_FPENV(Op, DAG);6924 case ISD::ROTR:6925 return lowerROTR(Op, DAG);6926 }6927 return SDValue();6928}6929 6930// Used for D16: Casts the result of an instruction into the right vector,6931// packs values if loads return unpacked values.6932static SDValue adjustLoadValueTypeImpl(SDValue Result, EVT LoadVT,6933 const SDLoc &DL, SelectionDAG &DAG,6934 bool Unpacked) {6935 if (!LoadVT.isVector())6936 return Result;6937 6938 // Cast back to the original packed type or to a larger type that is a6939 // multiple of 32 bit for D16. Widening the return type is a required for6940 // legalization.6941 EVT FittingLoadVT = LoadVT;6942 if ((LoadVT.getVectorNumElements() % 2) == 1) {6943 FittingLoadVT =6944 EVT::getVectorVT(*DAG.getContext(), LoadVT.getVectorElementType(),6945 LoadVT.getVectorNumElements() + 1);6946 }6947 6948 if (Unpacked) { // From v2i32/v4i32 back to v2f16/v4f16.6949 // Truncate to v2i16/v4i16.6950 EVT IntLoadVT = FittingLoadVT.changeTypeToInteger();6951 6952 // Workaround legalizer not scalarizing truncate after vector op6953 // legalization but not creating intermediate vector trunc.6954 SmallVector<SDValue, 4> Elts;6955 DAG.ExtractVectorElements(Result, Elts);6956 for (SDValue &Elt : Elts)6957 Elt = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Elt);6958 6959 // Pad illegal v1i16/v3fi6 to v4i166960 if ((LoadVT.getVectorNumElements() % 2) == 1)6961 Elts.push_back(DAG.getPOISON(MVT::i16));6962 6963 Result = DAG.getBuildVector(IntLoadVT, DL, Elts);6964 6965 // Bitcast to original type (v2f16/v4f16).6966 return DAG.getNode(ISD::BITCAST, DL, FittingLoadVT, Result);6967 }6968 6969 // Cast back to the original packed type.6970 return DAG.getNode(ISD::BITCAST, DL, FittingLoadVT, Result);6971}6972 6973SDValue SITargetLowering::adjustLoadValueType(unsigned Opcode, MemSDNode *M,6974 SelectionDAG &DAG,6975 ArrayRef<SDValue> Ops,6976 bool IsIntrinsic) const {6977 SDLoc DL(M);6978 6979 bool Unpacked = Subtarget->hasUnpackedD16VMem();6980 EVT LoadVT = M->getValueType(0);6981 6982 EVT EquivLoadVT = LoadVT;6983 if (LoadVT.isVector()) {6984 if (Unpacked) {6985 EquivLoadVT = EVT::getVectorVT(*DAG.getContext(), MVT::i32,6986 LoadVT.getVectorNumElements());6987 } else if ((LoadVT.getVectorNumElements() % 2) == 1) {6988 // Widen v3f16 to legal type6989 EquivLoadVT =6990 EVT::getVectorVT(*DAG.getContext(), LoadVT.getVectorElementType(),6991 LoadVT.getVectorNumElements() + 1);6992 }6993 }6994 6995 // Change from v4f16/v2f16 to EquivLoadVT.6996 SDVTList VTList = DAG.getVTList(EquivLoadVT, MVT::Other);6997 6998 SDValue Load = DAG.getMemIntrinsicNode(6999 IsIntrinsic ? (unsigned)ISD::INTRINSIC_W_CHAIN : Opcode, DL, VTList, Ops,7000 M->getMemoryVT(), M->getMemOperand());7001 7002 SDValue Adjusted = adjustLoadValueTypeImpl(Load, LoadVT, DL, DAG, Unpacked);7003 7004 return DAG.getMergeValues({Adjusted, Load.getValue(1)}, DL);7005}7006 7007SDValue SITargetLowering::lowerIntrinsicLoad(MemSDNode *M, bool IsFormat,7008 SelectionDAG &DAG,7009 ArrayRef<SDValue> Ops) const {7010 SDLoc DL(M);7011 EVT LoadVT = M->getValueType(0);7012 EVT EltType = LoadVT.getScalarType();7013 EVT IntVT = LoadVT.changeTypeToInteger();7014 7015 bool IsD16 = IsFormat && (EltType.getSizeInBits() == 16);7016 7017 assert(M->getNumValues() == 2 || M->getNumValues() == 3);7018 bool IsTFE = M->getNumValues() == 3;7019 7020 unsigned Opc = IsFormat ? (IsTFE ? AMDGPUISD::BUFFER_LOAD_FORMAT_TFE7021 : AMDGPUISD::BUFFER_LOAD_FORMAT)7022 : IsTFE ? AMDGPUISD::BUFFER_LOAD_TFE7023 : AMDGPUISD::BUFFER_LOAD;7024 7025 if (IsD16) {7026 return adjustLoadValueType(AMDGPUISD::BUFFER_LOAD_FORMAT_D16, M, DAG, Ops);7027 }7028 7029 // Handle BUFFER_LOAD_BYTE/UBYTE/SHORT/USHORT overloaded intrinsics7030 if (!IsD16 && !LoadVT.isVector() && EltType.getSizeInBits() < 32)7031 return handleByteShortBufferLoads(DAG, LoadVT, DL, Ops, M->getMemOperand(),7032 IsTFE);7033 7034 if (isTypeLegal(LoadVT)) {7035 return getMemIntrinsicNode(Opc, DL, M->getVTList(), Ops, IntVT,7036 M->getMemOperand(), DAG);7037 }7038 7039 EVT CastVT = getEquivalentMemType(*DAG.getContext(), LoadVT);7040 SDVTList VTList = DAG.getVTList(CastVT, MVT::Other);7041 SDValue MemNode = getMemIntrinsicNode(Opc, DL, VTList, Ops, CastVT,7042 M->getMemOperand(), DAG);7043 return DAG.getMergeValues(7044 {DAG.getNode(ISD::BITCAST, DL, LoadVT, MemNode), MemNode.getValue(1)},7045 DL);7046}7047 7048static SDValue lowerICMPIntrinsic(const SITargetLowering &TLI, SDNode *N,7049 SelectionDAG &DAG) {7050 EVT VT = N->getValueType(0);7051 unsigned CondCode = N->getConstantOperandVal(3);7052 if (!ICmpInst::isIntPredicate(static_cast<ICmpInst::Predicate>(CondCode)))7053 return DAG.getPOISON(VT);7054 7055 ICmpInst::Predicate IcInput = static_cast<ICmpInst::Predicate>(CondCode);7056 7057 SDValue LHS = N->getOperand(1);7058 SDValue RHS = N->getOperand(2);7059 7060 SDLoc DL(N);7061 7062 EVT CmpVT = LHS.getValueType();7063 if (CmpVT == MVT::i16 && !TLI.isTypeLegal(MVT::i16)) {7064 unsigned PromoteOp =7065 ICmpInst::isSigned(IcInput) ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;7066 LHS = DAG.getNode(PromoteOp, DL, MVT::i32, LHS);7067 RHS = DAG.getNode(PromoteOp, DL, MVT::i32, RHS);7068 }7069 7070 ISD::CondCode CCOpcode = getICmpCondCode(IcInput);7071 7072 unsigned WavefrontSize = TLI.getSubtarget()->getWavefrontSize();7073 EVT CCVT = EVT::getIntegerVT(*DAG.getContext(), WavefrontSize);7074 7075 SDValue SetCC = DAG.getNode(AMDGPUISD::SETCC, DL, CCVT, LHS, RHS,7076 DAG.getCondCode(CCOpcode));7077 if (VT.bitsEq(CCVT))7078 return SetCC;7079 return DAG.getZExtOrTrunc(SetCC, DL, VT);7080}7081 7082static SDValue lowerFCMPIntrinsic(const SITargetLowering &TLI, SDNode *N,7083 SelectionDAG &DAG) {7084 EVT VT = N->getValueType(0);7085 7086 unsigned CondCode = N->getConstantOperandVal(3);7087 if (!FCmpInst::isFPPredicate(static_cast<FCmpInst::Predicate>(CondCode)))7088 return DAG.getPOISON(VT);7089 7090 SDValue Src0 = N->getOperand(1);7091 SDValue Src1 = N->getOperand(2);7092 EVT CmpVT = Src0.getValueType();7093 SDLoc SL(N);7094 7095 if (CmpVT == MVT::f16 && !TLI.isTypeLegal(CmpVT)) {7096 Src0 = DAG.getNode(ISD::FP_EXTEND, SL, MVT::f32, Src0);7097 Src1 = DAG.getNode(ISD::FP_EXTEND, SL, MVT::f32, Src1);7098 }7099 7100 FCmpInst::Predicate IcInput = static_cast<FCmpInst::Predicate>(CondCode);7101 ISD::CondCode CCOpcode = getFCmpCondCode(IcInput);7102 unsigned WavefrontSize = TLI.getSubtarget()->getWavefrontSize();7103 EVT CCVT = EVT::getIntegerVT(*DAG.getContext(), WavefrontSize);7104 SDValue SetCC = DAG.getNode(AMDGPUISD::SETCC, SL, CCVT, Src0, Src1,7105 DAG.getCondCode(CCOpcode));7106 if (VT.bitsEq(CCVT))7107 return SetCC;7108 return DAG.getZExtOrTrunc(SetCC, SL, VT);7109}7110 7111static SDValue lowerBALLOTIntrinsic(const SITargetLowering &TLI, SDNode *N,7112 SelectionDAG &DAG) {7113 EVT VT = N->getValueType(0);7114 SDValue Src = N->getOperand(1);7115 SDLoc SL(N);7116 7117 if (Src.getOpcode() == ISD::SETCC) {7118 SDValue Op0 = Src.getOperand(0);7119 SDValue Op1 = Src.getOperand(1);7120 // Need to expand bfloat to float for comparison (setcc).7121 if (Op0.getValueType() == MVT::bf16) {7122 Op0 = DAG.getNode(ISD::FP_EXTEND, SL, MVT::f32, Op0);7123 Op1 = DAG.getNode(ISD::FP_EXTEND, SL, MVT::f32, Op1);7124 }7125 // (ballot (ISD::SETCC ...)) -> (AMDGPUISD::SETCC ...)7126 return DAG.getNode(AMDGPUISD::SETCC, SL, VT, Op0, Op1, Src.getOperand(2));7127 }7128 if (const ConstantSDNode *Arg = dyn_cast<ConstantSDNode>(Src)) {7129 // (ballot 0) -> 07130 if (Arg->isZero())7131 return DAG.getConstant(0, SL, VT);7132 7133 // (ballot 1) -> EXEC/EXEC_LO7134 if (Arg->isOne()) {7135 Register Exec;7136 if (VT.getScalarSizeInBits() == 32)7137 Exec = AMDGPU::EXEC_LO;7138 else if (VT.getScalarSizeInBits() == 64)7139 Exec = AMDGPU::EXEC;7140 else7141 return SDValue();7142 7143 return DAG.getCopyFromReg(DAG.getEntryNode(), SL, Exec, VT);7144 }7145 }7146 7147 // (ballot (i1 $src)) -> (AMDGPUISD::SETCC (i32 (zext $src)) (i32 0)7148 // ISD::SETNE)7149 return DAG.getNode(7150 AMDGPUISD::SETCC, SL, VT, DAG.getZExtOrTrunc(Src, SL, MVT::i32),7151 DAG.getConstant(0, SL, MVT::i32), DAG.getCondCode(ISD::SETNE));7152}7153 7154static SDValue lowerLaneOp(const SITargetLowering &TLI, SDNode *N,7155 SelectionDAG &DAG) {7156 EVT VT = N->getValueType(0);7157 unsigned ValSize = VT.getSizeInBits();7158 unsigned IID = N->getConstantOperandVal(0);7159 bool IsPermLane16 = IID == Intrinsic::amdgcn_permlane16 ||7160 IID == Intrinsic::amdgcn_permlanex16;7161 bool IsSetInactive = IID == Intrinsic::amdgcn_set_inactive ||7162 IID == Intrinsic::amdgcn_set_inactive_chain_arg;7163 SDLoc SL(N);7164 MVT IntVT = MVT::getIntegerVT(ValSize);7165 const GCNSubtarget *ST = TLI.getSubtarget();7166 unsigned SplitSize = 32;7167 if (IID == Intrinsic::amdgcn_update_dpp && (ValSize % 64 == 0) &&7168 ST->hasDPALU_DPP() &&7169 AMDGPU::isLegalDPALU_DPPControl(*ST, N->getConstantOperandVal(3)))7170 SplitSize = 64;7171 7172 auto createLaneOp = [&DAG, &SL, N, IID](SDValue Src0, SDValue Src1,7173 SDValue Src2, MVT ValT) -> SDValue {7174 SmallVector<SDValue, 8> Operands;7175 switch (IID) {7176 case Intrinsic::amdgcn_permlane16:7177 case Intrinsic::amdgcn_permlanex16:7178 case Intrinsic::amdgcn_update_dpp:7179 Operands.push_back(N->getOperand(6));7180 Operands.push_back(N->getOperand(5));7181 Operands.push_back(N->getOperand(4));7182 [[fallthrough]];7183 case Intrinsic::amdgcn_writelane:7184 Operands.push_back(Src2);7185 [[fallthrough]];7186 case Intrinsic::amdgcn_readlane:7187 case Intrinsic::amdgcn_set_inactive:7188 case Intrinsic::amdgcn_set_inactive_chain_arg:7189 case Intrinsic::amdgcn_mov_dpp8:7190 Operands.push_back(Src1);7191 [[fallthrough]];7192 case Intrinsic::amdgcn_readfirstlane:7193 case Intrinsic::amdgcn_permlane64:7194 Operands.push_back(Src0);7195 break;7196 default:7197 llvm_unreachable("unhandled lane op");7198 }7199 7200 Operands.push_back(DAG.getTargetConstant(IID, SL, MVT::i32));7201 std::reverse(Operands.begin(), Operands.end());7202 7203 if (SDNode *GL = N->getGluedNode()) {7204 assert(GL->getOpcode() == ISD::CONVERGENCECTRL_GLUE);7205 GL = GL->getOperand(0).getNode();7206 Operands.push_back(DAG.getNode(ISD::CONVERGENCECTRL_GLUE, SL, MVT::Glue,7207 SDValue(GL, 0)));7208 }7209 7210 return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, ValT, Operands);7211 };7212 7213 SDValue Src0 = N->getOperand(1);7214 SDValue Src1, Src2;7215 if (IID == Intrinsic::amdgcn_readlane || IID == Intrinsic::amdgcn_writelane ||7216 IID == Intrinsic::amdgcn_mov_dpp8 ||7217 IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16) {7218 Src1 = N->getOperand(2);7219 if (IID == Intrinsic::amdgcn_writelane ||7220 IID == Intrinsic::amdgcn_update_dpp || IsPermLane16)7221 Src2 = N->getOperand(3);7222 }7223 7224 if (ValSize == SplitSize) {7225 // Already legal7226 return SDValue();7227 }7228 7229 if (ValSize < 32) {7230 bool IsFloat = VT.isFloatingPoint();7231 Src0 = DAG.getAnyExtOrTrunc(IsFloat ? DAG.getBitcast(IntVT, Src0) : Src0,7232 SL, MVT::i32);7233 7234 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16) {7235 Src1 = DAG.getAnyExtOrTrunc(IsFloat ? DAG.getBitcast(IntVT, Src1) : Src1,7236 SL, MVT::i32);7237 }7238 7239 if (IID == Intrinsic::amdgcn_writelane) {7240 Src2 = DAG.getAnyExtOrTrunc(IsFloat ? DAG.getBitcast(IntVT, Src2) : Src2,7241 SL, MVT::i32);7242 }7243 7244 SDValue LaneOp = createLaneOp(Src0, Src1, Src2, MVT::i32);7245 SDValue Trunc = DAG.getAnyExtOrTrunc(LaneOp, SL, IntVT);7246 return IsFloat ? DAG.getBitcast(VT, Trunc) : Trunc;7247 }7248 7249 if (ValSize % SplitSize != 0)7250 return SDValue();7251 7252 auto unrollLaneOp = [&DAG, &SL](SDNode *N) -> SDValue {7253 EVT VT = N->getValueType(0);7254 unsigned NE = VT.getVectorNumElements();7255 EVT EltVT = VT.getVectorElementType();7256 SmallVector<SDValue, 8> Scalars;7257 unsigned NumOperands = N->getNumOperands();7258 SmallVector<SDValue, 4> Operands(NumOperands);7259 SDNode *GL = N->getGluedNode();7260 7261 // only handle convergencectrl_glue7262 assert(!GL || GL->getOpcode() == ISD::CONVERGENCECTRL_GLUE);7263 7264 for (unsigned i = 0; i != NE; ++i) {7265 for (unsigned j = 0, e = GL ? NumOperands - 1 : NumOperands; j != e;7266 ++j) {7267 SDValue Operand = N->getOperand(j);7268 EVT OperandVT = Operand.getValueType();7269 if (OperandVT.isVector()) {7270 // A vector operand; extract a single element.7271 EVT OperandEltVT = OperandVT.getVectorElementType();7272 Operands[j] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, OperandEltVT,7273 Operand, DAG.getVectorIdxConstant(i, SL));7274 } else {7275 // A scalar operand; just use it as is.7276 Operands[j] = Operand;7277 }7278 }7279 7280 if (GL)7281 Operands[NumOperands - 1] =7282 DAG.getNode(ISD::CONVERGENCECTRL_GLUE, SL, MVT::Glue,7283 SDValue(GL->getOperand(0).getNode(), 0));7284 7285 Scalars.push_back(DAG.getNode(N->getOpcode(), SL, EltVT, Operands));7286 }7287 7288 EVT VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT, NE);7289 return DAG.getBuildVector(VecVT, SL, Scalars);7290 };7291 7292 if (VT.isVector()) {7293 switch (MVT::SimpleValueType EltTy =7294 VT.getVectorElementType().getSimpleVT().SimpleTy) {7295 case MVT::i32:7296 case MVT::f32:7297 if (SplitSize == 32) {7298 SDValue LaneOp = createLaneOp(Src0, Src1, Src2, VT.getSimpleVT());7299 return unrollLaneOp(LaneOp.getNode());7300 }7301 [[fallthrough]];7302 case MVT::i16:7303 case MVT::f16:7304 case MVT::bf16: {7305 unsigned SubVecNumElt =7306 SplitSize / VT.getVectorElementType().getSizeInBits();7307 MVT SubVecVT = MVT::getVectorVT(EltTy, SubVecNumElt);7308 SmallVector<SDValue, 4> Pieces;7309 SDValue Src0SubVec, Src1SubVec, Src2SubVec;7310 for (unsigned i = 0, EltIdx = 0; i < ValSize / SplitSize; i++) {7311 Src0SubVec = DAG.getNode(ISD::EXTRACT_SUBVECTOR, SL, SubVecVT, Src0,7312 DAG.getConstant(EltIdx, SL, MVT::i32));7313 7314 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive ||7315 IsPermLane16)7316 Src1SubVec = DAG.getNode(ISD::EXTRACT_SUBVECTOR, SL, SubVecVT, Src1,7317 DAG.getConstant(EltIdx, SL, MVT::i32));7318 7319 if (IID == Intrinsic::amdgcn_writelane)7320 Src2SubVec = DAG.getNode(ISD::EXTRACT_SUBVECTOR, SL, SubVecVT, Src2,7321 DAG.getConstant(EltIdx, SL, MVT::i32));7322 7323 Pieces.push_back(7324 IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane167325 ? createLaneOp(Src0SubVec, Src1SubVec, Src2, SubVecVT)7326 : createLaneOp(Src0SubVec, Src1, Src2SubVec, SubVecVT));7327 EltIdx += SubVecNumElt;7328 }7329 return DAG.getNode(ISD::CONCAT_VECTORS, SL, VT, Pieces);7330 }7331 default:7332 // Handle all other cases by bitcasting to i32 vectors7333 break;7334 }7335 }7336 7337 MVT VecVT =7338 MVT::getVectorVT(MVT::getIntegerVT(SplitSize), ValSize / SplitSize);7339 Src0 = DAG.getBitcast(VecVT, Src0);7340 7341 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)7342 Src1 = DAG.getBitcast(VecVT, Src1);7343 7344 if (IID == Intrinsic::amdgcn_writelane)7345 Src2 = DAG.getBitcast(VecVT, Src2);7346 7347 SDValue LaneOp = createLaneOp(Src0, Src1, Src2, VecVT);7348 SDValue UnrolledLaneOp = unrollLaneOp(LaneOp.getNode());7349 return DAG.getBitcast(VT, UnrolledLaneOp);7350}7351 7352void SITargetLowering::ReplaceNodeResults(SDNode *N,7353 SmallVectorImpl<SDValue> &Results,7354 SelectionDAG &DAG) const {7355 switch (N->getOpcode()) {7356 case ISD::INSERT_VECTOR_ELT: {7357 if (SDValue Res = lowerINSERT_VECTOR_ELT(SDValue(N, 0), DAG))7358 Results.push_back(Res);7359 return;7360 }7361 case ISD::EXTRACT_VECTOR_ELT: {7362 if (SDValue Res = lowerEXTRACT_VECTOR_ELT(SDValue(N, 0), DAG))7363 Results.push_back(Res);7364 return;7365 }7366 case ISD::INTRINSIC_WO_CHAIN: {7367 unsigned IID = N->getConstantOperandVal(0);7368 switch (IID) {7369 case Intrinsic::amdgcn_make_buffer_rsrc:7370 Results.push_back(lowerPointerAsRsrcIntrin(N, DAG));7371 return;7372 case Intrinsic::amdgcn_cvt_pkrtz: {7373 SDValue Src0 = N->getOperand(1);7374 SDValue Src1 = N->getOperand(2);7375 SDLoc SL(N);7376 SDValue Cvt =7377 DAG.getNode(AMDGPUISD::CVT_PKRTZ_F16_F32, SL, MVT::i32, Src0, Src1);7378 Results.push_back(DAG.getNode(ISD::BITCAST, SL, MVT::v2f16, Cvt));7379 return;7380 }7381 case Intrinsic::amdgcn_cvt_pknorm_i16:7382 case Intrinsic::amdgcn_cvt_pknorm_u16:7383 case Intrinsic::amdgcn_cvt_pk_i16:7384 case Intrinsic::amdgcn_cvt_pk_u16: {7385 SDValue Src0 = N->getOperand(1);7386 SDValue Src1 = N->getOperand(2);7387 SDLoc SL(N);7388 unsigned Opcode;7389 7390 if (IID == Intrinsic::amdgcn_cvt_pknorm_i16)7391 Opcode = AMDGPUISD::CVT_PKNORM_I16_F32;7392 else if (IID == Intrinsic::amdgcn_cvt_pknorm_u16)7393 Opcode = AMDGPUISD::CVT_PKNORM_U16_F32;7394 else if (IID == Intrinsic::amdgcn_cvt_pk_i16)7395 Opcode = AMDGPUISD::CVT_PK_I16_I32;7396 else7397 Opcode = AMDGPUISD::CVT_PK_U16_U32;7398 7399 EVT VT = N->getValueType(0);7400 if (isTypeLegal(VT))7401 Results.push_back(DAG.getNode(Opcode, SL, VT, Src0, Src1));7402 else {7403 SDValue Cvt = DAG.getNode(Opcode, SL, MVT::i32, Src0, Src1);7404 Results.push_back(DAG.getNode(ISD::BITCAST, SL, MVT::v2i16, Cvt));7405 }7406 return;7407 }7408 case Intrinsic::amdgcn_s_buffer_load: {7409 // Lower llvm.amdgcn.s.buffer.load.(i8, u8) intrinsics. First, we generate7410 // s_buffer_load_u8 for signed and unsigned load instructions. Next, DAG7411 // combiner tries to merge the s_buffer_load_u8 with a sext instruction7412 // (performSignExtendInRegCombine()) and it replaces s_buffer_load_u8 with7413 // s_buffer_load_i8.7414 if (!Subtarget->hasScalarSubwordLoads())7415 return;7416 SDValue Op = SDValue(N, 0);7417 SDValue Rsrc = Op.getOperand(1);7418 SDValue Offset = Op.getOperand(2);7419 SDValue CachePolicy = Op.getOperand(3);7420 EVT VT = Op.getValueType();7421 assert(VT == MVT::i8 && "Expected 8-bit s_buffer_load intrinsics.\n");7422 SDLoc DL(Op);7423 MachineFunction &MF = DAG.getMachineFunction();7424 const DataLayout &DataLayout = DAG.getDataLayout();7425 Align Alignment =7426 DataLayout.getABITypeAlign(VT.getTypeForEVT(*DAG.getContext()));7427 MachineMemOperand *MMO = MF.getMachineMemOperand(7428 MachinePointerInfo(),7429 MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |7430 MachineMemOperand::MOInvariant,7431 VT.getStoreSize(), Alignment);7432 SDValue LoadVal;7433 if (!Offset->isDivergent()) {7434 SDValue Ops[] = {Rsrc, // source register7435 Offset, CachePolicy};7436 SDValue BufferLoad =7437 DAG.getMemIntrinsicNode(AMDGPUISD::SBUFFER_LOAD_UBYTE, DL,7438 DAG.getVTList(MVT::i32), Ops, VT, MMO);7439 LoadVal = DAG.getNode(ISD::TRUNCATE, DL, VT, BufferLoad);7440 } else {7441 SDValue Ops[] = {7442 DAG.getEntryNode(), // Chain7443 Rsrc, // rsrc7444 DAG.getConstant(0, DL, MVT::i32), // vindex7445 {}, // voffset7446 {}, // soffset7447 {}, // offset7448 CachePolicy, // cachepolicy7449 DAG.getTargetConstant(0, DL, MVT::i1), // idxen7450 };7451 setBufferOffsets(Offset, DAG, &Ops[3], Align(4));7452 LoadVal = handleByteShortBufferLoads(DAG, VT, DL, Ops, MMO);7453 }7454 Results.push_back(LoadVal);7455 return;7456 }7457 case Intrinsic::amdgcn_dead: {7458 for (unsigned I = 0, E = N->getNumValues(); I < E; ++I)7459 Results.push_back(DAG.getPOISON(N->getValueType(I)));7460 return;7461 }7462 }7463 break;7464 }7465 case ISD::INTRINSIC_W_CHAIN: {7466 if (SDValue Res = LowerINTRINSIC_W_CHAIN(SDValue(N, 0), DAG)) {7467 if (Res.getOpcode() == ISD::MERGE_VALUES) {7468 // FIXME: Hacky7469 for (unsigned I = 0; I < Res.getNumOperands(); I++) {7470 Results.push_back(Res.getOperand(I));7471 }7472 } else {7473 Results.push_back(Res);7474 Results.push_back(Res.getValue(1));7475 }7476 return;7477 }7478 7479 break;7480 }7481 case ISD::SELECT: {7482 SDLoc SL(N);7483 EVT VT = N->getValueType(0);7484 EVT NewVT = getEquivalentMemType(*DAG.getContext(), VT);7485 SDValue LHS = DAG.getNode(ISD::BITCAST, SL, NewVT, N->getOperand(1));7486 SDValue RHS = DAG.getNode(ISD::BITCAST, SL, NewVT, N->getOperand(2));7487 7488 EVT SelectVT = NewVT;7489 if (NewVT.bitsLT(MVT::i32)) {7490 LHS = DAG.getNode(ISD::ANY_EXTEND, SL, MVT::i32, LHS);7491 RHS = DAG.getNode(ISD::ANY_EXTEND, SL, MVT::i32, RHS);7492 SelectVT = MVT::i32;7493 }7494 7495 SDValue NewSelect =7496 DAG.getNode(ISD::SELECT, SL, SelectVT, N->getOperand(0), LHS, RHS);7497 7498 if (NewVT != SelectVT)7499 NewSelect = DAG.getNode(ISD::TRUNCATE, SL, NewVT, NewSelect);7500 Results.push_back(DAG.getNode(ISD::BITCAST, SL, VT, NewSelect));7501 return;7502 }7503 case ISD::FNEG: {7504 if (N->getValueType(0) != MVT::v2f16)7505 break;7506 7507 SDLoc SL(N);7508 SDValue BC = DAG.getNode(ISD::BITCAST, SL, MVT::i32, N->getOperand(0));7509 7510 SDValue Op = DAG.getNode(ISD::XOR, SL, MVT::i32, BC,7511 DAG.getConstant(0x80008000, SL, MVT::i32));7512 Results.push_back(DAG.getNode(ISD::BITCAST, SL, MVT::v2f16, Op));7513 return;7514 }7515 case ISD::FABS: {7516 if (N->getValueType(0) != MVT::v2f16)7517 break;7518 7519 SDLoc SL(N);7520 SDValue BC = DAG.getNode(ISD::BITCAST, SL, MVT::i32, N->getOperand(0));7521 7522 SDValue Op = DAG.getNode(ISD::AND, SL, MVT::i32, BC,7523 DAG.getConstant(0x7fff7fff, SL, MVT::i32));7524 Results.push_back(DAG.getNode(ISD::BITCAST, SL, MVT::v2f16, Op));7525 return;7526 }7527 case ISD::FSQRT: {7528 if (N->getValueType(0) != MVT::f16)7529 break;7530 Results.push_back(lowerFSQRTF16(SDValue(N, 0), DAG));7531 break;7532 }7533 default:7534 AMDGPUTargetLowering::ReplaceNodeResults(N, Results, DAG);7535 break;7536 }7537}7538 7539/// Helper function for LowerBRCOND7540static SDNode *findUser(SDValue Value, unsigned Opcode) {7541 7542 for (SDUse &U : Value->uses()) {7543 if (U.get() != Value)7544 continue;7545 7546 if (U.getUser()->getOpcode() == Opcode)7547 return U.getUser();7548 }7549 return nullptr;7550}7551 7552unsigned SITargetLowering::isCFIntrinsic(const SDNode *Intr) const {7553 if (Intr->getOpcode() == ISD::INTRINSIC_W_CHAIN) {7554 switch (Intr->getConstantOperandVal(1)) {7555 case Intrinsic::amdgcn_if:7556 return AMDGPUISD::IF;7557 case Intrinsic::amdgcn_else:7558 return AMDGPUISD::ELSE;7559 case Intrinsic::amdgcn_loop:7560 return AMDGPUISD::LOOP;7561 case Intrinsic::amdgcn_end_cf:7562 llvm_unreachable("should not occur");7563 default:7564 return 0;7565 }7566 }7567 7568 // break, if_break, else_break are all only used as inputs to loop, not7569 // directly as branch conditions.7570 return 0;7571}7572 7573bool SITargetLowering::shouldEmitFixup(const GlobalValue *GV) const {7574 const Triple &TT = getTargetMachine().getTargetTriple();7575 return (GV->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS ||7576 GV->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS_32BIT) &&7577 AMDGPU::shouldEmitConstantsToTextSection(TT);7578}7579 7580bool SITargetLowering::shouldEmitGOTReloc(const GlobalValue *GV) const {7581 if (Subtarget->isAmdPalOS() || Subtarget->isMesa3DOS())7582 return false;7583 7584 // FIXME: Either avoid relying on address space here or change the default7585 // address space for functions to avoid the explicit check.7586 return (GV->getValueType()->isFunctionTy() ||7587 !isNonGlobalAddrSpace(GV->getAddressSpace())) &&7588 !shouldEmitFixup(GV) && !getTargetMachine().shouldAssumeDSOLocal(GV);7589}7590 7591bool SITargetLowering::shouldEmitPCReloc(const GlobalValue *GV) const {7592 return !shouldEmitFixup(GV) && !shouldEmitGOTReloc(GV);7593}7594 7595bool SITargetLowering::shouldUseLDSConstAddress(const GlobalValue *GV) const {7596 if (!GV->hasExternalLinkage())7597 return true;7598 7599 const auto OS = getTargetMachine().getTargetTriple().getOS();7600 return OS == Triple::AMDHSA || OS == Triple::AMDPAL;7601}7602 7603/// This transforms the control flow intrinsics to get the branch destination as7604/// last parameter, also switches branch target with BR if the need arise7605SDValue SITargetLowering::LowerBRCOND(SDValue BRCOND, SelectionDAG &DAG) const {7606 SDLoc DL(BRCOND);7607 7608 SDNode *Intr = BRCOND.getOperand(1).getNode();7609 SDValue Target = BRCOND.getOperand(2);7610 SDNode *BR = nullptr;7611 SDNode *SetCC = nullptr;7612 7613 switch (Intr->getOpcode()) {7614 case ISD::SETCC: {7615 // As long as we negate the condition everything is fine7616 SetCC = Intr;7617 Intr = SetCC->getOperand(0).getNode();7618 break;7619 }7620 case ISD::XOR: {7621 // Similar to SETCC, if we have (xor c, -1), we will be fine.7622 SDValue LHS = Intr->getOperand(0);7623 SDValue RHS = Intr->getOperand(1);7624 if (auto *C = dyn_cast<ConstantSDNode>(RHS); C && C->getZExtValue()) {7625 Intr = LHS.getNode();7626 break;7627 }7628 [[fallthrough]];7629 }7630 default: {7631 // Get the target from BR if we don't negate the condition7632 BR = findUser(BRCOND, ISD::BR);7633 assert(BR && "brcond missing unconditional branch user");7634 Target = BR->getOperand(1);7635 }7636 }7637 7638 unsigned CFNode = isCFIntrinsic(Intr);7639 if (CFNode == 0) {7640 // This is a uniform branch so we don't need to legalize.7641 return BRCOND;7642 }7643 7644 bool HaveChain = Intr->getOpcode() == ISD::INTRINSIC_VOID ||7645 Intr->getOpcode() == ISD::INTRINSIC_W_CHAIN;7646 7647 assert(!SetCC ||7648 (SetCC->getConstantOperandVal(1) == 1 &&7649 cast<CondCodeSDNode>(SetCC->getOperand(2).getNode())->get() ==7650 ISD::SETNE));7651 7652 // operands of the new intrinsic call7653 SmallVector<SDValue, 4> Ops;7654 if (HaveChain)7655 Ops.push_back(BRCOND.getOperand(0));7656 7657 Ops.append(Intr->op_begin() + (HaveChain ? 2 : 1), Intr->op_end());7658 Ops.push_back(Target);7659 7660 ArrayRef<EVT> Res(Intr->value_begin() + 1, Intr->value_end());7661 7662 // build the new intrinsic call7663 SDNode *Result = DAG.getNode(CFNode, DL, DAG.getVTList(Res), Ops).getNode();7664 7665 if (!HaveChain) {7666 SDValue Ops[] = {SDValue(Result, 0), BRCOND.getOperand(0)};7667 7668 Result = DAG.getMergeValues(Ops, DL).getNode();7669 }7670 7671 if (BR) {7672 // Give the branch instruction our target7673 SDValue Ops[] = {BR->getOperand(0), BRCOND.getOperand(2)};7674 SDValue NewBR = DAG.getNode(ISD::BR, DL, BR->getVTList(), Ops);7675 DAG.ReplaceAllUsesWith(BR, NewBR.getNode());7676 }7677 7678 SDValue Chain = SDValue(Result, Result->getNumValues() - 1);7679 7680 // Copy the intrinsic results to registers7681 for (unsigned i = 1, e = Intr->getNumValues() - 1; i != e; ++i) {7682 SDNode *CopyToReg = findUser(SDValue(Intr, i), ISD::CopyToReg);7683 if (!CopyToReg)7684 continue;7685 7686 Chain = DAG.getCopyToReg(Chain, DL, CopyToReg->getOperand(1),7687 SDValue(Result, i - 1), SDValue());7688 7689 DAG.ReplaceAllUsesWith(SDValue(CopyToReg, 0), CopyToReg->getOperand(0));7690 }7691 7692 // Remove the old intrinsic from the chain7693 DAG.ReplaceAllUsesOfValueWith(SDValue(Intr, Intr->getNumValues() - 1),7694 Intr->getOperand(0));7695 7696 return Chain;7697}7698 7699SDValue SITargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const {7700 MVT VT = Op.getSimpleValueType();7701 SDLoc DL(Op);7702 // Checking the depth7703 if (Op.getConstantOperandVal(0) != 0)7704 return DAG.getConstant(0, DL, VT);7705 7706 MachineFunction &MF = DAG.getMachineFunction();7707 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();7708 // Check for kernel and shader functions7709 if (Info->isEntryFunction())7710 return DAG.getConstant(0, DL, VT);7711 7712 MachineFrameInfo &MFI = MF.getFrameInfo();7713 // There is a call to @llvm.returnaddress in this function7714 MFI.setReturnAddressIsTaken(true);7715 7716 const SIRegisterInfo *TRI = getSubtarget()->getRegisterInfo();7717 // Get the return address reg and mark it as an implicit live-in7718 Register Reg = MF.addLiveIn(TRI->getReturnAddressReg(MF),7719 getRegClassFor(VT, Op.getNode()->isDivergent()));7720 7721 return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, VT);7722}7723 7724SDValue SITargetLowering::getFPExtOrFPRound(SelectionDAG &DAG, SDValue Op,7725 const SDLoc &DL, EVT VT) const {7726 return Op.getValueType().bitsLE(VT)7727 ? DAG.getNode(ISD::FP_EXTEND, DL, VT, Op)7728 : DAG.getNode(ISD::FP_ROUND, DL, VT, Op,7729 DAG.getTargetConstant(0, DL, MVT::i32));7730}7731 7732SDValue SITargetLowering::splitFP_ROUNDVectorOp(SDValue Op,7733 SelectionDAG &DAG) const {7734 EVT DstVT = Op.getValueType();7735 unsigned NumElts = DstVT.getVectorNumElements();7736 assert(NumElts > 2 && isPowerOf2_32(NumElts));7737 7738 auto [Lo, Hi] = DAG.SplitVectorOperand(Op.getNode(), 0);7739 7740 SDLoc DL(Op);7741 unsigned Opc = Op.getOpcode();7742 SDValue Flags = Op.getOperand(1);7743 EVT HalfDstVT =7744 EVT::getVectorVT(*DAG.getContext(), DstVT.getScalarType(), NumElts / 2);7745 SDValue OpLo = DAG.getNode(Opc, DL, HalfDstVT, Lo, Flags);7746 SDValue OpHi = DAG.getNode(Opc, DL, HalfDstVT, Hi, Flags);7747 7748 return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, OpLo, OpHi);7749}7750 7751SDValue SITargetLowering::lowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const {7752 SDValue Src = Op.getOperand(0);7753 EVT SrcVT = Src.getValueType();7754 EVT DstVT = Op.getValueType();7755 7756 if (DstVT.isVector() && DstVT.getScalarType() == MVT::f16) {7757 assert(Subtarget->hasCvtPkF16F32Inst() && "support v_cvt_pk_f16_f32");7758 if (SrcVT.getScalarType() != MVT::f32)7759 return SDValue();7760 return SrcVT == MVT::v2f32 ? Op : splitFP_ROUNDVectorOp(Op, DAG);7761 }7762 7763 if (SrcVT.getScalarType() != MVT::f64)7764 return Op;7765 7766 SDLoc DL(Op);7767 if (DstVT == MVT::f16) {7768 // TODO: Handle strictfp7769 if (Op.getOpcode() != ISD::FP_ROUND)7770 return Op;7771 7772 if (!Subtarget->has16BitInsts()) {7773 SDValue FpToFp16 = DAG.getNode(ISD::FP_TO_FP16, DL, MVT::i32, Src);7774 SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, FpToFp16);7775 return DAG.getNode(ISD::BITCAST, DL, MVT::f16, Trunc);7776 }7777 if (Op->getFlags().hasApproximateFuncs()) {7778 SDValue Flags = Op.getOperand(1);7779 SDValue Src32 = DAG.getNode(ISD::FP_ROUND, DL, MVT::f32, Src, Flags);7780 return DAG.getNode(ISD::FP_ROUND, DL, MVT::f16, Src32, Flags);7781 }7782 SDValue FpToFp16 = LowerF64ToF16Safe(Src, DL, DAG);7783 SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, FpToFp16);7784 return DAG.getNode(ISD::BITCAST, DL, MVT::f16, Trunc);7785 }7786 7787 assert(DstVT.getScalarType() == MVT::bf16 &&7788 "custom lower FP_ROUND for f16 or bf16");7789 assert(Subtarget->hasBF16ConversionInsts() && "f32 -> bf16 is legal");7790 7791 // Round-inexact-to-odd f64 to f32, then do the final rounding using the7792 // hardware f32 -> bf16 instruction.7793 EVT F32VT = SrcVT.isVector() ? SrcVT.changeVectorElementType(MVT::f32) :7794 MVT::f32;7795 SDValue Rod = expandRoundInexactToOdd(F32VT, Src, DL, DAG);7796 return DAG.getNode(ISD::FP_ROUND, DL, DstVT, Rod,7797 DAG.getTargetConstant(0, DL, MVT::i32));7798}7799 7800SDValue SITargetLowering::lowerFMINNUM_FMAXNUM(SDValue Op,7801 SelectionDAG &DAG) const {7802 EVT VT = Op.getValueType();7803 const MachineFunction &MF = DAG.getMachineFunction();7804 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();7805 bool IsIEEEMode = Info->getMode().IEEE;7806 7807 // FIXME: Assert during selection that this is only selected for7808 // ieee_mode. Currently a combine can produce the ieee version for non-ieee7809 // mode functions, but this happens to be OK since it's only done in cases7810 // where there is known no sNaN.7811 if (IsIEEEMode)7812 return expandFMINNUM_FMAXNUM(Op.getNode(), DAG);7813 7814 if (VT == MVT::v4f16 || VT == MVT::v8f16 || VT == MVT::v16f16 ||7815 VT == MVT::v16bf16)7816 return splitBinaryVectorOp(Op, DAG);7817 return Op;7818}7819 7820SDValue7821SITargetLowering::lowerFMINIMUMNUM_FMAXIMUMNUM(SDValue Op,7822 SelectionDAG &DAG) const {7823 EVT VT = Op.getValueType();7824 const MachineFunction &MF = DAG.getMachineFunction();7825 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();7826 bool IsIEEEMode = Info->getMode().IEEE;7827 7828 if (IsIEEEMode)7829 return expandFMINIMUMNUM_FMAXIMUMNUM(Op.getNode(), DAG);7830 7831 if (VT == MVT::v4f16 || VT == MVT::v8f16 || VT == MVT::v16f16 ||7832 VT == MVT::v16bf16)7833 return splitBinaryVectorOp(Op, DAG);7834 return Op;7835}7836 7837SDValue SITargetLowering::lowerFMINIMUM_FMAXIMUM(SDValue Op,7838 SelectionDAG &DAG) const {7839 EVT VT = Op.getValueType();7840 if (VT.isVector())7841 return splitBinaryVectorOp(Op, DAG);7842 7843 assert(!Subtarget->hasIEEEMinimumMaximumInsts() &&7844 !Subtarget->hasMinimum3Maximum3F16() &&7845 Subtarget->hasMinimum3Maximum3PKF16() && VT == MVT::f16 &&7846 "should not need to widen f16 minimum/maximum to v2f16");7847 7848 // Widen f16 operation to v2f167849 7850 // fminimum f16:x, f16:y ->7851 // extract_vector_elt (fminimum (v2f16 (scalar_to_vector x))7852 // (v2f16 (scalar_to_vector y))), 07853 SDLoc SL(Op);7854 SDValue WideSrc0 =7855 DAG.getNode(ISD::SCALAR_TO_VECTOR, SL, MVT::v2f16, Op.getOperand(0));7856 SDValue WideSrc1 =7857 DAG.getNode(ISD::SCALAR_TO_VECTOR, SL, MVT::v2f16, Op.getOperand(1));7858 7859 SDValue Widened =7860 DAG.getNode(Op.getOpcode(), SL, MVT::v2f16, WideSrc0, WideSrc1);7861 7862 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::f16, Widened,7863 DAG.getConstant(0, SL, MVT::i32));7864}7865 7866SDValue SITargetLowering::lowerFLDEXP(SDValue Op, SelectionDAG &DAG) const {7867 bool IsStrict = Op.getOpcode() == ISD::STRICT_FLDEXP;7868 EVT VT = Op.getValueType();7869 assert(VT == MVT::f16);7870 7871 SDValue Exp = Op.getOperand(IsStrict ? 2 : 1);7872 EVT ExpVT = Exp.getValueType();7873 if (ExpVT == MVT::i16)7874 return Op;7875 7876 SDLoc DL(Op);7877 7878 // Correct the exponent type for f16 to i16.7879 // Clamp the range of the exponent to the instruction's range.7880 7881 // TODO: This should be a generic narrowing legalization, and can easily be7882 // for GlobalISel.7883 7884 SDValue MinExp = DAG.getSignedConstant(minIntN(16), DL, ExpVT);7885 SDValue ClampMin = DAG.getNode(ISD::SMAX, DL, ExpVT, Exp, MinExp);7886 7887 SDValue MaxExp = DAG.getSignedConstant(maxIntN(16), DL, ExpVT);7888 SDValue Clamp = DAG.getNode(ISD::SMIN, DL, ExpVT, ClampMin, MaxExp);7889 7890 SDValue TruncExp = DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Clamp);7891 7892 if (IsStrict) {7893 return DAG.getNode(ISD::STRICT_FLDEXP, DL, {VT, MVT::Other},7894 {Op.getOperand(0), Op.getOperand(1), TruncExp});7895 }7896 7897 return DAG.getNode(ISD::FLDEXP, DL, VT, Op.getOperand(0), TruncExp);7898}7899 7900static unsigned getExtOpcodeForPromotedOp(SDValue Op) {7901 switch (Op->getOpcode()) {7902 case ISD::SRA:7903 case ISD::SMIN:7904 case ISD::SMAX:7905 return ISD::SIGN_EXTEND;7906 case ISD::SRL:7907 case ISD::UMIN:7908 case ISD::UMAX:7909 return ISD::ZERO_EXTEND;7910 case ISD::ADD:7911 case ISD::SUB:7912 case ISD::AND:7913 case ISD::OR:7914 case ISD::XOR:7915 case ISD::SHL:7916 case ISD::SELECT:7917 case ISD::MUL:7918 // operation result won't be influenced by garbage high bits.7919 // TODO: are all of those cases correct, and are there more?7920 return ISD::ANY_EXTEND;7921 case ISD::SETCC: {7922 ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();7923 return ISD::isSignedIntSetCC(CC) ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;7924 }7925 default:7926 llvm_unreachable("unexpected opcode!");7927 }7928}7929 7930SDValue SITargetLowering::promoteUniformOpToI32(SDValue Op,7931 DAGCombinerInfo &DCI) const {7932 const unsigned Opc = Op.getOpcode();7933 assert(Opc == ISD::ADD || Opc == ISD::SUB || Opc == ISD::SHL ||7934 Opc == ISD::SRL || Opc == ISD::SRA || Opc == ISD::AND ||7935 Opc == ISD::OR || Opc == ISD::XOR || Opc == ISD::MUL ||7936 Opc == ISD::SETCC || Opc == ISD::SELECT || Opc == ISD::SMIN ||7937 Opc == ISD::SMAX || Opc == ISD::UMIN || Opc == ISD::UMAX);7938 7939 EVT OpTy = (Opc != ISD::SETCC) ? Op.getValueType()7940 : Op->getOperand(0).getValueType();7941 auto ExtTy = OpTy.changeElementType(MVT::i32);7942 7943 if (DCI.isBeforeLegalizeOps() ||7944 isNarrowingProfitable(Op.getNode(), ExtTy, OpTy))7945 return SDValue();7946 7947 auto &DAG = DCI.DAG;7948 7949 SDLoc DL(Op);7950 SDValue LHS;7951 SDValue RHS;7952 if (Opc == ISD::SELECT) {7953 LHS = Op->getOperand(1);7954 RHS = Op->getOperand(2);7955 } else {7956 LHS = Op->getOperand(0);7957 RHS = Op->getOperand(1);7958 }7959 7960 const unsigned ExtOp = getExtOpcodeForPromotedOp(Op);7961 LHS = DAG.getNode(ExtOp, DL, ExtTy, {LHS});7962 7963 // Special case: for shifts, the RHS always needs a zext.7964 if (Opc == ISD::SHL || Opc == ISD::SRL || Opc == ISD::SRA)7965 RHS = DAG.getNode(ISD::ZERO_EXTEND, DL, ExtTy, {RHS});7966 else7967 RHS = DAG.getNode(ExtOp, DL, ExtTy, {RHS});7968 7969 // setcc always return i1/i1 vec so no need to truncate after.7970 if (Opc == ISD::SETCC) {7971 ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();7972 return DAG.getSetCC(DL, Op.getValueType(), LHS, RHS, CC);7973 }7974 7975 // For other ops, we extend the operation's return type as well so we need to7976 // truncate back to the original type.7977 SDValue NewVal;7978 if (Opc == ISD::SELECT)7979 NewVal = DAG.getNode(ISD::SELECT, DL, ExtTy, {Op->getOperand(0), LHS, RHS});7980 else7981 NewVal = DAG.getNode(Opc, DL, ExtTy, {LHS, RHS});7982 7983 return DAG.getZExtOrTrunc(NewVal, DL, OpTy);7984}7985 7986SDValue SITargetLowering::lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const {7987 SDValue Mag = Op.getOperand(0);7988 EVT MagVT = Mag.getValueType();7989 7990 if (MagVT.getVectorNumElements() > 2)7991 return splitBinaryVectorOp(Op, DAG);7992 7993 SDValue Sign = Op.getOperand(1);7994 EVT SignVT = Sign.getValueType();7995 7996 if (MagVT == SignVT)7997 return Op;7998 7999 // fcopysign v2f16:mag, v2f32:sign ->8000 // fcopysign v2f16:mag, bitcast (trunc (bitcast sign to v2i32) to v2i16)8001 8002 SDLoc SL(Op);8003 SDValue SignAsInt32 = DAG.getNode(ISD::BITCAST, SL, MVT::v2i32, Sign);8004 SDValue SignAsInt16 = DAG.getNode(ISD::TRUNCATE, SL, MVT::v2i16, SignAsInt32);8005 8006 SDValue SignAsHalf16 = DAG.getNode(ISD::BITCAST, SL, MagVT, SignAsInt16);8007 8008 return DAG.getNode(ISD::FCOPYSIGN, SL, MagVT, Mag, SignAsHalf16);8009}8010 8011// Custom lowering for vector multiplications and s_mul_u64.8012SDValue SITargetLowering::lowerMUL(SDValue Op, SelectionDAG &DAG) const {8013 EVT VT = Op.getValueType();8014 8015 // Split vector operands.8016 if (VT.isVector())8017 return splitBinaryVectorOp(Op, DAG);8018 8019 assert(VT == MVT::i64 && "The following code is a special for s_mul_u64");8020 8021 // There are four ways to lower s_mul_u64:8022 //8023 // 1. If all the operands are uniform, then we lower it as it is.8024 //8025 // 2. If the operands are divergent, then we have to split s_mul_u64 in 32-bit8026 // multiplications because there is not a vector equivalent of s_mul_u64.8027 //8028 // 3. If the cost model decides that it is more efficient to use vector8029 // registers, then we have to split s_mul_u64 in 32-bit multiplications.8030 // This happens in splitScalarSMULU64() in SIInstrInfo.cpp .8031 //8032 // 4. If the cost model decides to use vector registers and both of the8033 // operands are zero-extended/sign-extended from 32-bits, then we split the8034 // s_mul_u64 in two 32-bit multiplications. The problem is that it is not8035 // possible to check if the operands are zero-extended or sign-extended in8036 // SIInstrInfo.cpp. For this reason, here, we replace s_mul_u64 with8037 // s_mul_u64_u32_pseudo if both operands are zero-extended and we replace8038 // s_mul_u64 with s_mul_i64_i32_pseudo if both operands are sign-extended.8039 // If the cost model decides that we have to use vector registers, then8040 // splitScalarSMulPseudo() (in SIInstrInfo.cpp) split s_mul_u64_u32/8041 // s_mul_i64_i32_pseudo in two vector multiplications. If the cost model8042 // decides that we should use scalar registers, then s_mul_u64_u32_pseudo/8043 // s_mul_i64_i32_pseudo is lowered as s_mul_u64 in expandPostRAPseudo() in8044 // SIInstrInfo.cpp .8045 8046 if (Op->isDivergent())8047 return SDValue();8048 8049 SDValue Op0 = Op.getOperand(0);8050 SDValue Op1 = Op.getOperand(1);8051 // If all the operands are zero-enteted to 32-bits, then we replace s_mul_u648052 // with s_mul_u64_u32_pseudo. If all the operands are sign-extended to8053 // 32-bits, then we replace s_mul_u64 with s_mul_i64_i32_pseudo.8054 KnownBits Op0KnownBits = DAG.computeKnownBits(Op0);8055 unsigned Op0LeadingZeros = Op0KnownBits.countMinLeadingZeros();8056 KnownBits Op1KnownBits = DAG.computeKnownBits(Op1);8057 unsigned Op1LeadingZeros = Op1KnownBits.countMinLeadingZeros();8058 SDLoc SL(Op);8059 if (Op0LeadingZeros >= 32 && Op1LeadingZeros >= 32)8060 return SDValue(8061 DAG.getMachineNode(AMDGPU::S_MUL_U64_U32_PSEUDO, SL, VT, Op0, Op1), 0);8062 unsigned Op0SignBits = DAG.ComputeNumSignBits(Op0);8063 unsigned Op1SignBits = DAG.ComputeNumSignBits(Op1);8064 if (Op0SignBits >= 33 && Op1SignBits >= 33)8065 return SDValue(8066 DAG.getMachineNode(AMDGPU::S_MUL_I64_I32_PSEUDO, SL, VT, Op0, Op1), 0);8067 // If all the operands are uniform, then we lower s_mul_u64 as it is.8068 return Op;8069}8070 8071SDValue SITargetLowering::lowerXMULO(SDValue Op, SelectionDAG &DAG) const {8072 EVT VT = Op.getValueType();8073 SDLoc SL(Op);8074 SDValue LHS = Op.getOperand(0);8075 SDValue RHS = Op.getOperand(1);8076 bool isSigned = Op.getOpcode() == ISD::SMULO;8077 8078 if (ConstantSDNode *RHSC = isConstOrConstSplat(RHS)) {8079 const APInt &C = RHSC->getAPIntValue();8080 // mulo(X, 1 << S) -> { X << S, (X << S) >> S != X }8081 if (C.isPowerOf2()) {8082 // smulo(x, signed_min) is same as umulo(x, signed_min).8083 bool UseArithShift = isSigned && !C.isMinSignedValue();8084 SDValue ShiftAmt = DAG.getConstant(C.logBase2(), SL, MVT::i32);8085 SDValue Result = DAG.getNode(ISD::SHL, SL, VT, LHS, ShiftAmt);8086 SDValue Overflow =8087 DAG.getSetCC(SL, MVT::i1,8088 DAG.getNode(UseArithShift ? ISD::SRA : ISD::SRL, SL, VT,8089 Result, ShiftAmt),8090 LHS, ISD::SETNE);8091 return DAG.getMergeValues({Result, Overflow}, SL);8092 }8093 }8094 8095 SDValue Result = DAG.getNode(ISD::MUL, SL, VT, LHS, RHS);8096 SDValue Top =8097 DAG.getNode(isSigned ? ISD::MULHS : ISD::MULHU, SL, VT, LHS, RHS);8098 8099 SDValue Sign = isSigned8100 ? DAG.getNode(ISD::SRA, SL, VT, Result,8101 DAG.getConstant(VT.getScalarSizeInBits() - 1,8102 SL, MVT::i32))8103 : DAG.getConstant(0, SL, VT);8104 SDValue Overflow = DAG.getSetCC(SL, MVT::i1, Top, Sign, ISD::SETNE);8105 8106 return DAG.getMergeValues({Result, Overflow}, SL);8107}8108 8109SDValue SITargetLowering::lowerXMUL_LOHI(SDValue Op, SelectionDAG &DAG) const {8110 if (Op->isDivergent()) {8111 // Select to V_MAD_[IU]64_[IU]32.8112 return Op;8113 }8114 if (Subtarget->hasSMulHi()) {8115 // Expand to S_MUL_I32 + S_MUL_HI_[IU]32.8116 return SDValue();8117 }8118 // The multiply is uniform but we would have to use V_MUL_HI_[IU]32 to8119 // calculate the high part, so we might as well do the whole thing with8120 // V_MAD_[IU]64_[IU]32.8121 return Op;8122}8123 8124SDValue SITargetLowering::lowerTRAP(SDValue Op, SelectionDAG &DAG) const {8125 if (!Subtarget->isTrapHandlerEnabled() ||8126 Subtarget->getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA)8127 return lowerTrapEndpgm(Op, DAG);8128 8129 return Subtarget->supportsGetDoorbellID() ? lowerTrapHsa(Op, DAG)8130 : lowerTrapHsaQueuePtr(Op, DAG);8131}8132 8133SDValue SITargetLowering::lowerTrapEndpgm(SDValue Op, SelectionDAG &DAG) const {8134 SDLoc SL(Op);8135 SDValue Chain = Op.getOperand(0);8136 return DAG.getNode(AMDGPUISD::ENDPGM_TRAP, SL, MVT::Other, Chain);8137}8138 8139SDValue8140SITargetLowering::loadImplicitKernelArgument(SelectionDAG &DAG, MVT VT,8141 const SDLoc &DL, Align Alignment,8142 ImplicitParameter Param) const {8143 MachineFunction &MF = DAG.getMachineFunction();8144 uint64_t Offset = getImplicitParameterOffset(MF, Param);8145 SDValue Ptr = lowerKernArgParameterPtr(DAG, DL, DAG.getEntryNode(), Offset);8146 MachinePointerInfo PtrInfo(AMDGPUAS::CONSTANT_ADDRESS);8147 return DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, PtrInfo, Alignment,8148 MachineMemOperand::MODereferenceable |8149 MachineMemOperand::MOInvariant);8150}8151 8152SDValue SITargetLowering::lowerTrapHsaQueuePtr(SDValue Op,8153 SelectionDAG &DAG) const {8154 SDLoc SL(Op);8155 SDValue Chain = Op.getOperand(0);8156 8157 SDValue QueuePtr;8158 // For code object version 5, QueuePtr is passed through implicit kernarg.8159 const Module *M = DAG.getMachineFunction().getFunction().getParent();8160 if (AMDGPU::getAMDHSACodeObjectVersion(*M) >= AMDGPU::AMDHSA_COV5) {8161 QueuePtr =8162 loadImplicitKernelArgument(DAG, MVT::i64, SL, Align(8), QUEUE_PTR);8163 } else {8164 MachineFunction &MF = DAG.getMachineFunction();8165 SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();8166 Register UserSGPR = Info->getQueuePtrUserSGPR();8167 8168 if (UserSGPR == AMDGPU::NoRegister) {8169 // We probably are in a function incorrectly marked with8170 // amdgpu-no-queue-ptr. This is undefined. We don't want to delete the8171 // trap, so just use a null pointer.8172 QueuePtr = DAG.getConstant(0, SL, MVT::i64);8173 } else {8174 QueuePtr = CreateLiveInRegister(DAG, &AMDGPU::SReg_64RegClass, UserSGPR,8175 MVT::i64);8176 }8177 }8178 8179 SDValue SGPR01 = DAG.getRegister(AMDGPU::SGPR0_SGPR1, MVT::i64);8180 SDValue ToReg = DAG.getCopyToReg(Chain, SL, SGPR01, QueuePtr, SDValue());8181 8182 uint64_t TrapID = static_cast<uint64_t>(GCNSubtarget::TrapID::LLVMAMDHSATrap);8183 SDValue Ops[] = {ToReg, DAG.getTargetConstant(TrapID, SL, MVT::i16), SGPR01,8184 ToReg.getValue(1)};8185 return DAG.getNode(AMDGPUISD::TRAP, SL, MVT::Other, Ops);8186}8187 8188SDValue SITargetLowering::lowerTrapHsa(SDValue Op, SelectionDAG &DAG) const {8189 SDLoc SL(Op);8190 SDValue Chain = Op.getOperand(0);8191 8192 // We need to simulate the 's_trap 2' instruction on targets that run in8193 // PRIV=1 (where it is treated as a nop).8194 if (Subtarget->hasPrivEnabledTrap2NopBug())8195 return DAG.getNode(AMDGPUISD::SIMULATED_TRAP, SL, MVT::Other, Chain);8196 8197 uint64_t TrapID = static_cast<uint64_t>(GCNSubtarget::TrapID::LLVMAMDHSATrap);8198 SDValue Ops[] = {Chain, DAG.getTargetConstant(TrapID, SL, MVT::i16)};8199 return DAG.getNode(AMDGPUISD::TRAP, SL, MVT::Other, Ops);8200}8201 8202SDValue SITargetLowering::lowerDEBUGTRAP(SDValue Op, SelectionDAG &DAG) const {8203 SDLoc SL(Op);8204 SDValue Chain = Op.getOperand(0);8205 MachineFunction &MF = DAG.getMachineFunction();8206 8207 if (!Subtarget->isTrapHandlerEnabled() ||8208 Subtarget->getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA) {8209 LLVMContext &Ctx = MF.getFunction().getContext();8210 Ctx.diagnose(DiagnosticInfoUnsupported(MF.getFunction(),8211 "debugtrap handler not supported",8212 Op.getDebugLoc(), DS_Warning));8213 return Chain;8214 }8215 8216 uint64_t TrapID =8217 static_cast<uint64_t>(GCNSubtarget::TrapID::LLVMAMDHSADebugTrap);8218 SDValue Ops[] = {Chain, DAG.getTargetConstant(TrapID, SL, MVT::i16)};8219 return DAG.getNode(AMDGPUISD::TRAP, SL, MVT::Other, Ops);8220}8221 8222SDValue SITargetLowering::getSegmentAperture(unsigned AS, const SDLoc &DL,8223 SelectionDAG &DAG) const {8224 if (Subtarget->hasApertureRegs()) {8225 const unsigned ApertureRegNo = (AS == AMDGPUAS::LOCAL_ADDRESS)8226 ? AMDGPU::SRC_SHARED_BASE8227 : AMDGPU::SRC_PRIVATE_BASE;8228 assert((ApertureRegNo != AMDGPU::SRC_PRIVATE_BASE ||8229 !Subtarget->hasGloballyAddressableScratch()) &&8230 "Cannot use src_private_base with globally addressable scratch!");8231 // Note: this feature (register) is broken. When used as a 32-bit operand,8232 // it returns a wrong value (all zeroes?). The real value is in the upper 328233 // bits.8234 //8235 // To work around the issue, emit a 64 bit copy from this register8236 // then extract the high bits. Note that this shouldn't even result in a8237 // shift being emitted and simply become a pair of registers (e.g.):8238 // s_mov_b64 s[6:7], src_shared_base8239 // v_mov_b32_e32 v1, s78240 SDValue Copy =8241 DAG.getCopyFromReg(DAG.getEntryNode(), DL, ApertureRegNo, MVT::v2i32);8242 return DAG.getExtractVectorElt(DL, MVT::i32, Copy, 1);8243 }8244 8245 // For code object version 5, private_base and shared_base are passed through8246 // implicit kernargs.8247 const Module *M = DAG.getMachineFunction().getFunction().getParent();8248 if (AMDGPU::getAMDHSACodeObjectVersion(*M) >= AMDGPU::AMDHSA_COV5) {8249 ImplicitParameter Param =8250 (AS == AMDGPUAS::LOCAL_ADDRESS) ? SHARED_BASE : PRIVATE_BASE;8251 return loadImplicitKernelArgument(DAG, MVT::i32, DL, Align(4), Param);8252 }8253 8254 MachineFunction &MF = DAG.getMachineFunction();8255 SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();8256 Register UserSGPR = Info->getQueuePtrUserSGPR();8257 if (UserSGPR == AMDGPU::NoRegister) {8258 // We probably are in a function incorrectly marked with8259 // amdgpu-no-queue-ptr. This is undefined.8260 return DAG.getPOISON(MVT::i32);8261 }8262 8263 SDValue QueuePtr =8264 CreateLiveInRegister(DAG, &AMDGPU::SReg_64RegClass, UserSGPR, MVT::i64);8265 8266 // Offset into amd_queue_t for group_segment_aperture_base_hi /8267 // private_segment_aperture_base_hi.8268 uint32_t StructOffset = (AS == AMDGPUAS::LOCAL_ADDRESS) ? 0x40 : 0x44;8269 8270 SDValue Ptr =8271 DAG.getObjectPtrOffset(DL, QueuePtr, TypeSize::getFixed(StructOffset));8272 8273 // TODO: Use custom target PseudoSourceValue.8274 // TODO: We should use the value from the IR intrinsic call, but it might not8275 // be available and how do we get it?8276 MachinePointerInfo PtrInfo(AMDGPUAS::CONSTANT_ADDRESS);8277 return DAG.getLoad(MVT::i32, DL, QueuePtr.getValue(1), Ptr, PtrInfo,8278 commonAlignment(Align(64), StructOffset),8279 MachineMemOperand::MODereferenceable |8280 MachineMemOperand::MOInvariant);8281}8282 8283/// Return true if the value is a known valid address, such that a null check is8284/// not necessary.8285static bool isKnownNonNull(SDValue Val, SelectionDAG &DAG,8286 const AMDGPUTargetMachine &TM, unsigned AddrSpace) {8287 if (isa<FrameIndexSDNode, GlobalAddressSDNode, BasicBlockSDNode>(Val))8288 return true;8289 8290 if (auto *ConstVal = dyn_cast<ConstantSDNode>(Val))8291 return ConstVal->getSExtValue() != TM.getNullPointerValue(AddrSpace);8292 8293 // TODO: Search through arithmetic, handle arguments and loads8294 // marked nonnull.8295 return false;8296}8297 8298SDValue SITargetLowering::lowerADDRSPACECAST(SDValue Op,8299 SelectionDAG &DAG) const {8300 SDLoc SL(Op);8301 8302 const AMDGPUTargetMachine &TM =8303 static_cast<const AMDGPUTargetMachine &>(getTargetMachine());8304 8305 unsigned DestAS, SrcAS;8306 SDValue Src;8307 bool IsNonNull = false;8308 if (const auto *ASC = dyn_cast<AddrSpaceCastSDNode>(Op)) {8309 SrcAS = ASC->getSrcAddressSpace();8310 Src = ASC->getOperand(0);8311 DestAS = ASC->getDestAddressSpace();8312 } else {8313 assert(Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN &&8314 Op.getConstantOperandVal(0) ==8315 Intrinsic::amdgcn_addrspacecast_nonnull);8316 Src = Op->getOperand(1);8317 SrcAS = Op->getConstantOperandVal(2);8318 DestAS = Op->getConstantOperandVal(3);8319 IsNonNull = true;8320 }8321 8322 SDValue FlatNullPtr = DAG.getConstant(0, SL, MVT::i64);8323 8324 // flat -> local/private8325 if (SrcAS == AMDGPUAS::FLAT_ADDRESS) {8326 if (DestAS == AMDGPUAS::LOCAL_ADDRESS ||8327 DestAS == AMDGPUAS::PRIVATE_ADDRESS) {8328 SDValue Ptr = DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, Src);8329 8330 if (DestAS == AMDGPUAS::PRIVATE_ADDRESS &&8331 Subtarget->hasGloballyAddressableScratch()) {8332 // flat -> private with globally addressable scratch: subtract8333 // src_flat_scratch_base_lo.8334 SDValue FlatScratchBaseLo(8335 DAG.getMachineNode(8336 AMDGPU::S_MOV_B32, SL, MVT::i32,8337 DAG.getRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_LO, MVT::i32)),8338 0);8339 Ptr = DAG.getNode(ISD::SUB, SL, MVT::i32, Ptr, FlatScratchBaseLo);8340 }8341 8342 if (IsNonNull || isKnownNonNull(Op, DAG, TM, SrcAS))8343 return Ptr;8344 8345 unsigned NullVal = TM.getNullPointerValue(DestAS);8346 SDValue SegmentNullPtr = DAG.getConstant(NullVal, SL, MVT::i32);8347 SDValue NonNull = DAG.getSetCC(SL, MVT::i1, Src, FlatNullPtr, ISD::SETNE);8348 8349 return DAG.getNode(ISD::SELECT, SL, MVT::i32, NonNull, Ptr,8350 SegmentNullPtr);8351 }8352 }8353 8354 // local/private -> flat8355 if (DestAS == AMDGPUAS::FLAT_ADDRESS) {8356 if (SrcAS == AMDGPUAS::LOCAL_ADDRESS ||8357 SrcAS == AMDGPUAS::PRIVATE_ADDRESS) {8358 SDValue CvtPtr;8359 if (SrcAS == AMDGPUAS::PRIVATE_ADDRESS &&8360 Subtarget->hasGloballyAddressableScratch()) {8361 // For wave32: Addr = (TID[4:0] << 52) + FLAT_SCRATCH_BASE + privateAddr8362 // For wave64: Addr = (TID[5:0] << 51) + FLAT_SCRATCH_BASE + privateAddr8363 SDValue AllOnes = DAG.getSignedTargetConstant(-1, SL, MVT::i32);8364 SDValue ThreadID = DAG.getConstant(0, SL, MVT::i32);8365 ThreadID = DAG.getNode(8366 ISD::INTRINSIC_WO_CHAIN, SL, MVT::i32,8367 DAG.getTargetConstant(Intrinsic::amdgcn_mbcnt_lo, SL, MVT::i32),8368 AllOnes, ThreadID);8369 if (Subtarget->isWave64())8370 ThreadID = DAG.getNode(8371 ISD::INTRINSIC_WO_CHAIN, SL, MVT::i32,8372 DAG.getTargetConstant(Intrinsic::amdgcn_mbcnt_hi, SL, MVT::i32),8373 AllOnes, ThreadID);8374 SDValue ShAmt = DAG.getShiftAmountConstant(8375 57 - 32 - Subtarget->getWavefrontSizeLog2(), MVT::i32, SL);8376 SDValue SrcHi = DAG.getNode(ISD::SHL, SL, MVT::i32, ThreadID, ShAmt);8377 CvtPtr = DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v2i32, Src, SrcHi);8378 CvtPtr = DAG.getNode(ISD::BITCAST, SL, MVT::i64, CvtPtr);8379 // Accessing src_flat_scratch_base_lo as a 64-bit operand gives the full8380 // 64-bit hi:lo value.8381 SDValue FlatScratchBase = {8382 DAG.getMachineNode(8383 AMDGPU::S_MOV_B64, SL, MVT::i64,8384 DAG.getRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE, MVT::i64)),8385 0};8386 CvtPtr = DAG.getNode(ISD::ADD, SL, MVT::i64, CvtPtr, FlatScratchBase);8387 } else {8388 SDValue Aperture = getSegmentAperture(SrcAS, SL, DAG);8389 CvtPtr = DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v2i32, Src, Aperture);8390 CvtPtr = DAG.getNode(ISD::BITCAST, SL, MVT::i64, CvtPtr);8391 }8392 8393 if (IsNonNull || isKnownNonNull(Op, DAG, TM, SrcAS))8394 return CvtPtr;8395 8396 unsigned NullVal = TM.getNullPointerValue(SrcAS);8397 SDValue SegmentNullPtr = DAG.getConstant(NullVal, SL, MVT::i32);8398 8399 SDValue NonNull =8400 DAG.getSetCC(SL, MVT::i1, Src, SegmentNullPtr, ISD::SETNE);8401 8402 return DAG.getNode(ISD::SELECT, SL, MVT::i64, NonNull, CvtPtr,8403 FlatNullPtr);8404 }8405 }8406 8407 if (SrcAS == AMDGPUAS::CONSTANT_ADDRESS_32BIT &&8408 Op.getValueType() == MVT::i64) {8409 const SIMachineFunctionInfo *Info =8410 DAG.getMachineFunction().getInfo<SIMachineFunctionInfo>();8411 SDValue Hi = DAG.getConstant(Info->get32BitAddressHighBits(), SL, MVT::i32);8412 SDValue Vec = DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v2i32, Src, Hi);8413 return DAG.getNode(ISD::BITCAST, SL, MVT::i64, Vec);8414 }8415 8416 if (DestAS == AMDGPUAS::CONSTANT_ADDRESS_32BIT &&8417 Src.getValueType() == MVT::i64)8418 return DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, Src);8419 8420 // global <-> flat are no-ops and never emitted.8421 8422 // Invalid casts are poison.8423 return DAG.getPOISON(Op->getValueType(0));8424}8425 8426// This lowers an INSERT_SUBVECTOR by extracting the individual elements from8427// the small vector and inserting them into the big vector. That is better than8428// the default expansion of doing it via a stack slot. Even though the use of8429// the stack slot would be optimized away afterwards, the stack slot itself8430// remains.8431SDValue SITargetLowering::lowerINSERT_SUBVECTOR(SDValue Op,8432 SelectionDAG &DAG) const {8433 SDValue Vec = Op.getOperand(0);8434 SDValue Ins = Op.getOperand(1);8435 SDValue Idx = Op.getOperand(2);8436 EVT VecVT = Vec.getValueType();8437 EVT InsVT = Ins.getValueType();8438 EVT EltVT = VecVT.getVectorElementType();8439 unsigned InsNumElts = InsVT.getVectorNumElements();8440 unsigned IdxVal = Idx->getAsZExtVal();8441 SDLoc SL(Op);8442 8443 if (EltVT.getScalarSizeInBits() == 16 && IdxVal % 2 == 0) {8444 // Insert 32-bit registers at a time.8445 assert(InsNumElts % 2 == 0 && "expect legal vector types");8446 8447 unsigned VecNumElts = VecVT.getVectorNumElements();8448 EVT NewVecVT =8449 EVT::getVectorVT(*DAG.getContext(), MVT::i32, VecNumElts / 2);8450 EVT NewInsVT = InsNumElts == 2 ? MVT::i328451 : EVT::getVectorVT(*DAG.getContext(),8452 MVT::i32, InsNumElts / 2);8453 8454 Vec = DAG.getNode(ISD::BITCAST, SL, NewVecVT, Vec);8455 Ins = DAG.getNode(ISD::BITCAST, SL, NewInsVT, Ins);8456 8457 for (unsigned I = 0; I != InsNumElts / 2; ++I) {8458 SDValue Elt;8459 if (InsNumElts == 2) {8460 Elt = Ins;8461 } else {8462 Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, Ins,8463 DAG.getConstant(I, SL, MVT::i32));8464 }8465 Vec = DAG.getNode(ISD::INSERT_VECTOR_ELT, SL, NewVecVT, Vec, Elt,8466 DAG.getConstant(IdxVal / 2 + I, SL, MVT::i32));8467 }8468 8469 return DAG.getNode(ISD::BITCAST, SL, VecVT, Vec);8470 }8471 8472 for (unsigned I = 0; I != InsNumElts; ++I) {8473 SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, EltVT, Ins,8474 DAG.getConstant(I, SL, MVT::i32));8475 Vec = DAG.getNode(ISD::INSERT_VECTOR_ELT, SL, VecVT, Vec, Elt,8476 DAG.getConstant(IdxVal + I, SL, MVT::i32));8477 }8478 return Vec;8479}8480 8481SDValue SITargetLowering::lowerINSERT_VECTOR_ELT(SDValue Op,8482 SelectionDAG &DAG) const {8483 SDValue Vec = Op.getOperand(0);8484 SDValue InsVal = Op.getOperand(1);8485 SDValue Idx = Op.getOperand(2);8486 EVT VecVT = Vec.getValueType();8487 EVT EltVT = VecVT.getVectorElementType();8488 unsigned VecSize = VecVT.getSizeInBits();8489 unsigned EltSize = EltVT.getSizeInBits();8490 SDLoc SL(Op);8491 8492 // Specially handle the case of v4i16 with static indexing.8493 unsigned NumElts = VecVT.getVectorNumElements();8494 auto *KIdx = dyn_cast<ConstantSDNode>(Idx);8495 if (NumElts == 4 && EltSize == 16 && KIdx) {8496 SDValue BCVec = DAG.getNode(ISD::BITCAST, SL, MVT::v2i32, Vec);8497 8498 SDValue LoHalf = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, BCVec,8499 DAG.getConstant(0, SL, MVT::i32));8500 SDValue HiHalf = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, BCVec,8501 DAG.getConstant(1, SL, MVT::i32));8502 8503 SDValue LoVec = DAG.getNode(ISD::BITCAST, SL, MVT::v2i16, LoHalf);8504 SDValue HiVec = DAG.getNode(ISD::BITCAST, SL, MVT::v2i16, HiHalf);8505 8506 unsigned Idx = KIdx->getZExtValue();8507 bool InsertLo = Idx < 2;8508 SDValue InsHalf = DAG.getNode(8509 ISD::INSERT_VECTOR_ELT, SL, MVT::v2i16, InsertLo ? LoVec : HiVec,8510 DAG.getNode(ISD::BITCAST, SL, MVT::i16, InsVal),8511 DAG.getConstant(InsertLo ? Idx : (Idx - 2), SL, MVT::i32));8512 8513 InsHalf = DAG.getNode(ISD::BITCAST, SL, MVT::i32, InsHalf);8514 8515 SDValue Concat =8516 InsertLo ? DAG.getBuildVector(MVT::v2i32, SL, {InsHalf, HiHalf})8517 : DAG.getBuildVector(MVT::v2i32, SL, {LoHalf, InsHalf});8518 8519 return DAG.getNode(ISD::BITCAST, SL, VecVT, Concat);8520 }8521 8522 // Static indexing does not lower to stack access, and hence there is no need8523 // for special custom lowering to avoid stack access.8524 if (isa<ConstantSDNode>(Idx))8525 return SDValue();8526 8527 // Avoid stack access for dynamic indexing by custom lowering to8528 // v_bfi_b32 (v_bfm_b32 16, (shl idx, 16)), val, vec8529 8530 assert(VecSize <= 64 && "Expected target vector size to be <= 64 bits");8531 8532 MVT IntVT = MVT::getIntegerVT(VecSize);8533 8534 // Convert vector index to bit-index and get the required bit mask.8535 assert(isPowerOf2_32(EltSize));8536 const auto EltMask = maskTrailingOnes<uint64_t>(EltSize);8537 SDValue ScaleFactor = DAG.getConstant(Log2_32(EltSize), SL, MVT::i32);8538 SDValue ScaledIdx = DAG.getNode(ISD::SHL, SL, MVT::i32, Idx, ScaleFactor);8539 SDValue BFM = DAG.getNode(ISD::SHL, SL, IntVT,8540 DAG.getConstant(EltMask, SL, IntVT), ScaledIdx);8541 8542 // 1. Create a congruent vector with the target value in each element.8543 SDValue ExtVal = DAG.getNode(ISD::BITCAST, SL, IntVT,8544 DAG.getSplatBuildVector(VecVT, SL, InsVal));8545 8546 // 2. Mask off all other indices except the required index within (1).8547 SDValue LHS = DAG.getNode(ISD::AND, SL, IntVT, BFM, ExtVal);8548 8549 // 3. Mask off the required index within the target vector.8550 SDValue BCVec = DAG.getNode(ISD::BITCAST, SL, IntVT, Vec);8551 SDValue RHS =8552 DAG.getNode(ISD::AND, SL, IntVT, DAG.getNOT(SL, BFM, IntVT), BCVec);8553 8554 // 4. Get (2) and (3) ORed into the target vector.8555 SDValue BFI =8556 DAG.getNode(ISD::OR, SL, IntVT, LHS, RHS, SDNodeFlags::Disjoint);8557 8558 return DAG.getNode(ISD::BITCAST, SL, VecVT, BFI);8559}8560 8561SDValue SITargetLowering::lowerEXTRACT_VECTOR_ELT(SDValue Op,8562 SelectionDAG &DAG) const {8563 SDLoc SL(Op);8564 8565 EVT ResultVT = Op.getValueType();8566 SDValue Vec = Op.getOperand(0);8567 SDValue Idx = Op.getOperand(1);8568 EVT VecVT = Vec.getValueType();8569 unsigned VecSize = VecVT.getSizeInBits();8570 EVT EltVT = VecVT.getVectorElementType();8571 8572 DAGCombinerInfo DCI(DAG, AfterLegalizeVectorOps, true, nullptr);8573 8574 // Make sure we do any optimizations that will make it easier to fold8575 // source modifiers before obscuring it with bit operations.8576 8577 // XXX - Why doesn't this get called when vector_shuffle is expanded?8578 if (SDValue Combined = performExtractVectorEltCombine(Op.getNode(), DCI))8579 return Combined;8580 8581 if (VecSize == 128 || VecSize == 256 || VecSize == 512) {8582 SDValue Lo, Hi;8583 auto [LoVT, HiVT] = DAG.GetSplitDestVTs(VecVT);8584 8585 if (VecSize == 128) {8586 SDValue V2 = DAG.getBitcast(MVT::v2i64, Vec);8587 Lo = DAG.getBitcast(LoVT,8588 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i64, V2,8589 DAG.getConstant(0, SL, MVT::i32)));8590 Hi = DAG.getBitcast(HiVT,8591 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i64, V2,8592 DAG.getConstant(1, SL, MVT::i32)));8593 } else if (VecSize == 256) {8594 SDValue V2 = DAG.getBitcast(MVT::v4i64, Vec);8595 SDValue Parts[4];8596 for (unsigned P = 0; P < 4; ++P) {8597 Parts[P] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i64, V2,8598 DAG.getConstant(P, SL, MVT::i32));8599 }8600 8601 Lo = DAG.getBitcast(LoVT, DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v2i64,8602 Parts[0], Parts[1]));8603 Hi = DAG.getBitcast(HiVT, DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v2i64,8604 Parts[2], Parts[3]));8605 } else {8606 assert(VecSize == 512);8607 8608 SDValue V2 = DAG.getBitcast(MVT::v8i64, Vec);8609 SDValue Parts[8];8610 for (unsigned P = 0; P < 8; ++P) {8611 Parts[P] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i64, V2,8612 DAG.getConstant(P, SL, MVT::i32));8613 }8614 8615 Lo = DAG.getBitcast(LoVT,8616 DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v4i64,8617 Parts[0], Parts[1], Parts[2], Parts[3]));8618 Hi = DAG.getBitcast(HiVT,8619 DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v4i64,8620 Parts[4], Parts[5], Parts[6], Parts[7]));8621 }8622 8623 EVT IdxVT = Idx.getValueType();8624 unsigned NElem = VecVT.getVectorNumElements();8625 assert(isPowerOf2_32(NElem));8626 SDValue IdxMask = DAG.getConstant(NElem / 2 - 1, SL, IdxVT);8627 SDValue NewIdx = DAG.getNode(ISD::AND, SL, IdxVT, Idx, IdxMask);8628 SDValue Half = DAG.getSelectCC(SL, Idx, IdxMask, Hi, Lo, ISD::SETUGT);8629 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, EltVT, Half, NewIdx);8630 }8631 8632 assert(VecSize <= 64);8633 8634 MVT IntVT = MVT::getIntegerVT(VecSize);8635 8636 // If Vec is just a SCALAR_TO_VECTOR, then use the scalar integer directly.8637 SDValue VecBC = peekThroughBitcasts(Vec);8638 if (VecBC.getOpcode() == ISD::SCALAR_TO_VECTOR) {8639 SDValue Src = VecBC.getOperand(0);8640 Src = DAG.getBitcast(Src.getValueType().changeTypeToInteger(), Src);8641 Vec = DAG.getAnyExtOrTrunc(Src, SL, IntVT);8642 }8643 8644 unsigned EltSize = EltVT.getSizeInBits();8645 assert(isPowerOf2_32(EltSize));8646 8647 SDValue ScaleFactor = DAG.getConstant(Log2_32(EltSize), SL, MVT::i32);8648 8649 // Convert vector index to bit-index (* EltSize)8650 SDValue ScaledIdx = DAG.getNode(ISD::SHL, SL, MVT::i32, Idx, ScaleFactor);8651 8652 SDValue BC = DAG.getNode(ISD::BITCAST, SL, IntVT, Vec);8653 SDValue Elt = DAG.getNode(ISD::SRL, SL, IntVT, BC, ScaledIdx);8654 8655 if (ResultVT == MVT::f16 || ResultVT == MVT::bf16) {8656 SDValue Result = DAG.getNode(ISD::TRUNCATE, SL, MVT::i16, Elt);8657 return DAG.getNode(ISD::BITCAST, SL, ResultVT, Result);8658 }8659 8660 return DAG.getAnyExtOrTrunc(Elt, SL, ResultVT);8661}8662 8663static bool elementPairIsContiguous(ArrayRef<int> Mask, int Elt) {8664 assert(Elt % 2 == 0);8665 return Mask[Elt + 1] == Mask[Elt] + 1 && (Mask[Elt] % 2 == 0);8666}8667 8668static bool elementPairIsOddToEven(ArrayRef<int> Mask, int Elt) {8669 assert(Elt % 2 == 0);8670 return Mask[Elt] >= 0 && Mask[Elt + 1] >= 0 && (Mask[Elt] & 1) &&8671 !(Mask[Elt + 1] & 1);8672}8673 8674SDValue SITargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,8675 SelectionDAG &DAG) const {8676 SDLoc SL(Op);8677 EVT ResultVT = Op.getValueType();8678 ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(Op);8679 MVT EltVT = ResultVT.getVectorElementType().getSimpleVT();8680 const int NewSrcNumElts = 2;8681 MVT PackVT = MVT::getVectorVT(EltVT, NewSrcNumElts);8682 int SrcNumElts = Op.getOperand(0).getValueType().getVectorNumElements();8683 8684 // Break up the shuffle into registers sized pieces.8685 //8686 // We're trying to form sub-shuffles that the register allocation pipeline8687 // won't be able to figure out, like how to use v_pk_mov_b32 to do a register8688 // blend or 16-bit op_sel. It should be able to figure out how to reassemble a8689 // pair of copies into a consecutive register copy, so use the ordinary8690 // extract_vector_elt lowering unless we can use the shuffle.8691 //8692 // TODO: This is a bit of hack, and we should probably always use8693 // extract_subvector for the largest possible subvector we can (or at least8694 // use it for PackVT aligned pieces). However we have worse support for8695 // combines on them don't directly treat extract_subvector / insert_subvector8696 // as legal. The DAG scheduler also ends up doing a worse job with the8697 // extract_subvectors.8698 const bool ShouldUseConsecutiveExtract = EltVT.getSizeInBits() == 16;8699 8700 // vector_shuffle <0,1,6,7> lhs, rhs8701 // -> concat_vectors (extract_subvector lhs, 0), (extract_subvector rhs, 2)8702 //8703 // vector_shuffle <6,7,2,3> lhs, rhs8704 // -> concat_vectors (extract_subvector rhs, 2), (extract_subvector lhs, 2)8705 //8706 // vector_shuffle <6,7,0,1> lhs, rhs8707 // -> concat_vectors (extract_subvector rhs, 2), (extract_subvector lhs, 0)8708 8709 // Avoid scalarizing when both halves are reading from consecutive elements.8710 8711 // If we're treating 2 element shuffles as legal, also create odd-to-even8712 // shuffles of neighboring pairs.8713 //8714 // vector_shuffle <3,2,7,6> lhs, rhs8715 // -> concat_vectors vector_shuffle <1, 0> (extract_subvector lhs, 0)8716 // vector_shuffle <1, 0> (extract_subvector rhs, 2)8717 8718 SmallVector<SDValue, 16> Pieces;8719 for (int I = 0, N = ResultVT.getVectorNumElements(); I != N; I += 2) {8720 if (ShouldUseConsecutiveExtract &&8721 elementPairIsContiguous(SVN->getMask(), I)) {8722 const int Idx = SVN->getMaskElt(I);8723 int VecIdx = Idx < SrcNumElts ? 0 : 1;8724 int EltIdx = Idx < SrcNumElts ? Idx : Idx - SrcNumElts;8725 SDValue SubVec = DAG.getNode(ISD::EXTRACT_SUBVECTOR, SL, PackVT,8726 SVN->getOperand(VecIdx),8727 DAG.getConstant(EltIdx, SL, MVT::i32));8728 Pieces.push_back(SubVec);8729 } else if (elementPairIsOddToEven(SVN->getMask(), I) &&8730 isOperationLegal(ISD::VECTOR_SHUFFLE, PackVT)) {8731 int Idx0 = SVN->getMaskElt(I);8732 int Idx1 = SVN->getMaskElt(I + 1);8733 8734 SDValue SrcOp0 = SVN->getOperand(0);8735 SDValue SrcOp1 = SrcOp0;8736 if (Idx0 >= SrcNumElts) {8737 SrcOp0 = SVN->getOperand(1);8738 Idx0 -= SrcNumElts;8739 }8740 8741 if (Idx1 >= SrcNumElts) {8742 SrcOp1 = SVN->getOperand(1);8743 Idx1 -= SrcNumElts;8744 }8745 8746 int AlignedIdx0 = Idx0 & ~(NewSrcNumElts - 1);8747 int AlignedIdx1 = Idx1 & ~(NewSrcNumElts - 1);8748 8749 // Extract nearest even aligned piece.8750 SDValue SubVec0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, SL, PackVT, SrcOp0,8751 DAG.getConstant(AlignedIdx0, SL, MVT::i32));8752 SDValue SubVec1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, SL, PackVT, SrcOp1,8753 DAG.getConstant(AlignedIdx1, SL, MVT::i32));8754 8755 int NewMaskIdx0 = Idx0 - AlignedIdx0;8756 int NewMaskIdx1 = Idx1 - AlignedIdx1;8757 8758 SDValue Result0 = SubVec0;8759 SDValue Result1 = SubVec0;8760 8761 if (SubVec0 != SubVec1) {8762 NewMaskIdx1 += NewSrcNumElts;8763 Result1 = SubVec1;8764 } else {8765 Result1 = DAG.getPOISON(PackVT);8766 }8767 8768 SDValue Shuf = DAG.getVectorShuffle(PackVT, SL, Result0, Result1,8769 {NewMaskIdx0, NewMaskIdx1});8770 Pieces.push_back(Shuf);8771 } else {8772 const int Idx0 = SVN->getMaskElt(I);8773 const int Idx1 = SVN->getMaskElt(I + 1);8774 int VecIdx0 = Idx0 < SrcNumElts ? 0 : 1;8775 int VecIdx1 = Idx1 < SrcNumElts ? 0 : 1;8776 int EltIdx0 = Idx0 < SrcNumElts ? Idx0 : Idx0 - SrcNumElts;8777 int EltIdx1 = Idx1 < SrcNumElts ? Idx1 : Idx1 - SrcNumElts;8778 8779 SDValue Vec0 = SVN->getOperand(VecIdx0);8780 SDValue Elt0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, EltVT, Vec0,8781 DAG.getSignedConstant(EltIdx0, SL, MVT::i32));8782 8783 SDValue Vec1 = SVN->getOperand(VecIdx1);8784 SDValue Elt1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, EltVT, Vec1,8785 DAG.getSignedConstant(EltIdx1, SL, MVT::i32));8786 Pieces.push_back(DAG.getBuildVector(PackVT, SL, {Elt0, Elt1}));8787 }8788 }8789 8790 return DAG.getNode(ISD::CONCAT_VECTORS, SL, ResultVT, Pieces);8791}8792 8793SDValue SITargetLowering::lowerSCALAR_TO_VECTOR(SDValue Op,8794 SelectionDAG &DAG) const {8795 SDValue SVal = Op.getOperand(0);8796 EVT ResultVT = Op.getValueType();8797 EVT SValVT = SVal.getValueType();8798 SDValue UndefVal = DAG.getPOISON(SValVT);8799 SDLoc SL(Op);8800 8801 SmallVector<SDValue, 8> VElts;8802 VElts.push_back(SVal);8803 for (int I = 1, E = ResultVT.getVectorNumElements(); I < E; ++I)8804 VElts.push_back(UndefVal);8805 8806 return DAG.getBuildVector(ResultVT, SL, VElts);8807}8808 8809SDValue SITargetLowering::lowerBUILD_VECTOR(SDValue Op,8810 SelectionDAG &DAG) const {8811 SDLoc SL(Op);8812 EVT VT = Op.getValueType();8813 8814 if (VT == MVT::v2f16 || VT == MVT::v2i16 || VT == MVT::v2bf16) {8815 assert(!Subtarget->hasVOP3PInsts() && "this should be legal");8816 8817 SDValue Lo = Op.getOperand(0);8818 SDValue Hi = Op.getOperand(1);8819 8820 // Avoid adding defined bits with the zero_extend.8821 if (Hi.isUndef()) {8822 Lo = DAG.getNode(ISD::BITCAST, SL, MVT::i16, Lo);8823 SDValue ExtLo = DAG.getNode(ISD::ANY_EXTEND, SL, MVT::i32, Lo);8824 return DAG.getNode(ISD::BITCAST, SL, VT, ExtLo);8825 }8826 8827 Hi = DAG.getNode(ISD::BITCAST, SL, MVT::i16, Hi);8828 Hi = DAG.getNode(ISD::ZERO_EXTEND, SL, MVT::i32, Hi);8829 8830 SDValue ShlHi = DAG.getNode(ISD::SHL, SL, MVT::i32, Hi,8831 DAG.getConstant(16, SL, MVT::i32));8832 if (Lo.isUndef())8833 return DAG.getNode(ISD::BITCAST, SL, VT, ShlHi);8834 8835 Lo = DAG.getNode(ISD::BITCAST, SL, MVT::i16, Lo);8836 Lo = DAG.getNode(ISD::ZERO_EXTEND, SL, MVT::i32, Lo);8837 8838 SDValue Or =8839 DAG.getNode(ISD::OR, SL, MVT::i32, Lo, ShlHi, SDNodeFlags::Disjoint);8840 return DAG.getNode(ISD::BITCAST, SL, VT, Or);8841 }8842 8843 // Split into 2-element chunks.8844 const unsigned NumParts = VT.getVectorNumElements() / 2;8845 EVT PartVT = MVT::getVectorVT(VT.getVectorElementType().getSimpleVT(), 2);8846 MVT PartIntVT = MVT::getIntegerVT(PartVT.getSizeInBits());8847 8848 SmallVector<SDValue> Casts;8849 for (unsigned P = 0; P < NumParts; ++P) {8850 SDValue Vec = DAG.getBuildVector(8851 PartVT, SL, {Op.getOperand(P * 2), Op.getOperand(P * 2 + 1)});8852 Casts.push_back(DAG.getNode(ISD::BITCAST, SL, PartIntVT, Vec));8853 }8854 8855 SDValue Blend =8856 DAG.getBuildVector(MVT::getVectorVT(PartIntVT, NumParts), SL, Casts);8857 return DAG.getNode(ISD::BITCAST, SL, VT, Blend);8858}8859 8860bool SITargetLowering::isOffsetFoldingLegal(8861 const GlobalAddressSDNode *GA) const {8862 // OSes that use ELF REL relocations (instead of RELA) can only store a8863 // 32-bit addend in the instruction, so it is not safe to allow offset folding8864 // which can create arbitrary 64-bit addends. (This is only a problem for8865 // R_AMDGPU_*32_HI relocations since other relocation types are unaffected by8866 // the high 32 bits of the addend.)8867 //8868 // This should be kept in sync with how HasRelocationAddend is initialized in8869 // the constructor of ELFAMDGPUAsmBackend.8870 if (!Subtarget->isAmdHsaOS())8871 return false;8872 8873 // We can fold offsets for anything that doesn't require a GOT relocation.8874 return (GA->getAddressSpace() == AMDGPUAS::GLOBAL_ADDRESS ||8875 GA->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS ||8876 GA->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS_32BIT) &&8877 !shouldEmitGOTReloc(GA->getGlobal());8878}8879 8880static SDValue8881buildPCRelGlobalAddress(SelectionDAG &DAG, const GlobalValue *GV,8882 const SDLoc &DL, int64_t Offset, EVT PtrVT,8883 unsigned GAFlags = SIInstrInfo::MO_NONE) {8884 assert(isInt<32>(Offset + 4) && "32-bit offset is expected!");8885 // In order to support pc-relative addressing, the PC_ADD_REL_OFFSET SDNode is8886 // lowered to the following code sequence:8887 //8888 // For constant address space:8889 // s_getpc_b64 s[0:1]8890 // s_add_u32 s0, s0, $symbol8891 // s_addc_u32 s1, s1, 08892 //8893 // s_getpc_b64 returns the address of the s_add_u32 instruction and then8894 // a fixup or relocation is emitted to replace $symbol with a literal8895 // constant, which is a pc-relative offset from the encoding of the $symbol8896 // operand to the global variable.8897 //8898 // For global address space:8899 // s_getpc_b64 s[0:1]8900 // s_add_u32 s0, s0, $symbol@{gotpc}rel32@lo8901 // s_addc_u32 s1, s1, $symbol@{gotpc}rel32@hi8902 //8903 // s_getpc_b64 returns the address of the s_add_u32 instruction and then8904 // fixups or relocations are emitted to replace $symbol@*@lo and8905 // $symbol@*@hi with lower 32 bits and higher 32 bits of a literal constant,8906 // which is a 64-bit pc-relative offset from the encoding of the $symbol8907 // operand to the global variable.8908 if (((const GCNSubtarget &)DAG.getSubtarget()).has64BitLiterals()) {8909 assert(GAFlags != SIInstrInfo::MO_NONE);8910 8911 SDValue Ptr =8912 DAG.getTargetGlobalAddress(GV, DL, MVT::i64, Offset, GAFlags + 2);8913 return DAG.getNode(AMDGPUISD::PC_ADD_REL_OFFSET64, DL, PtrVT, Ptr);8914 }8915 8916 SDValue PtrLo = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, Offset, GAFlags);8917 SDValue PtrHi;8918 if (GAFlags == SIInstrInfo::MO_NONE)8919 PtrHi = DAG.getTargetConstant(0, DL, MVT::i32);8920 else8921 PtrHi = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, Offset, GAFlags + 1);8922 return DAG.getNode(AMDGPUISD::PC_ADD_REL_OFFSET, DL, PtrVT, PtrLo, PtrHi);8923}8924 8925SDValue SITargetLowering::LowerGlobalAddress(AMDGPUMachineFunction *MFI,8926 SDValue Op,8927 SelectionDAG &DAG) const {8928 GlobalAddressSDNode *GSD = cast<GlobalAddressSDNode>(Op);8929 SDLoc DL(GSD);8930 EVT PtrVT = Op.getValueType();8931 8932 const GlobalValue *GV = GSD->getGlobal();8933 if ((GSD->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS &&8934 shouldUseLDSConstAddress(GV)) ||8935 GSD->getAddressSpace() == AMDGPUAS::REGION_ADDRESS ||8936 GSD->getAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS) {8937 if (GSD->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS &&8938 GV->hasExternalLinkage()) {8939 Type *Ty = GV->getValueType();8940 // HIP uses an unsized array `extern __shared__ T s[]` or similar8941 // zero-sized type in other languages to declare the dynamic shared8942 // memory which size is not known at the compile time. They will be8943 // allocated by the runtime and placed directly after the static8944 // allocated ones. They all share the same offset.8945 if (DAG.getDataLayout().getTypeAllocSize(Ty).isZero()) {8946 assert(PtrVT == MVT::i32 && "32-bit pointer is expected.");8947 // Adjust alignment for that dynamic shared memory array.8948 Function &F = DAG.getMachineFunction().getFunction();8949 MFI->setDynLDSAlign(F, *cast<GlobalVariable>(GV));8950 MFI->setUsesDynamicLDS(true);8951 return SDValue(8952 DAG.getMachineNode(AMDGPU::GET_GROUPSTATICSIZE, DL, PtrVT), 0);8953 }8954 }8955 return AMDGPUTargetLowering::LowerGlobalAddress(MFI, Op, DAG);8956 }8957 8958 if (GSD->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {8959 SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, GSD->getOffset(),8960 SIInstrInfo::MO_ABS32_LO);8961 return DAG.getNode(AMDGPUISD::LDS, DL, MVT::i32, GA);8962 }8963 8964 if (Subtarget->isAmdPalOS() || Subtarget->isMesa3DOS()) {8965 if (Subtarget->has64BitLiterals()) {8966 SDValue Addr = DAG.getTargetGlobalAddress(8967 GV, DL, MVT::i64, GSD->getOffset(), SIInstrInfo::MO_ABS64);8968 return SDValue(DAG.getMachineNode(AMDGPU::S_MOV_B64, DL, MVT::i64, Addr),8969 0);8970 }8971 8972 SDValue AddrLo = DAG.getTargetGlobalAddress(8973 GV, DL, MVT::i32, GSD->getOffset(), SIInstrInfo::MO_ABS32_LO);8974 AddrLo = {DAG.getMachineNode(AMDGPU::S_MOV_B32, DL, MVT::i32, AddrLo), 0};8975 8976 SDValue AddrHi = DAG.getTargetGlobalAddress(8977 GV, DL, MVT::i32, GSD->getOffset(), SIInstrInfo::MO_ABS32_HI);8978 AddrHi = {DAG.getMachineNode(AMDGPU::S_MOV_B32, DL, MVT::i32, AddrHi), 0};8979 8980 return DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, AddrLo, AddrHi);8981 }8982 8983 if (shouldEmitFixup(GV))8984 return buildPCRelGlobalAddress(DAG, GV, DL, GSD->getOffset(), PtrVT);8985 8986 if (shouldEmitPCReloc(GV))8987 return buildPCRelGlobalAddress(DAG, GV, DL, GSD->getOffset(), PtrVT,8988 SIInstrInfo::MO_REL32);8989 8990 SDValue GOTAddr = buildPCRelGlobalAddress(DAG, GV, DL, 0, PtrVT,8991 SIInstrInfo::MO_GOTPCREL32);8992 PointerType *PtrTy =8993 PointerType::get(*DAG.getContext(), AMDGPUAS::CONSTANT_ADDRESS);8994 const DataLayout &DataLayout = DAG.getDataLayout();8995 Align Alignment = DataLayout.getABITypeAlign(PtrTy);8996 MachinePointerInfo PtrInfo =8997 MachinePointerInfo::getGOT(DAG.getMachineFunction());8998 8999 return DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), GOTAddr, PtrInfo, Alignment,9000 MachineMemOperand::MODereferenceable |9001 MachineMemOperand::MOInvariant);9002}9003 9004SDValue SITargetLowering::copyToM0(SelectionDAG &DAG, SDValue Chain,9005 const SDLoc &DL, SDValue V) const {9006 // We can't use S_MOV_B32 directly, because there is no way to specify m0 as9007 // the destination register.9008 //9009 // We can't use CopyToReg, because MachineCSE won't combine COPY instructions,9010 // so we will end up with redundant moves to m0.9011 //9012 // We use a pseudo to ensure we emit s_mov_b32 with m0 as the direct result.9013 9014 // A Null SDValue creates a glue result.9015 SDNode *M0 = DAG.getMachineNode(AMDGPU::SI_INIT_M0, DL, MVT::Other, MVT::Glue,9016 V, Chain);9017 return SDValue(M0, 0);9018}9019 9020SDValue SITargetLowering::lowerImplicitZextParam(SelectionDAG &DAG, SDValue Op,9021 MVT VT,9022 unsigned Offset) const {9023 SDLoc SL(Op);9024 SDValue Param = lowerKernargMemParameter(9025 DAG, MVT::i32, MVT::i32, SL, DAG.getEntryNode(), Offset, Align(4), false);9026 // The local size values will have the hi 16-bits as zero.9027 return DAG.getNode(ISD::AssertZext, SL, MVT::i32, Param,9028 DAG.getValueType(VT));9029}9030 9031static SDValue emitNonHSAIntrinsicError(SelectionDAG &DAG, const SDLoc &DL,9032 EVT VT) {9033 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(9034 DAG.getMachineFunction().getFunction(),9035 "non-hsa intrinsic with hsa target", DL.getDebugLoc()));9036 return DAG.getPOISON(VT);9037}9038 9039static SDValue emitRemovedIntrinsicError(SelectionDAG &DAG, const SDLoc &DL,9040 EVT VT) {9041 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(9042 DAG.getMachineFunction().getFunction(),9043 "intrinsic not supported on subtarget", DL.getDebugLoc()));9044 return DAG.getPOISON(VT);9045}9046 9047static SDValue getBuildDwordsVector(SelectionDAG &DAG, SDLoc DL,9048 ArrayRef<SDValue> Elts) {9049 assert(!Elts.empty());9050 MVT Type;9051 unsigned NumElts = Elts.size();9052 9053 if (NumElts <= 12) {9054 Type = MVT::getVectorVT(MVT::f32, NumElts);9055 } else {9056 assert(Elts.size() <= 16);9057 Type = MVT::v16f32;9058 NumElts = 16;9059 }9060 9061 SmallVector<SDValue, 16> VecElts(NumElts);9062 for (unsigned i = 0; i < Elts.size(); ++i) {9063 SDValue Elt = Elts[i];9064 if (Elt.getValueType() != MVT::f32)9065 Elt = DAG.getBitcast(MVT::f32, Elt);9066 VecElts[i] = Elt;9067 }9068 for (unsigned i = Elts.size(); i < NumElts; ++i)9069 VecElts[i] = DAG.getPOISON(MVT::f32);9070 9071 if (NumElts == 1)9072 return VecElts[0];9073 return DAG.getBuildVector(Type, DL, VecElts);9074}9075 9076static SDValue padEltsToUndef(SelectionDAG &DAG, const SDLoc &DL, EVT CastVT,9077 SDValue Src, int ExtraElts) {9078 EVT SrcVT = Src.getValueType();9079 9080 SmallVector<SDValue, 8> Elts;9081 9082 if (SrcVT.isVector())9083 DAG.ExtractVectorElements(Src, Elts);9084 else9085 Elts.push_back(Src);9086 9087 SDValue Undef = DAG.getPOISON(SrcVT.getScalarType());9088 while (ExtraElts--)9089 Elts.push_back(Undef);9090 9091 return DAG.getBuildVector(CastVT, DL, Elts);9092}9093 9094// Re-construct the required return value for a image load intrinsic.9095// This is more complicated due to the optional use TexFailCtrl which means the9096// required return type is an aggregate9097static SDValue constructRetValue(SelectionDAG &DAG, MachineSDNode *Result,9098 ArrayRef<EVT> ResultTypes, bool IsTexFail,9099 bool Unpacked, bool IsD16, int DMaskPop,9100 int NumVDataDwords, bool IsAtomicPacked16Bit,9101 const SDLoc &DL) {9102 // Determine the required return type. This is the same regardless of9103 // IsTexFail flag9104 EVT ReqRetVT = ResultTypes[0];9105 int ReqRetNumElts = ReqRetVT.isVector() ? ReqRetVT.getVectorNumElements() : 1;9106 int NumDataDwords = ((IsD16 && !Unpacked) || IsAtomicPacked16Bit)9107 ? (ReqRetNumElts + 1) / 29108 : ReqRetNumElts;9109 9110 int MaskPopDwords = (!IsD16 || Unpacked) ? DMaskPop : (DMaskPop + 1) / 2;9111 9112 MVT DataDwordVT =9113 NumDataDwords == 1 ? MVT::i32 : MVT::getVectorVT(MVT::i32, NumDataDwords);9114 9115 MVT MaskPopVT =9116 MaskPopDwords == 1 ? MVT::i32 : MVT::getVectorVT(MVT::i32, MaskPopDwords);9117 9118 SDValue Data(Result, 0);9119 SDValue TexFail;9120 9121 if (DMaskPop > 0 && Data.getValueType() != MaskPopVT) {9122 SDValue ZeroIdx = DAG.getConstant(0, DL, MVT::i32);9123 if (MaskPopVT.isVector()) {9124 Data = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, MaskPopVT,9125 SDValue(Result, 0), ZeroIdx);9126 } else {9127 Data = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MaskPopVT,9128 SDValue(Result, 0), ZeroIdx);9129 }9130 }9131 9132 if (DataDwordVT.isVector() && !IsAtomicPacked16Bit)9133 Data = padEltsToUndef(DAG, DL, DataDwordVT, Data,9134 NumDataDwords - MaskPopDwords);9135 9136 if (IsD16)9137 Data = adjustLoadValueTypeImpl(Data, ReqRetVT, DL, DAG, Unpacked);9138 9139 EVT LegalReqRetVT = ReqRetVT;9140 if (!ReqRetVT.isVector()) {9141 if (!Data.getValueType().isInteger())9142 Data = DAG.getNode(ISD::BITCAST, DL,9143 Data.getValueType().changeTypeToInteger(), Data);9144 Data = DAG.getNode(ISD::TRUNCATE, DL, ReqRetVT.changeTypeToInteger(), Data);9145 } else {9146 // We need to widen the return vector to a legal type9147 if ((ReqRetVT.getVectorNumElements() % 2) == 1 &&9148 ReqRetVT.getVectorElementType().getSizeInBits() == 16) {9149 LegalReqRetVT =9150 EVT::getVectorVT(*DAG.getContext(), ReqRetVT.getVectorElementType(),9151 ReqRetVT.getVectorNumElements() + 1);9152 }9153 }9154 Data = DAG.getNode(ISD::BITCAST, DL, LegalReqRetVT, Data);9155 9156 if (IsTexFail) {9157 TexFail =9158 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, SDValue(Result, 0),9159 DAG.getConstant(MaskPopDwords, DL, MVT::i32));9160 9161 return DAG.getMergeValues({Data, TexFail, SDValue(Result, 1)}, DL);9162 }9163 9164 if (Result->getNumValues() == 1)9165 return Data;9166 9167 return DAG.getMergeValues({Data, SDValue(Result, 1)}, DL);9168}9169 9170static bool parseTexFail(SDValue TexFailCtrl, SelectionDAG &DAG, SDValue *TFE,9171 SDValue *LWE, bool &IsTexFail) {9172 auto *TexFailCtrlConst = cast<ConstantSDNode>(TexFailCtrl.getNode());9173 9174 uint64_t Value = TexFailCtrlConst->getZExtValue();9175 if (Value) {9176 IsTexFail = true;9177 }9178 9179 SDLoc DL(TexFailCtrlConst);9180 *TFE = DAG.getTargetConstant((Value & 0x1) ? 1 : 0, DL, MVT::i32);9181 Value &= ~(uint64_t)0x1;9182 *LWE = DAG.getTargetConstant((Value & 0x2) ? 1 : 0, DL, MVT::i32);9183 Value &= ~(uint64_t)0x2;9184 9185 return Value == 0;9186}9187 9188static void packImage16bitOpsToDwords(SelectionDAG &DAG, SDValue Op,9189 MVT PackVectorVT,9190 SmallVectorImpl<SDValue> &PackedAddrs,9191 unsigned DimIdx, unsigned EndIdx,9192 unsigned NumGradients) {9193 SDLoc DL(Op);9194 for (unsigned I = DimIdx; I < EndIdx; I++) {9195 SDValue Addr = Op.getOperand(I);9196 9197 // Gradients are packed with undef for each coordinate.9198 // In <hi 16 bit>,<lo 16 bit> notation, the registers look like this:9199 // 1D: undef,dx/dh; undef,dx/dv9200 // 2D: dy/dh,dx/dh; dy/dv,dx/dv9201 // 3D: dy/dh,dx/dh; undef,dz/dh; dy/dv,dx/dv; undef,dz/dv9202 if (((I + 1) >= EndIdx) ||9203 ((NumGradients / 2) % 2 == 1 && (I == DimIdx + (NumGradients / 2) - 1 ||9204 I == DimIdx + NumGradients - 1))) {9205 if (Addr.getValueType() != MVT::i16)9206 Addr = DAG.getBitcast(MVT::i16, Addr);9207 Addr = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Addr);9208 } else {9209 Addr = DAG.getBuildVector(PackVectorVT, DL, {Addr, Op.getOperand(I + 1)});9210 I++;9211 }9212 Addr = DAG.getBitcast(MVT::f32, Addr);9213 PackedAddrs.push_back(Addr);9214 }9215}9216 9217SDValue SITargetLowering::lowerImage(SDValue Op,9218 const AMDGPU::ImageDimIntrinsicInfo *Intr,9219 SelectionDAG &DAG, bool WithChain) const {9220 SDLoc DL(Op);9221 MachineFunction &MF = DAG.getMachineFunction();9222 const GCNSubtarget *ST = &MF.getSubtarget<GCNSubtarget>();9223 unsigned IntrOpcode = Intr->BaseOpcode;9224 // For image atomic: use no-return opcode if result is unused.9225 if (Intr->AtomicNoRetBaseOpcode != Intr->BaseOpcode &&9226 !Op.getNode()->hasAnyUseOfValue(0))9227 IntrOpcode = Intr->AtomicNoRetBaseOpcode;9228 const AMDGPU::MIMGBaseOpcodeInfo *BaseOpcode =9229 AMDGPU::getMIMGBaseOpcodeInfo(IntrOpcode);9230 const AMDGPU::MIMGDimInfo *DimInfo = AMDGPU::getMIMGDimInfo(Intr->Dim);9231 bool IsGFX10Plus = AMDGPU::isGFX10Plus(*Subtarget);9232 bool IsGFX11Plus = AMDGPU::isGFX11Plus(*Subtarget);9233 bool IsGFX12Plus = AMDGPU::isGFX12Plus(*Subtarget);9234 9235 SmallVector<EVT, 3> ResultTypes(Op->values());9236 SmallVector<EVT, 3> OrigResultTypes(Op->values());9237 if (BaseOpcode->NoReturn && BaseOpcode->Atomic)9238 ResultTypes.erase(&ResultTypes[0]);9239 9240 bool IsD16 = false;9241 bool IsG16 = false;9242 bool IsA16 = false;9243 SDValue VData;9244 int NumVDataDwords = 0;9245 bool AdjustRetType = false;9246 bool IsAtomicPacked16Bit = false;9247 9248 // Offset of intrinsic arguments9249 const unsigned ArgOffset = WithChain ? 2 : 1;9250 9251 unsigned DMask;9252 unsigned DMaskLanes = 0;9253 9254 if (BaseOpcode->Atomic) {9255 VData = Op.getOperand(2);9256 9257 IsAtomicPacked16Bit =9258 (IntrOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_F16 ||9259 IntrOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_F16_NORTN ||9260 IntrOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_BF16 ||9261 IntrOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_BF16_NORTN);9262 9263 bool Is64Bit = VData.getValueSizeInBits() == 64;9264 if (BaseOpcode->AtomicX2) {9265 SDValue VData2 = Op.getOperand(3);9266 VData = DAG.getBuildVector(Is64Bit ? MVT::v2i64 : MVT::v2i32, DL,9267 {VData, VData2});9268 if (Is64Bit)9269 VData = DAG.getBitcast(MVT::v4i32, VData);9270 9271 if (!BaseOpcode->NoReturn)9272 ResultTypes[0] = Is64Bit ? MVT::v2i64 : MVT::v2i32;9273 9274 DMask = Is64Bit ? 0xf : 0x3;9275 NumVDataDwords = Is64Bit ? 4 : 2;9276 } else {9277 DMask = Is64Bit ? 0x3 : 0x1;9278 NumVDataDwords = Is64Bit ? 2 : 1;9279 }9280 } else {9281 DMask = Op->getConstantOperandVal(ArgOffset + Intr->DMaskIndex);9282 DMaskLanes = BaseOpcode->Gather4 ? 4 : llvm::popcount(DMask);9283 9284 if (BaseOpcode->Store) {9285 VData = Op.getOperand(2);9286 9287 MVT StoreVT = VData.getSimpleValueType();9288 if (StoreVT.getScalarType() == MVT::f16) {9289 if (!Subtarget->hasD16Images() || !BaseOpcode->HasD16)9290 return Op; // D16 is unsupported for this instruction9291 9292 IsD16 = true;9293 VData = handleD16VData(VData, DAG, true);9294 }9295 9296 NumVDataDwords = (VData.getValueType().getSizeInBits() + 31) / 32;9297 } else if (!BaseOpcode->NoReturn) {9298 // Work out the num dwords based on the dmask popcount and underlying type9299 // and whether packing is supported.9300 MVT LoadVT = ResultTypes[0].getSimpleVT();9301 if (LoadVT.getScalarType() == MVT::f16) {9302 if (!Subtarget->hasD16Images() || !BaseOpcode->HasD16)9303 return Op; // D16 is unsupported for this instruction9304 9305 IsD16 = true;9306 }9307 9308 // Confirm that the return type is large enough for the dmask specified9309 if ((LoadVT.isVector() && LoadVT.getVectorNumElements() < DMaskLanes) ||9310 (!LoadVT.isVector() && DMaskLanes > 1))9311 return Op;9312 9313 // The sq block of gfx8 and gfx9 do not estimate register use correctly9314 // for d16 image_gather4, image_gather4_l, and image_gather4_lz9315 // instructions.9316 if (IsD16 && !Subtarget->hasUnpackedD16VMem() &&9317 !(BaseOpcode->Gather4 && Subtarget->hasImageGather4D16Bug()))9318 NumVDataDwords = (DMaskLanes + 1) / 2;9319 else9320 NumVDataDwords = DMaskLanes;9321 9322 AdjustRetType = true;9323 }9324 }9325 9326 unsigned VAddrEnd = ArgOffset + Intr->VAddrEnd;9327 SmallVector<SDValue, 4> VAddrs;9328 9329 // Check for 16 bit addresses or derivatives and pack if true.9330 MVT VAddrVT =9331 Op.getOperand(ArgOffset + Intr->GradientStart).getSimpleValueType();9332 MVT VAddrScalarVT = VAddrVT.getScalarType();9333 MVT GradPackVectorVT = VAddrScalarVT == MVT::f16 ? MVT::v2f16 : MVT::v2i16;9334 IsG16 = VAddrScalarVT == MVT::f16 || VAddrScalarVT == MVT::i16;9335 9336 VAddrVT = Op.getOperand(ArgOffset + Intr->CoordStart).getSimpleValueType();9337 VAddrScalarVT = VAddrVT.getScalarType();9338 MVT AddrPackVectorVT = VAddrScalarVT == MVT::f16 ? MVT::v2f16 : MVT::v2i16;9339 IsA16 = VAddrScalarVT == MVT::f16 || VAddrScalarVT == MVT::i16;9340 9341 // Push back extra arguments.9342 for (unsigned I = Intr->VAddrStart; I < Intr->GradientStart; I++) {9343 if (IsA16 && (Op.getOperand(ArgOffset + I).getValueType() == MVT::f16)) {9344 assert(I == Intr->BiasIndex && "Got unexpected 16-bit extra argument");9345 // Special handling of bias when A16 is on. Bias is of type half but9346 // occupies full 32-bit.9347 SDValue Bias = DAG.getBuildVector(9348 MVT::v2f16, DL,9349 {Op.getOperand(ArgOffset + I), DAG.getPOISON(MVT::f16)});9350 VAddrs.push_back(Bias);9351 } else {9352 assert((!IsA16 || Intr->NumBiasArgs == 0 || I != Intr->BiasIndex) &&9353 "Bias needs to be converted to 16 bit in A16 mode");9354 VAddrs.push_back(Op.getOperand(ArgOffset + I));9355 }9356 }9357 9358 if (BaseOpcode->Gradients && !ST->hasG16() && (IsA16 != IsG16)) {9359 // 16 bit gradients are supported, but are tied to the A16 control9360 // so both gradients and addresses must be 16 bit9361 LLVM_DEBUG(9362 dbgs() << "Failed to lower image intrinsic: 16 bit addresses "9363 "require 16 bit args for both gradients and addresses");9364 return Op;9365 }9366 9367 if (IsA16) {9368 if (!ST->hasA16()) {9369 LLVM_DEBUG(dbgs() << "Failed to lower image intrinsic: Target does not "9370 "support 16 bit addresses\n");9371 return Op;9372 }9373 }9374 9375 // We've dealt with incorrect input so we know that if IsA16, IsG169376 // are set then we have to compress/pack operands (either address,9377 // gradient or both)9378 // In the case where a16 and gradients are tied (no G16 support) then we9379 // have already verified that both IsA16 and IsG16 are true9380 if (BaseOpcode->Gradients && IsG16 && ST->hasG16()) {9381 // Activate g169382 const AMDGPU::MIMGG16MappingInfo *G16MappingInfo =9383 AMDGPU::getMIMGG16MappingInfo(Intr->BaseOpcode);9384 IntrOpcode = G16MappingInfo->G16; // set new opcode to variant with _g169385 }9386 9387 // Add gradients (packed or unpacked)9388 if (IsG16) {9389 // Pack the gradients9390 // const int PackEndIdx = IsA16 ? VAddrEnd : (ArgOffset + Intr->CoordStart);9391 packImage16bitOpsToDwords(DAG, Op, GradPackVectorVT, VAddrs,9392 ArgOffset + Intr->GradientStart,9393 ArgOffset + Intr->CoordStart, Intr->NumGradients);9394 } else {9395 for (unsigned I = ArgOffset + Intr->GradientStart;9396 I < ArgOffset + Intr->CoordStart; I++)9397 VAddrs.push_back(Op.getOperand(I));9398 }9399 9400 // Add addresses (packed or unpacked)9401 if (IsA16) {9402 packImage16bitOpsToDwords(DAG, Op, AddrPackVectorVT, VAddrs,9403 ArgOffset + Intr->CoordStart, VAddrEnd,9404 0 /* No gradients */);9405 } else {9406 // Add uncompressed address9407 for (unsigned I = ArgOffset + Intr->CoordStart; I < VAddrEnd; I++)9408 VAddrs.push_back(Op.getOperand(I));9409 }9410 9411 // If the register allocator cannot place the address registers contiguously9412 // without introducing moves, then using the non-sequential address encoding9413 // is always preferable, since it saves VALU instructions and is usually a9414 // wash in terms of code size or even better.9415 //9416 // However, we currently have no way of hinting to the register allocator that9417 // MIMG addresses should be placed contiguously when it is possible to do so,9418 // so force non-NSA for the common 2-address case as a heuristic.9419 //9420 // SIShrinkInstructions will convert NSA encodings to non-NSA after register9421 // allocation when possible.9422 //9423 // Partial NSA is allowed on GFX11+ where the final register is a contiguous9424 // set of the remaining addresses.9425 const unsigned NSAMaxSize = ST->getNSAMaxSize(BaseOpcode->Sampler);9426 const bool HasPartialNSAEncoding = ST->hasPartialNSAEncoding();9427 const bool UseNSA = ST->hasNSAEncoding() &&9428 VAddrs.size() >= ST->getNSAThreshold(MF) &&9429 (VAddrs.size() <= NSAMaxSize || HasPartialNSAEncoding);9430 const bool UsePartialNSA =9431 UseNSA && HasPartialNSAEncoding && VAddrs.size() > NSAMaxSize;9432 9433 SDValue VAddr;9434 if (UsePartialNSA) {9435 VAddr = getBuildDwordsVector(DAG, DL,9436 ArrayRef(VAddrs).drop_front(NSAMaxSize - 1));9437 } else if (!UseNSA) {9438 VAddr = getBuildDwordsVector(DAG, DL, VAddrs);9439 }9440 9441 SDValue True = DAG.getTargetConstant(1, DL, MVT::i1);9442 SDValue False = DAG.getTargetConstant(0, DL, MVT::i1);9443 SDValue Unorm;9444 if (!BaseOpcode->Sampler) {9445 Unorm = True;9446 } else {9447 uint64_t UnormConst =9448 Op.getConstantOperandVal(ArgOffset + Intr->UnormIndex);9449 9450 Unorm = UnormConst ? True : False;9451 }9452 9453 SDValue TFE;9454 SDValue LWE;9455 SDValue TexFail = Op.getOperand(ArgOffset + Intr->TexFailCtrlIndex);9456 bool IsTexFail = false;9457 if (!parseTexFail(TexFail, DAG, &TFE, &LWE, IsTexFail))9458 return Op;9459 9460 if (IsTexFail) {9461 if (!DMaskLanes) {9462 // Expecting to get an error flag since TFC is on - and dmask is 09463 // Force dmask to be at least 1 otherwise the instruction will fail9464 DMask = 0x1;9465 DMaskLanes = 1;9466 NumVDataDwords = 1;9467 }9468 NumVDataDwords += 1;9469 AdjustRetType = true;9470 }9471 9472 // Has something earlier tagged that the return type needs adjusting9473 // This happens if the instruction is a load or has set TexFailCtrl flags9474 if (AdjustRetType) {9475 // NumVDataDwords reflects the true number of dwords required in the return9476 // type9477 if (DMaskLanes == 0 && !BaseOpcode->Store) {9478 // This is a no-op load. This can be eliminated9479 SDValue Undef = DAG.getPOISON(Op.getValueType());9480 if (isa<MemSDNode>(Op))9481 return DAG.getMergeValues({Undef, Op.getOperand(0)}, DL);9482 return Undef;9483 }9484 9485 EVT NewVT = NumVDataDwords > 1 ? EVT::getVectorVT(*DAG.getContext(),9486 MVT::i32, NumVDataDwords)9487 : MVT::i32;9488 9489 ResultTypes[0] = NewVT;9490 if (ResultTypes.size() == 3) {9491 // Original result was aggregate type used for TexFailCtrl results9492 // The actual instruction returns as a vector type which has now been9493 // created. Remove the aggregate result.9494 ResultTypes.erase(&ResultTypes[1]);9495 }9496 }9497 9498 unsigned CPol = Op.getConstantOperandVal(ArgOffset + Intr->CachePolicyIndex);9499 // Keep GLC only when the atomic's result is actually used.9500 if (BaseOpcode->Atomic && !BaseOpcode->NoReturn)9501 CPol |= AMDGPU::CPol::GLC;9502 if (CPol & ~((IsGFX12Plus ? AMDGPU::CPol::ALL : AMDGPU::CPol::ALL_pregfx12) |9503 AMDGPU::CPol::VOLATILE))9504 return Op;9505 9506 SmallVector<SDValue, 26> Ops;9507 if (BaseOpcode->Store || BaseOpcode->Atomic)9508 Ops.push_back(VData); // vdata9509 if (UsePartialNSA) {9510 append_range(Ops, ArrayRef(VAddrs).take_front(NSAMaxSize - 1));9511 Ops.push_back(VAddr);9512 } else if (UseNSA)9513 append_range(Ops, VAddrs);9514 else9515 Ops.push_back(VAddr);9516 SDValue Rsrc = Op.getOperand(ArgOffset + Intr->RsrcIndex);9517 EVT RsrcVT = Rsrc.getValueType();9518 if (RsrcVT != MVT::v4i32 && RsrcVT != MVT::v8i32)9519 return Op;9520 Ops.push_back(Rsrc);9521 if (BaseOpcode->Sampler) {9522 SDValue Samp = Op.getOperand(ArgOffset + Intr->SampIndex);9523 if (Samp.getValueType() != MVT::v4i32)9524 return Op;9525 Ops.push_back(Samp);9526 }9527 Ops.push_back(DAG.getTargetConstant(DMask, DL, MVT::i32));9528 if (IsGFX10Plus)9529 Ops.push_back(DAG.getTargetConstant(DimInfo->Encoding, DL, MVT::i32));9530 if (!IsGFX12Plus || BaseOpcode->Sampler || BaseOpcode->MSAA)9531 Ops.push_back(Unorm);9532 Ops.push_back(DAG.getTargetConstant(CPol, DL, MVT::i32));9533 Ops.push_back(IsA16 && // r128, a16 for gfx99534 ST->hasFeature(AMDGPU::FeatureR128A16)9535 ? True9536 : False);9537 if (IsGFX10Plus)9538 Ops.push_back(IsA16 ? True : False);9539 9540 if (!Subtarget->hasGFX90AInsts())9541 Ops.push_back(TFE); // tfe9542 else if (TFE->getAsZExtVal()) {9543 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(9544 DAG.getMachineFunction().getFunction(),9545 "TFE is not supported on this GPU", DL.getDebugLoc()));9546 }9547 9548 if (!IsGFX12Plus || BaseOpcode->Sampler || BaseOpcode->MSAA)9549 Ops.push_back(LWE); // lwe9550 if (!IsGFX10Plus)9551 Ops.push_back(DimInfo->DA ? True : False);9552 if (BaseOpcode->HasD16)9553 Ops.push_back(IsD16 ? True : False);9554 if (isa<MemSDNode>(Op))9555 Ops.push_back(Op.getOperand(0)); // chain9556 9557 int NumVAddrDwords =9558 UseNSA ? VAddrs.size() : VAddr.getValueType().getSizeInBits() / 32;9559 int Opcode = -1;9560 9561 if (IsGFX12Plus) {9562 Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx12,9563 NumVDataDwords, NumVAddrDwords);9564 } else if (IsGFX11Plus) {9565 Opcode = AMDGPU::getMIMGOpcode(IntrOpcode,9566 UseNSA ? AMDGPU::MIMGEncGfx11NSA9567 : AMDGPU::MIMGEncGfx11Default,9568 NumVDataDwords, NumVAddrDwords);9569 } else if (IsGFX10Plus) {9570 Opcode = AMDGPU::getMIMGOpcode(IntrOpcode,9571 UseNSA ? AMDGPU::MIMGEncGfx10NSA9572 : AMDGPU::MIMGEncGfx10Default,9573 NumVDataDwords, NumVAddrDwords);9574 } else {9575 if (Subtarget->hasGFX90AInsts()) {9576 Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx90a,9577 NumVDataDwords, NumVAddrDwords);9578 if (Opcode == -1) {9579 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(9580 DAG.getMachineFunction().getFunction(),9581 "requested image instruction is not supported on this GPU",9582 DL.getDebugLoc()));9583 9584 unsigned Idx = 0;9585 SmallVector<SDValue, 3> RetValues(OrigResultTypes.size());9586 for (EVT VT : OrigResultTypes) {9587 if (VT == MVT::Other)9588 RetValues[Idx++] = Op.getOperand(0); // Chain9589 else9590 RetValues[Idx++] = DAG.getPOISON(VT);9591 }9592 9593 return DAG.getMergeValues(RetValues, DL);9594 }9595 }9596 if (Opcode == -1 &&9597 Subtarget->getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS)9598 Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx8,9599 NumVDataDwords, NumVAddrDwords);9600 if (Opcode == -1)9601 Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx6,9602 NumVDataDwords, NumVAddrDwords);9603 }9604 if (Opcode == -1)9605 return Op;9606 9607 MachineSDNode *NewNode = DAG.getMachineNode(Opcode, DL, ResultTypes, Ops);9608 if (auto *MemOp = dyn_cast<MemSDNode>(Op)) {9609 MachineMemOperand *MemRef = MemOp->getMemOperand();9610 DAG.setNodeMemRefs(NewNode, {MemRef});9611 }9612 9613 if (BaseOpcode->NoReturn) {9614 if (BaseOpcode->Atomic)9615 return DAG.getMergeValues(9616 {DAG.getPOISON(OrigResultTypes[0]), SDValue(NewNode, 0)}, DL);9617 9618 return SDValue(NewNode, 0);9619 }9620 9621 if (BaseOpcode->AtomicX2) {9622 SmallVector<SDValue, 1> Elt;9623 DAG.ExtractVectorElements(SDValue(NewNode, 0), Elt, 0, 1);9624 return DAG.getMergeValues({Elt[0], SDValue(NewNode, 1)}, DL);9625 }9626 9627 return constructRetValue(DAG, NewNode, OrigResultTypes, IsTexFail,9628 Subtarget->hasUnpackedD16VMem(), IsD16, DMaskLanes,9629 NumVDataDwords, IsAtomicPacked16Bit, DL);9630}9631 9632SDValue SITargetLowering::lowerSBuffer(EVT VT, SDLoc DL, SDValue Rsrc,9633 SDValue Offset, SDValue CachePolicy,9634 SelectionDAG &DAG) const {9635 MachineFunction &MF = DAG.getMachineFunction();9636 9637 const DataLayout &DataLayout = DAG.getDataLayout();9638 Align Alignment =9639 DataLayout.getABITypeAlign(VT.getTypeForEVT(*DAG.getContext()));9640 9641 MachineMemOperand *MMO = MF.getMachineMemOperand(9642 MachinePointerInfo(),9643 MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |9644 MachineMemOperand::MOInvariant,9645 VT.getStoreSize(), Alignment);9646 9647 if (!Offset->isDivergent()) {9648 SDValue Ops[] = {Rsrc, Offset, CachePolicy};9649 9650 // Lower llvm.amdgcn.s.buffer.load.{i16, u16} intrinsics. Initially, the9651 // s_buffer_load_u16 instruction is emitted for both signed and unsigned9652 // loads. Later, DAG combiner tries to combine s_buffer_load_u16 with sext9653 // and generates s_buffer_load_i16 (performSignExtendInRegCombine).9654 if (VT == MVT::i16 && Subtarget->hasScalarSubwordLoads()) {9655 SDValue BufferLoad =9656 DAG.getMemIntrinsicNode(AMDGPUISD::SBUFFER_LOAD_USHORT, DL,9657 DAG.getVTList(MVT::i32), Ops, VT, MMO);9658 return DAG.getNode(ISD::TRUNCATE, DL, VT, BufferLoad);9659 }9660 9661 // Widen vec3 load to vec4.9662 if (VT.isVector() && VT.getVectorNumElements() == 3 &&9663 !Subtarget->hasScalarDwordx3Loads()) {9664 EVT WidenedVT =9665 EVT::getVectorVT(*DAG.getContext(), VT.getVectorElementType(), 4);9666 auto WidenedOp = DAG.getMemIntrinsicNode(9667 AMDGPUISD::SBUFFER_LOAD, DL, DAG.getVTList(WidenedVT), Ops, WidenedVT,9668 MF.getMachineMemOperand(MMO, 0, WidenedVT.getStoreSize()));9669 auto Subvector = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, VT, WidenedOp,9670 DAG.getVectorIdxConstant(0, DL));9671 return Subvector;9672 }9673 9674 return DAG.getMemIntrinsicNode(AMDGPUISD::SBUFFER_LOAD, DL,9675 DAG.getVTList(VT), Ops, VT, MMO);9676 }9677 9678 // We have a divergent offset. Emit a MUBUF buffer load instead. We can9679 // assume that the buffer is unswizzled.9680 SDValue Ops[] = {9681 DAG.getEntryNode(), // Chain9682 Rsrc, // rsrc9683 DAG.getConstant(0, DL, MVT::i32), // vindex9684 {}, // voffset9685 {}, // soffset9686 {}, // offset9687 CachePolicy, // cachepolicy9688 DAG.getTargetConstant(0, DL, MVT::i1), // idxen9689 };9690 if (VT == MVT::i16 && Subtarget->hasScalarSubwordLoads()) {9691 setBufferOffsets(Offset, DAG, &Ops[3], Align(4));9692 return handleByteShortBufferLoads(DAG, VT, DL, Ops, MMO);9693 }9694 9695 SmallVector<SDValue, 4> Loads;9696 unsigned NumLoads = 1;9697 MVT LoadVT = VT.getSimpleVT();9698 unsigned NumElts = LoadVT.isVector() ? LoadVT.getVectorNumElements() : 1;9699 assert((LoadVT.getScalarType() == MVT::i32 ||9700 LoadVT.getScalarType() == MVT::f32));9701 9702 if (NumElts == 8 || NumElts == 16) {9703 NumLoads = NumElts / 4;9704 LoadVT = MVT::getVectorVT(LoadVT.getScalarType(), 4);9705 }9706 9707 SDVTList VTList = DAG.getVTList({LoadVT, MVT::Other});9708 9709 // Use the alignment to ensure that the required offsets will fit into the9710 // immediate offsets.9711 setBufferOffsets(Offset, DAG, &Ops[3],9712 NumLoads > 1 ? Align(16 * NumLoads) : Align(4));9713 9714 uint64_t InstOffset = Ops[5]->getAsZExtVal();9715 for (unsigned i = 0; i < NumLoads; ++i) {9716 Ops[5] = DAG.getTargetConstant(InstOffset + 16 * i, DL, MVT::i32);9717 Loads.push_back(getMemIntrinsicNode(AMDGPUISD::BUFFER_LOAD, DL, VTList, Ops,9718 LoadVT, MMO, DAG));9719 }9720 9721 if (NumElts == 8 || NumElts == 16)9722 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Loads);9723 9724 return Loads[0];9725}9726 9727SDValue SITargetLowering::lowerWaveID(SelectionDAG &DAG, SDValue Op) const {9728 // With architected SGPRs, waveIDinGroup is in TTMP8[29:25].9729 if (!Subtarget->hasArchitectedSGPRs())9730 return {};9731 SDLoc SL(Op);9732 MVT VT = MVT::i32;9733 SDValue TTMP8 = DAG.getCopyFromReg(DAG.getEntryNode(), SL, AMDGPU::TTMP8, VT);9734 return DAG.getNode(AMDGPUISD::BFE_U32, SL, VT, TTMP8,9735 DAG.getConstant(25, SL, VT), DAG.getConstant(5, SL, VT));9736}9737 9738SDValue SITargetLowering::lowerConstHwRegRead(SelectionDAG &DAG, SDValue Op,9739 AMDGPU::Hwreg::Id HwReg,9740 unsigned LowBit,9741 unsigned Width) const {9742 SDLoc SL(Op);9743 using namespace AMDGPU::Hwreg;9744 return {DAG.getMachineNode(9745 AMDGPU::S_GETREG_B32_const, SL, MVT::i32,9746 DAG.getTargetConstant(HwregEncoding::encode(HwReg, LowBit, Width),9747 SL, MVT::i32)),9748 0};9749}9750 9751SDValue SITargetLowering::lowerWorkitemID(SelectionDAG &DAG, SDValue Op,9752 unsigned Dim,9753 const ArgDescriptor &Arg) const {9754 SDLoc SL(Op);9755 MachineFunction &MF = DAG.getMachineFunction();9756 unsigned MaxID = Subtarget->getMaxWorkitemID(MF.getFunction(), Dim);9757 if (MaxID == 0)9758 return DAG.getConstant(0, SL, MVT::i32);9759 9760 // It's undefined behavior if a function marked with the amdgpu-no-*9761 // attributes uses the corresponding intrinsic.9762 if (!Arg)9763 return DAG.getPOISON(Op->getValueType(0));9764 9765 SDValue Val = loadInputValue(DAG, &AMDGPU::VGPR_32RegClass, MVT::i32,9766 SDLoc(DAG.getEntryNode()), Arg);9767 9768 // Don't bother inserting AssertZext for packed IDs since we're emitting the9769 // masking operations anyway.9770 //9771 // TODO: We could assert the top bit is 0 for the source copy.9772 if (Arg.isMasked())9773 return Val;9774 9775 // Preserve the known bits after expansion to a copy.9776 EVT SmallVT = EVT::getIntegerVT(*DAG.getContext(), llvm::bit_width(MaxID));9777 return DAG.getNode(ISD::AssertZext, SL, MVT::i32, Val,9778 DAG.getValueType(SmallVT));9779}9780 9781SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,9782 SelectionDAG &DAG) const {9783 MachineFunction &MF = DAG.getMachineFunction();9784 auto *MFI = MF.getInfo<SIMachineFunctionInfo>();9785 9786 EVT VT = Op.getValueType();9787 SDLoc DL(Op);9788 unsigned IntrinsicID = Op.getConstantOperandVal(0);9789 9790 // TODO: Should this propagate fast-math-flags?9791 9792 switch (IntrinsicID) {9793 case Intrinsic::amdgcn_implicit_buffer_ptr: {9794 if (getSubtarget()->isAmdHsaOrMesa(MF.getFunction()))9795 return emitNonHSAIntrinsicError(DAG, DL, VT);9796 return getPreloadedValue(DAG, *MFI, VT,9797 AMDGPUFunctionArgInfo::IMPLICIT_BUFFER_PTR);9798 }9799 case Intrinsic::amdgcn_dispatch_ptr:9800 case Intrinsic::amdgcn_queue_ptr: {9801 if (!Subtarget->isAmdHsaOrMesa(MF.getFunction())) {9802 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(9803 MF.getFunction(), "unsupported hsa intrinsic without hsa target",9804 DL.getDebugLoc()));9805 return DAG.getPOISON(VT);9806 }9807 9808 auto RegID = IntrinsicID == Intrinsic::amdgcn_dispatch_ptr9809 ? AMDGPUFunctionArgInfo::DISPATCH_PTR9810 : AMDGPUFunctionArgInfo::QUEUE_PTR;9811 return getPreloadedValue(DAG, *MFI, VT, RegID);9812 }9813 case Intrinsic::amdgcn_implicitarg_ptr: {9814 if (MFI->isEntryFunction())9815 return getImplicitArgPtr(DAG, DL);9816 return getPreloadedValue(DAG, *MFI, VT,9817 AMDGPUFunctionArgInfo::IMPLICIT_ARG_PTR);9818 }9819 case Intrinsic::amdgcn_kernarg_segment_ptr: {9820 if (!AMDGPU::isKernel(MF.getFunction())) {9821 // This only makes sense to call in a kernel, so just lower to null.9822 return DAG.getConstant(0, DL, VT);9823 }9824 9825 return getPreloadedValue(DAG, *MFI, VT,9826 AMDGPUFunctionArgInfo::KERNARG_SEGMENT_PTR);9827 }9828 case Intrinsic::amdgcn_dispatch_id: {9829 return getPreloadedValue(DAG, *MFI, VT, AMDGPUFunctionArgInfo::DISPATCH_ID);9830 }9831 case Intrinsic::amdgcn_rcp:9832 return DAG.getNode(AMDGPUISD::RCP, DL, VT, Op.getOperand(1));9833 case Intrinsic::amdgcn_rsq:9834 return DAG.getNode(AMDGPUISD::RSQ, DL, VT, Op.getOperand(1));9835 case Intrinsic::amdgcn_rsq_legacy:9836 if (Subtarget->getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS)9837 return emitRemovedIntrinsicError(DAG, DL, VT);9838 return SDValue();9839 case Intrinsic::amdgcn_rcp_legacy:9840 if (Subtarget->getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS)9841 return emitRemovedIntrinsicError(DAG, DL, VT);9842 return DAG.getNode(AMDGPUISD::RCP_LEGACY, DL, VT, Op.getOperand(1));9843 case Intrinsic::amdgcn_rsq_clamp: {9844 if (Subtarget->getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS)9845 return DAG.getNode(AMDGPUISD::RSQ_CLAMP, DL, VT, Op.getOperand(1));9846 9847 Type *Type = VT.getTypeForEVT(*DAG.getContext());9848 APFloat Max = APFloat::getLargest(Type->getFltSemantics());9849 APFloat Min = APFloat::getLargest(Type->getFltSemantics(), true);9850 9851 SDValue Rsq = DAG.getNode(AMDGPUISD::RSQ, DL, VT, Op.getOperand(1));9852 SDValue Tmp =9853 DAG.getNode(ISD::FMINNUM, DL, VT, Rsq, DAG.getConstantFP(Max, DL, VT));9854 return DAG.getNode(ISD::FMAXNUM, DL, VT, Tmp,9855 DAG.getConstantFP(Min, DL, VT));9856 }9857 case Intrinsic::r600_read_ngroups_x:9858 if (Subtarget->isAmdHsaOS())9859 return emitNonHSAIntrinsicError(DAG, DL, VT);9860 9861 return lowerKernargMemParameter(DAG, VT, VT, DL, DAG.getEntryNode(),9862 SI::KernelInputOffsets::NGROUPS_X, Align(4),9863 false);9864 case Intrinsic::r600_read_ngroups_y:9865 if (Subtarget->isAmdHsaOS())9866 return emitNonHSAIntrinsicError(DAG, DL, VT);9867 9868 return lowerKernargMemParameter(DAG, VT, VT, DL, DAG.getEntryNode(),9869 SI::KernelInputOffsets::NGROUPS_Y, Align(4),9870 false);9871 case Intrinsic::r600_read_ngroups_z:9872 if (Subtarget->isAmdHsaOS())9873 return emitNonHSAIntrinsicError(DAG, DL, VT);9874 9875 return lowerKernargMemParameter(DAG, VT, VT, DL, DAG.getEntryNode(),9876 SI::KernelInputOffsets::NGROUPS_Z, Align(4),9877 false);9878 case Intrinsic::r600_read_local_size_x:9879 if (Subtarget->isAmdHsaOS())9880 return emitNonHSAIntrinsicError(DAG, DL, VT);9881 9882 return lowerImplicitZextParam(DAG, Op, MVT::i16,9883 SI::KernelInputOffsets::LOCAL_SIZE_X);9884 case Intrinsic::r600_read_local_size_y:9885 if (Subtarget->isAmdHsaOS())9886 return emitNonHSAIntrinsicError(DAG, DL, VT);9887 9888 return lowerImplicitZextParam(DAG, Op, MVT::i16,9889 SI::KernelInputOffsets::LOCAL_SIZE_Y);9890 case Intrinsic::r600_read_local_size_z:9891 if (Subtarget->isAmdHsaOS())9892 return emitNonHSAIntrinsicError(DAG, DL, VT);9893 9894 return lowerImplicitZextParam(DAG, Op, MVT::i16,9895 SI::KernelInputOffsets::LOCAL_SIZE_Z);9896 case Intrinsic::amdgcn_workgroup_id_x:9897 return lowerWorkGroupId(DAG, *MFI, VT,9898 AMDGPUFunctionArgInfo::WORKGROUP_ID_X,9899 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_ID_X,9900 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_ID_X);9901 case Intrinsic::amdgcn_workgroup_id_y:9902 return lowerWorkGroupId(DAG, *MFI, VT,9903 AMDGPUFunctionArgInfo::WORKGROUP_ID_Y,9904 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_ID_Y,9905 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_ID_Y);9906 case Intrinsic::amdgcn_workgroup_id_z:9907 return lowerWorkGroupId(DAG, *MFI, VT,9908 AMDGPUFunctionArgInfo::WORKGROUP_ID_Z,9909 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_ID_Z,9910 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_ID_Z);9911 case Intrinsic::amdgcn_cluster_id_x:9912 return Subtarget->hasClusters()9913 ? getPreloadedValue(DAG, *MFI, VT,9914 AMDGPUFunctionArgInfo::WORKGROUP_ID_X)9915 : DAG.getPOISON(VT);9916 case Intrinsic::amdgcn_cluster_id_y:9917 return Subtarget->hasClusters()9918 ? getPreloadedValue(DAG, *MFI, VT,9919 AMDGPUFunctionArgInfo::WORKGROUP_ID_Y)9920 : DAG.getPOISON(VT);9921 case Intrinsic::amdgcn_cluster_id_z:9922 return Subtarget->hasClusters()9923 ? getPreloadedValue(DAG, *MFI, VT,9924 AMDGPUFunctionArgInfo::WORKGROUP_ID_Z)9925 : DAG.getPOISON(VT);9926 case Intrinsic::amdgcn_cluster_workgroup_id_x:9927 return Subtarget->hasClusters()9928 ? getPreloadedValue(9929 DAG, *MFI, VT,9930 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_ID_X)9931 : DAG.getPOISON(VT);9932 case Intrinsic::amdgcn_cluster_workgroup_id_y:9933 return Subtarget->hasClusters()9934 ? getPreloadedValue(9935 DAG, *MFI, VT,9936 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_ID_Y)9937 : DAG.getPOISON(VT);9938 case Intrinsic::amdgcn_cluster_workgroup_id_z:9939 return Subtarget->hasClusters()9940 ? getPreloadedValue(9941 DAG, *MFI, VT,9942 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_ID_Z)9943 : DAG.getPOISON(VT);9944 case Intrinsic::amdgcn_cluster_workgroup_flat_id:9945 return Subtarget->hasClusters()9946 ? lowerConstHwRegRead(DAG, Op, AMDGPU::Hwreg::ID_IB_STS2, 21, 4)9947 : SDValue();9948 case Intrinsic::amdgcn_cluster_workgroup_max_id_x:9949 return Subtarget->hasClusters()9950 ? getPreloadedValue(9951 DAG, *MFI, VT,9952 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_ID_X)9953 : DAG.getPOISON(VT);9954 case Intrinsic::amdgcn_cluster_workgroup_max_id_y:9955 return Subtarget->hasClusters()9956 ? getPreloadedValue(9957 DAG, *MFI, VT,9958 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_ID_Y)9959 : DAG.getPOISON(VT);9960 case Intrinsic::amdgcn_cluster_workgroup_max_id_z:9961 return Subtarget->hasClusters()9962 ? getPreloadedValue(9963 DAG, *MFI, VT,9964 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_ID_Z)9965 : DAG.getPOISON(VT);9966 case Intrinsic::amdgcn_cluster_workgroup_max_flat_id:9967 return Subtarget->hasClusters()9968 ? getPreloadedValue(9969 DAG, *MFI, VT,9970 AMDGPUFunctionArgInfo::CLUSTER_WORKGROUP_MAX_FLAT_ID)9971 : DAG.getPOISON(VT);9972 case Intrinsic::amdgcn_wave_id:9973 return lowerWaveID(DAG, Op);9974 case Intrinsic::amdgcn_lds_kernel_id: {9975 if (MFI->isEntryFunction())9976 return getLDSKernelId(DAG, DL);9977 return getPreloadedValue(DAG, *MFI, VT,9978 AMDGPUFunctionArgInfo::LDS_KERNEL_ID);9979 }9980 case Intrinsic::amdgcn_workitem_id_x:9981 return lowerWorkitemID(DAG, Op, 0, MFI->getArgInfo().WorkItemIDX);9982 case Intrinsic::amdgcn_workitem_id_y:9983 return lowerWorkitemID(DAG, Op, 1, MFI->getArgInfo().WorkItemIDY);9984 case Intrinsic::amdgcn_workitem_id_z:9985 return lowerWorkitemID(DAG, Op, 2, MFI->getArgInfo().WorkItemIDZ);9986 case Intrinsic::amdgcn_wavefrontsize:9987 return DAG.getConstant(MF.getSubtarget<GCNSubtarget>().getWavefrontSize(),9988 SDLoc(Op), MVT::i32);9989 case Intrinsic::amdgcn_s_buffer_load: {9990 unsigned CPol = Op.getConstantOperandVal(3);9991 // s_buffer_load, because of how it's optimized, can't be volatile9992 // so reject ones with the volatile bit set.9993 if (CPol & ~((Subtarget->getGeneration() >= AMDGPUSubtarget::GFX12)9994 ? AMDGPU::CPol::ALL9995 : AMDGPU::CPol::ALL_pregfx12))9996 return Op;9997 return lowerSBuffer(VT, DL, Op.getOperand(1), Op.getOperand(2),9998 Op.getOperand(3), DAG);9999 }10000 case Intrinsic::amdgcn_fdiv_fast:10001 return lowerFDIV_FAST(Op, DAG);10002 case Intrinsic::amdgcn_sin:10003 return DAG.getNode(AMDGPUISD::SIN_HW, DL, VT, Op.getOperand(1));10004 10005 case Intrinsic::amdgcn_cos:10006 return DAG.getNode(AMDGPUISD::COS_HW, DL, VT, Op.getOperand(1));10007 10008 case Intrinsic::amdgcn_mul_u24:10009 return DAG.getNode(AMDGPUISD::MUL_U24, DL, VT, Op.getOperand(1),10010 Op.getOperand(2));10011 case Intrinsic::amdgcn_mul_i24:10012 return DAG.getNode(AMDGPUISD::MUL_I24, DL, VT, Op.getOperand(1),10013 Op.getOperand(2));10014 10015 case Intrinsic::amdgcn_log_clamp: {10016 if (Subtarget->getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS)10017 return SDValue();10018 10019 return emitRemovedIntrinsicError(DAG, DL, VT);10020 }10021 case Intrinsic::amdgcn_fract:10022 return DAG.getNode(AMDGPUISD::FRACT, DL, VT, Op.getOperand(1));10023 10024 case Intrinsic::amdgcn_class:10025 return DAG.getNode(AMDGPUISD::FP_CLASS, DL, VT, Op.getOperand(1),10026 Op.getOperand(2));10027 case Intrinsic::amdgcn_div_fmas:10028 return DAG.getNode(AMDGPUISD::DIV_FMAS, DL, VT, Op.getOperand(1),10029 Op.getOperand(2), Op.getOperand(3), Op.getOperand(4));10030 10031 case Intrinsic::amdgcn_div_fixup:10032 return DAG.getNode(AMDGPUISD::DIV_FIXUP, DL, VT, Op.getOperand(1),10033 Op.getOperand(2), Op.getOperand(3));10034 10035 case Intrinsic::amdgcn_div_scale: {10036 const ConstantSDNode *Param = cast<ConstantSDNode>(Op.getOperand(3));10037 10038 // Translate to the operands expected by the machine instruction. The10039 // first parameter must be the same as the first instruction.10040 SDValue Numerator = Op.getOperand(1);10041 SDValue Denominator = Op.getOperand(2);10042 10043 // Note this order is opposite of the machine instruction's operations,10044 // which is s0.f = Quotient, s1.f = Denominator, s2.f = Numerator. The10045 // intrinsic has the numerator as the first operand to match a normal10046 // division operation.10047 10048 SDValue Src0 = Param->isAllOnes() ? Numerator : Denominator;10049 10050 return DAG.getNode(AMDGPUISD::DIV_SCALE, DL, Op->getVTList(), Src0,10051 Denominator, Numerator);10052 }10053 case Intrinsic::amdgcn_icmp: {10054 // There is a Pat that handles this variant, so return it as-is.10055 if (Op.getOperand(1).getValueType() == MVT::i1 &&10056 Op.getConstantOperandVal(2) == 0 &&10057 Op.getConstantOperandVal(3) == ICmpInst::Predicate::ICMP_NE)10058 return Op;10059 return lowerICMPIntrinsic(*this, Op.getNode(), DAG);10060 }10061 case Intrinsic::amdgcn_fcmp: {10062 return lowerFCMPIntrinsic(*this, Op.getNode(), DAG);10063 }10064 case Intrinsic::amdgcn_ballot:10065 return lowerBALLOTIntrinsic(*this, Op.getNode(), DAG);10066 case Intrinsic::amdgcn_fmed3:10067 return DAG.getNode(AMDGPUISD::FMED3, DL, VT, Op.getOperand(1),10068 Op.getOperand(2), Op.getOperand(3));10069 case Intrinsic::amdgcn_fdot2:10070 return DAG.getNode(AMDGPUISD::FDOT2, DL, VT, Op.getOperand(1),10071 Op.getOperand(2), Op.getOperand(3), Op.getOperand(4));10072 case Intrinsic::amdgcn_fmul_legacy:10073 return DAG.getNode(AMDGPUISD::FMUL_LEGACY, DL, VT, Op.getOperand(1),10074 Op.getOperand(2));10075 case Intrinsic::amdgcn_sffbh:10076 return DAG.getNode(AMDGPUISD::FFBH_I32, DL, VT, Op.getOperand(1));10077 case Intrinsic::amdgcn_sbfe:10078 return DAG.getNode(AMDGPUISD::BFE_I32, DL, VT, Op.getOperand(1),10079 Op.getOperand(2), Op.getOperand(3));10080 case Intrinsic::amdgcn_ubfe:10081 return DAG.getNode(AMDGPUISD::BFE_U32, DL, VT, Op.getOperand(1),10082 Op.getOperand(2), Op.getOperand(3));10083 case Intrinsic::amdgcn_cvt_pkrtz:10084 case Intrinsic::amdgcn_cvt_pknorm_i16:10085 case Intrinsic::amdgcn_cvt_pknorm_u16:10086 case Intrinsic::amdgcn_cvt_pk_i16:10087 case Intrinsic::amdgcn_cvt_pk_u16: {10088 // FIXME: Stop adding cast if v2f16/v2i16 are legal.10089 EVT VT = Op.getValueType();10090 unsigned Opcode;10091 10092 if (IntrinsicID == Intrinsic::amdgcn_cvt_pkrtz)10093 Opcode = AMDGPUISD::CVT_PKRTZ_F16_F32;10094 else if (IntrinsicID == Intrinsic::amdgcn_cvt_pknorm_i16)10095 Opcode = AMDGPUISD::CVT_PKNORM_I16_F32;10096 else if (IntrinsicID == Intrinsic::amdgcn_cvt_pknorm_u16)10097 Opcode = AMDGPUISD::CVT_PKNORM_U16_F32;10098 else if (IntrinsicID == Intrinsic::amdgcn_cvt_pk_i16)10099 Opcode = AMDGPUISD::CVT_PK_I16_I32;10100 else10101 Opcode = AMDGPUISD::CVT_PK_U16_U32;10102 10103 if (isTypeLegal(VT))10104 return DAG.getNode(Opcode, DL, VT, Op.getOperand(1), Op.getOperand(2));10105 10106 SDValue Node =10107 DAG.getNode(Opcode, DL, MVT::i32, Op.getOperand(1), Op.getOperand(2));10108 return DAG.getNode(ISD::BITCAST, DL, VT, Node);10109 }10110 case Intrinsic::amdgcn_fmad_ftz:10111 return DAG.getNode(AMDGPUISD::FMAD_FTZ, DL, VT, Op.getOperand(1),10112 Op.getOperand(2), Op.getOperand(3));10113 10114 case Intrinsic::amdgcn_if_break:10115 return SDValue(DAG.getMachineNode(AMDGPU::SI_IF_BREAK, DL, VT,10116 Op->getOperand(1), Op->getOperand(2)),10117 0);10118 10119 case Intrinsic::amdgcn_groupstaticsize: {10120 Triple::OSType OS = getTargetMachine().getTargetTriple().getOS();10121 if (OS == Triple::AMDHSA || OS == Triple::AMDPAL)10122 return Op;10123 10124 const Module *M = MF.getFunction().getParent();10125 const GlobalValue *GV =10126 Intrinsic::getDeclarationIfExists(M, Intrinsic::amdgcn_groupstaticsize);10127 SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, 0,10128 SIInstrInfo::MO_ABS32_LO);10129 return {DAG.getMachineNode(AMDGPU::S_MOV_B32, DL, MVT::i32, GA), 0};10130 }10131 case Intrinsic::amdgcn_is_shared:10132 case Intrinsic::amdgcn_is_private: {10133 SDLoc SL(Op);10134 SDValue SrcVec =10135 DAG.getNode(ISD::BITCAST, DL, MVT::v2i32, Op.getOperand(1));10136 SDValue SrcHi = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, SrcVec,10137 DAG.getConstant(1, SL, MVT::i32));10138 10139 unsigned AS = (IntrinsicID == Intrinsic::amdgcn_is_shared)10140 ? AMDGPUAS::LOCAL_ADDRESS10141 : AMDGPUAS::PRIVATE_ADDRESS;10142 if (AS == AMDGPUAS::PRIVATE_ADDRESS &&10143 Subtarget->hasGloballyAddressableScratch()) {10144 SDValue FlatScratchBaseHi(10145 DAG.getMachineNode(10146 AMDGPU::S_MOV_B32, DL, MVT::i32,10147 DAG.getRegister(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI, MVT::i32)),10148 0);10149 // Test bits 63..58 against the aperture address.10150 return DAG.getSetCC(10151 SL, MVT::i1,10152 DAG.getNode(ISD::XOR, SL, MVT::i32, SrcHi, FlatScratchBaseHi),10153 DAG.getConstant(1u << 26, SL, MVT::i32), ISD::SETULT);10154 }10155 10156 SDValue Aperture = getSegmentAperture(AS, SL, DAG);10157 return DAG.getSetCC(SL, MVT::i1, SrcHi, Aperture, ISD::SETEQ);10158 }10159 case Intrinsic::amdgcn_perm:10160 return DAG.getNode(AMDGPUISD::PERM, DL, MVT::i32, Op.getOperand(1),10161 Op.getOperand(2), Op.getOperand(3));10162 case Intrinsic::amdgcn_reloc_constant: {10163 Module *M = MF.getFunction().getParent();10164 const MDNode *Metadata = cast<MDNodeSDNode>(Op.getOperand(1))->getMD();10165 auto SymbolName = cast<MDString>(Metadata->getOperand(0))->getString();10166 auto *RelocSymbol = cast<GlobalVariable>(10167 M->getOrInsertGlobal(SymbolName, Type::getInt32Ty(M->getContext())));10168 SDValue GA = DAG.getTargetGlobalAddress(RelocSymbol, DL, MVT::i32, 0,10169 SIInstrInfo::MO_ABS32_LO);10170 return {DAG.getMachineNode(AMDGPU::S_MOV_B32, DL, MVT::i32, GA), 0};10171 }10172 case Intrinsic::amdgcn_swmmac_f16_16x16x32_f16:10173 case Intrinsic::amdgcn_swmmac_bf16_16x16x32_bf16:10174 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf16:10175 case Intrinsic::amdgcn_swmmac_f32_16x16x32_f16:10176 case Intrinsic::amdgcn_swmmac_f32_16x16x32_fp8_fp8:10177 case Intrinsic::amdgcn_swmmac_f32_16x16x32_fp8_bf8:10178 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf8_fp8:10179 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf8_bf8: {10180 if (Op.getOperand(4).getValueType() == MVT::i32)10181 return SDValue();10182 10183 SDLoc SL(Op);10184 auto IndexKeyi32 = DAG.getAnyExtOrTrunc(Op.getOperand(4), SL, MVT::i32);10185 return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, Op.getValueType(),10186 Op.getOperand(0), Op.getOperand(1), Op.getOperand(2),10187 Op.getOperand(3), IndexKeyi32);10188 }10189 case Intrinsic::amdgcn_swmmac_f32_16x16x128_fp8_fp8:10190 case Intrinsic::amdgcn_swmmac_f32_16x16x128_fp8_bf8:10191 case Intrinsic::amdgcn_swmmac_f32_16x16x128_bf8_fp8:10192 case Intrinsic::amdgcn_swmmac_f32_16x16x128_bf8_bf8:10193 case Intrinsic::amdgcn_swmmac_f16_16x16x128_fp8_fp8:10194 case Intrinsic::amdgcn_swmmac_f16_16x16x128_fp8_bf8:10195 case Intrinsic::amdgcn_swmmac_f16_16x16x128_bf8_fp8:10196 case Intrinsic::amdgcn_swmmac_f16_16x16x128_bf8_bf8: {10197 if (Op.getOperand(4).getValueType() == MVT::i64)10198 return SDValue();10199 10200 SDLoc SL(Op);10201 auto IndexKeyi64 = DAG.getAnyExtOrTrunc(Op.getOperand(4), SL, MVT::i64);10202 return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, Op.getValueType(),10203 {Op.getOperand(0), Op.getOperand(1), Op.getOperand(2),10204 Op.getOperand(3), IndexKeyi64, Op.getOperand(5),10205 Op.getOperand(6)});10206 }10207 case Intrinsic::amdgcn_swmmac_f16_16x16x64_f16:10208 case Intrinsic::amdgcn_swmmac_bf16_16x16x64_bf16:10209 case Intrinsic::amdgcn_swmmac_f32_16x16x64_bf16:10210 case Intrinsic::amdgcn_swmmac_bf16f32_16x16x64_bf16:10211 case Intrinsic::amdgcn_swmmac_f32_16x16x64_f16:10212 case Intrinsic::amdgcn_swmmac_i32_16x16x128_iu8: {10213 EVT IndexKeyTy = IntrinsicID == Intrinsic::amdgcn_swmmac_i32_16x16x128_iu810214 ? MVT::i6410215 : MVT::i32;10216 if (Op.getOperand(6).getValueType() == IndexKeyTy)10217 return SDValue();10218 10219 SDLoc SL(Op);10220 auto IndexKey = DAG.getAnyExtOrTrunc(Op.getOperand(6), SL, IndexKeyTy);10221 return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, Op.getValueType(),10222 {Op.getOperand(0), Op.getOperand(1), Op.getOperand(2),10223 Op.getOperand(3), Op.getOperand(4), Op.getOperand(5),10224 IndexKey, Op.getOperand(7),10225 Op.getOperand(8)}); // No clamp operand10226 }10227 case Intrinsic::amdgcn_swmmac_i32_16x16x32_iu4:10228 case Intrinsic::amdgcn_swmmac_i32_16x16x32_iu8:10229 case Intrinsic::amdgcn_swmmac_i32_16x16x64_iu4: {10230 if (Op.getOperand(6).getValueType() == MVT::i32)10231 return SDValue();10232 10233 SDLoc SL(Op);10234 auto IndexKeyi32 = DAG.getAnyExtOrTrunc(Op.getOperand(6), SL, MVT::i32);10235 return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, Op.getValueType(),10236 {Op.getOperand(0), Op.getOperand(1), Op.getOperand(2),10237 Op.getOperand(3), Op.getOperand(4), Op.getOperand(5),10238 IndexKeyi32, Op.getOperand(7)});10239 }10240 case Intrinsic::amdgcn_addrspacecast_nonnull:10241 return lowerADDRSPACECAST(Op, DAG);10242 case Intrinsic::amdgcn_readlane:10243 case Intrinsic::amdgcn_readfirstlane:10244 case Intrinsic::amdgcn_writelane:10245 case Intrinsic::amdgcn_permlane16:10246 case Intrinsic::amdgcn_permlanex16:10247 case Intrinsic::amdgcn_permlane64:10248 case Intrinsic::amdgcn_set_inactive:10249 case Intrinsic::amdgcn_set_inactive_chain_arg:10250 case Intrinsic::amdgcn_mov_dpp8:10251 case Intrinsic::amdgcn_update_dpp:10252 return lowerLaneOp(*this, Op.getNode(), DAG);10253 case Intrinsic::amdgcn_dead: {10254 SmallVector<SDValue, 8> Poisons;10255 for (const EVT ValTy : Op.getNode()->values())10256 Poisons.push_back(DAG.getPOISON(ValTy));10257 return DAG.getMergeValues(Poisons, SDLoc(Op));10258 }10259 default:10260 if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr =10261 AMDGPU::getImageDimIntrinsicInfo(IntrinsicID))10262 return lowerImage(Op, ImageDimIntr, DAG, false);10263 10264 return Op;10265 }10266}10267 10268// On targets not supporting constant in soffset field, turn zero to10269// SGPR_NULL to avoid generating an extra s_mov with zero.10270static SDValue selectSOffset(SDValue SOffset, SelectionDAG &DAG,10271 const GCNSubtarget *Subtarget) {10272 if (Subtarget->hasRestrictedSOffset() && isNullConstant(SOffset))10273 return DAG.getRegister(AMDGPU::SGPR_NULL, MVT::i32);10274 return SOffset;10275}10276 10277SDValue SITargetLowering::lowerRawBufferAtomicIntrin(SDValue Op,10278 SelectionDAG &DAG,10279 unsigned NewOpcode) const {10280 SDLoc DL(Op);10281 10282 SDValue VData = Op.getOperand(2);10283 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);10284 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(4), DAG);10285 auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);10286 SDValue Ops[] = {10287 Op.getOperand(0), // Chain10288 VData, // vdata10289 Rsrc, // rsrc10290 DAG.getConstant(0, DL, MVT::i32), // vindex10291 VOffset, // voffset10292 SOffset, // soffset10293 Offset, // offset10294 Op.getOperand(6), // cachepolicy10295 DAG.getTargetConstant(0, DL, MVT::i1), // idxen10296 };10297 10298 auto *M = cast<MemSDNode>(Op);10299 10300 EVT MemVT = VData.getValueType();10301 return DAG.getMemIntrinsicNode(NewOpcode, DL, Op->getVTList(), Ops, MemVT,10302 M->getMemOperand());10303}10304 10305SDValue10306SITargetLowering::lowerStructBufferAtomicIntrin(SDValue Op, SelectionDAG &DAG,10307 unsigned NewOpcode) const {10308 SDLoc DL(Op);10309 10310 SDValue VData = Op.getOperand(2);10311 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);10312 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(5), DAG);10313 auto SOffset = selectSOffset(Op.getOperand(6), DAG, Subtarget);10314 SDValue Ops[] = {10315 Op.getOperand(0), // Chain10316 VData, // vdata10317 Rsrc, // rsrc10318 Op.getOperand(4), // vindex10319 VOffset, // voffset10320 SOffset, // soffset10321 Offset, // offset10322 Op.getOperand(7), // cachepolicy10323 DAG.getTargetConstant(1, DL, MVT::i1), // idxen10324 };10325 10326 auto *M = cast<MemSDNode>(Op);10327 10328 EVT MemVT = VData.getValueType();10329 return DAG.getMemIntrinsicNode(NewOpcode, DL, Op->getVTList(), Ops, MemVT,10330 M->getMemOperand());10331}10332 10333SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op,10334 SelectionDAG &DAG) const {10335 unsigned IntrID = Op.getConstantOperandVal(1);10336 SDLoc DL(Op);10337 10338 switch (IntrID) {10339 case Intrinsic::amdgcn_ds_ordered_add:10340 case Intrinsic::amdgcn_ds_ordered_swap: {10341 MemSDNode *M = cast<MemSDNode>(Op);10342 SDValue Chain = M->getOperand(0);10343 SDValue M0 = M->getOperand(2);10344 SDValue Value = M->getOperand(3);10345 unsigned IndexOperand = M->getConstantOperandVal(7);10346 unsigned WaveRelease = M->getConstantOperandVal(8);10347 unsigned WaveDone = M->getConstantOperandVal(9);10348 10349 unsigned OrderedCountIndex = IndexOperand & 0x3f;10350 IndexOperand &= ~0x3f;10351 unsigned CountDw = 0;10352 10353 if (Subtarget->getGeneration() >= AMDGPUSubtarget::GFX10) {10354 CountDw = (IndexOperand >> 24) & 0xf;10355 IndexOperand &= ~(0xf << 24);10356 10357 if (CountDw < 1 || CountDw > 4) {10358 const Function &Fn = DAG.getMachineFunction().getFunction();10359 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(10360 Fn, "ds_ordered_count: dword count must be between 1 and 4",10361 DL.getDebugLoc()));10362 CountDw = 1;10363 }10364 }10365 10366 if (IndexOperand) {10367 const Function &Fn = DAG.getMachineFunction().getFunction();10368 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(10369 Fn, "ds_ordered_count: bad index operand", DL.getDebugLoc()));10370 }10371 10372 if (WaveDone && !WaveRelease) {10373 // TODO: Move this to IR verifier10374 const Function &Fn = DAG.getMachineFunction().getFunction();10375 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(10376 Fn, "ds_ordered_count: wave_done requires wave_release",10377 DL.getDebugLoc()));10378 }10379 10380 unsigned Instruction = IntrID == Intrinsic::amdgcn_ds_ordered_add ? 0 : 1;10381 unsigned ShaderType =10382 SIInstrInfo::getDSShaderTypeValue(DAG.getMachineFunction());10383 unsigned Offset0 = OrderedCountIndex << 2;10384 unsigned Offset1 = WaveRelease | (WaveDone << 1) | (Instruction << 4);10385 10386 if (Subtarget->getGeneration() >= AMDGPUSubtarget::GFX10)10387 Offset1 |= (CountDw - 1) << 6;10388 10389 if (Subtarget->getGeneration() < AMDGPUSubtarget::GFX11)10390 Offset1 |= ShaderType << 2;10391 10392 unsigned Offset = Offset0 | (Offset1 << 8);10393 10394 SDValue Ops[] = {10395 Chain, Value, DAG.getTargetConstant(Offset, DL, MVT::i16),10396 copyToM0(DAG, Chain, DL, M0).getValue(1), // Glue10397 };10398 return DAG.getMemIntrinsicNode(AMDGPUISD::DS_ORDERED_COUNT, DL,10399 M->getVTList(), Ops, M->getMemoryVT(),10400 M->getMemOperand());10401 }10402 case Intrinsic::amdgcn_raw_buffer_load:10403 case Intrinsic::amdgcn_raw_ptr_buffer_load:10404 case Intrinsic::amdgcn_raw_atomic_buffer_load:10405 case Intrinsic::amdgcn_raw_ptr_atomic_buffer_load:10406 case Intrinsic::amdgcn_raw_buffer_load_format:10407 case Intrinsic::amdgcn_raw_ptr_buffer_load_format: {10408 const bool IsFormat =10409 IntrID == Intrinsic::amdgcn_raw_buffer_load_format ||10410 IntrID == Intrinsic::amdgcn_raw_ptr_buffer_load_format;10411 10412 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(2), DAG);10413 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(3), DAG);10414 auto SOffset = selectSOffset(Op.getOperand(4), DAG, Subtarget);10415 SDValue Ops[] = {10416 Op.getOperand(0), // Chain10417 Rsrc, // rsrc10418 DAG.getConstant(0, DL, MVT::i32), // vindex10419 VOffset, // voffset10420 SOffset, // soffset10421 Offset, // offset10422 Op.getOperand(5), // cachepolicy, swizzled buffer10423 DAG.getTargetConstant(0, DL, MVT::i1), // idxen10424 };10425 10426 auto *M = cast<MemSDNode>(Op);10427 return lowerIntrinsicLoad(M, IsFormat, DAG, Ops);10428 }10429 case Intrinsic::amdgcn_struct_buffer_load:10430 case Intrinsic::amdgcn_struct_ptr_buffer_load:10431 case Intrinsic::amdgcn_struct_buffer_load_format:10432 case Intrinsic::amdgcn_struct_ptr_buffer_load_format:10433 case Intrinsic::amdgcn_struct_atomic_buffer_load:10434 case Intrinsic::amdgcn_struct_ptr_atomic_buffer_load: {10435 const bool IsFormat =10436 IntrID == Intrinsic::amdgcn_struct_buffer_load_format ||10437 IntrID == Intrinsic::amdgcn_struct_ptr_buffer_load_format;10438 10439 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(2), DAG);10440 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(4), DAG);10441 auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);10442 SDValue Ops[] = {10443 Op.getOperand(0), // Chain10444 Rsrc, // rsrc10445 Op.getOperand(3), // vindex10446 VOffset, // voffset10447 SOffset, // soffset10448 Offset, // offset10449 Op.getOperand(6), // cachepolicy, swizzled buffer10450 DAG.getTargetConstant(1, DL, MVT::i1), // idxen10451 };10452 10453 return lowerIntrinsicLoad(cast<MemSDNode>(Op), IsFormat, DAG, Ops);10454 }10455 case Intrinsic::amdgcn_raw_tbuffer_load:10456 case Intrinsic::amdgcn_raw_ptr_tbuffer_load: {10457 MemSDNode *M = cast<MemSDNode>(Op);10458 EVT LoadVT = Op.getValueType();10459 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(2), DAG);10460 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(3), DAG);10461 auto SOffset = selectSOffset(Op.getOperand(4), DAG, Subtarget);10462 10463 SDValue Ops[] = {10464 Op.getOperand(0), // Chain10465 Rsrc, // rsrc10466 DAG.getConstant(0, DL, MVT::i32), // vindex10467 VOffset, // voffset10468 SOffset, // soffset10469 Offset, // offset10470 Op.getOperand(5), // format10471 Op.getOperand(6), // cachepolicy, swizzled buffer10472 DAG.getTargetConstant(0, DL, MVT::i1), // idxen10473 };10474 10475 if (LoadVT.getScalarType() == MVT::f16)10476 return adjustLoadValueType(AMDGPUISD::TBUFFER_LOAD_FORMAT_D16, M, DAG,10477 Ops);10478 return getMemIntrinsicNode(AMDGPUISD::TBUFFER_LOAD_FORMAT, DL,10479 Op->getVTList(), Ops, LoadVT, M->getMemOperand(),10480 DAG);10481 }10482 case Intrinsic::amdgcn_struct_tbuffer_load:10483 case Intrinsic::amdgcn_struct_ptr_tbuffer_load: {10484 MemSDNode *M = cast<MemSDNode>(Op);10485 EVT LoadVT = Op.getValueType();10486 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(2), DAG);10487 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(4), DAG);10488 auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);10489 10490 SDValue Ops[] = {10491 Op.getOperand(0), // Chain10492 Rsrc, // rsrc10493 Op.getOperand(3), // vindex10494 VOffset, // voffset10495 SOffset, // soffset10496 Offset, // offset10497 Op.getOperand(6), // format10498 Op.getOperand(7), // cachepolicy, swizzled buffer10499 DAG.getTargetConstant(1, DL, MVT::i1), // idxen10500 };10501 10502 if (LoadVT.getScalarType() == MVT::f16)10503 return adjustLoadValueType(AMDGPUISD::TBUFFER_LOAD_FORMAT_D16, M, DAG,10504 Ops);10505 return getMemIntrinsicNode(AMDGPUISD::TBUFFER_LOAD_FORMAT, DL,10506 Op->getVTList(), Ops, LoadVT, M->getMemOperand(),10507 DAG);10508 }10509 case Intrinsic::amdgcn_raw_buffer_atomic_fadd:10510 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd:10511 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_FADD);10512 case Intrinsic::amdgcn_struct_buffer_atomic_fadd:10513 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fadd:10514 return lowerStructBufferAtomicIntrin(Op, DAG,10515 AMDGPUISD::BUFFER_ATOMIC_FADD);10516 case Intrinsic::amdgcn_raw_buffer_atomic_fmin:10517 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin:10518 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_FMIN);10519 case Intrinsic::amdgcn_struct_buffer_atomic_fmin:10520 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmin:10521 return lowerStructBufferAtomicIntrin(Op, DAG,10522 AMDGPUISD::BUFFER_ATOMIC_FMIN);10523 case Intrinsic::amdgcn_raw_buffer_atomic_fmax:10524 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax:10525 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_FMAX);10526 case Intrinsic::amdgcn_struct_buffer_atomic_fmax:10527 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmax:10528 return lowerStructBufferAtomicIntrin(Op, DAG,10529 AMDGPUISD::BUFFER_ATOMIC_FMAX);10530 case Intrinsic::amdgcn_raw_buffer_atomic_swap:10531 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap:10532 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_SWAP);10533 case Intrinsic::amdgcn_raw_buffer_atomic_add:10534 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_add:10535 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_ADD);10536 case Intrinsic::amdgcn_raw_buffer_atomic_sub:10537 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub:10538 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_SUB);10539 case Intrinsic::amdgcn_raw_buffer_atomic_smin:10540 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin:10541 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_SMIN);10542 case Intrinsic::amdgcn_raw_buffer_atomic_umin:10543 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin:10544 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_UMIN);10545 case Intrinsic::amdgcn_raw_buffer_atomic_smax:10546 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax:10547 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_SMAX);10548 case Intrinsic::amdgcn_raw_buffer_atomic_umax:10549 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax:10550 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_UMAX);10551 case Intrinsic::amdgcn_raw_buffer_atomic_and:10552 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_and:10553 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_AND);10554 case Intrinsic::amdgcn_raw_buffer_atomic_or:10555 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_or:10556 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_OR);10557 case Intrinsic::amdgcn_raw_buffer_atomic_xor:10558 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor:10559 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_XOR);10560 case Intrinsic::amdgcn_raw_buffer_atomic_inc:10561 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_inc:10562 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_INC);10563 case Intrinsic::amdgcn_raw_buffer_atomic_dec:10564 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_dec:10565 return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_DEC);10566 case Intrinsic::amdgcn_raw_buffer_atomic_cond_sub_u32:10567 return lowerRawBufferAtomicIntrin(Op, DAG,10568 AMDGPUISD::BUFFER_ATOMIC_COND_SUB_U32);10569 case Intrinsic::amdgcn_struct_buffer_atomic_swap:10570 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_swap:10571 return lowerStructBufferAtomicIntrin(Op, DAG,10572 AMDGPUISD::BUFFER_ATOMIC_SWAP);10573 case Intrinsic::amdgcn_struct_buffer_atomic_add:10574 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_add:10575 return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_ADD);10576 case Intrinsic::amdgcn_struct_buffer_atomic_sub:10577 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub:10578 return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_SUB);10579 case Intrinsic::amdgcn_struct_buffer_atomic_smin:10580 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smin:10581 return lowerStructBufferAtomicIntrin(Op, DAG,10582 AMDGPUISD::BUFFER_ATOMIC_SMIN);10583 case Intrinsic::amdgcn_struct_buffer_atomic_umin:10584 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umin:10585 return lowerStructBufferAtomicIntrin(Op, DAG,10586 AMDGPUISD::BUFFER_ATOMIC_UMIN);10587 case Intrinsic::amdgcn_struct_buffer_atomic_smax:10588 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smax:10589 return lowerStructBufferAtomicIntrin(Op, DAG,10590 AMDGPUISD::BUFFER_ATOMIC_SMAX);10591 case Intrinsic::amdgcn_struct_buffer_atomic_umax:10592 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umax:10593 return lowerStructBufferAtomicIntrin(Op, DAG,10594 AMDGPUISD::BUFFER_ATOMIC_UMAX);10595 case Intrinsic::amdgcn_struct_buffer_atomic_and:10596 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_and:10597 return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_AND);10598 case Intrinsic::amdgcn_struct_buffer_atomic_or:10599 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_or:10600 return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_OR);10601 case Intrinsic::amdgcn_struct_buffer_atomic_xor:10602 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_xor:10603 return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_XOR);10604 case Intrinsic::amdgcn_struct_buffer_atomic_inc:10605 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_inc:10606 return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_INC);10607 case Intrinsic::amdgcn_struct_buffer_atomic_dec:10608 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_dec:10609 return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_DEC);10610 case Intrinsic::amdgcn_struct_buffer_atomic_cond_sub_u32:10611 return lowerStructBufferAtomicIntrin(Op, DAG,10612 AMDGPUISD::BUFFER_ATOMIC_COND_SUB_U32);10613 10614 case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap:10615 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap: {10616 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(4), DAG);10617 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(5), DAG);10618 auto SOffset = selectSOffset(Op.getOperand(6), DAG, Subtarget);10619 SDValue Ops[] = {10620 Op.getOperand(0), // Chain10621 Op.getOperand(2), // src10622 Op.getOperand(3), // cmp10623 Rsrc, // rsrc10624 DAG.getConstant(0, DL, MVT::i32), // vindex10625 VOffset, // voffset10626 SOffset, // soffset10627 Offset, // offset10628 Op.getOperand(7), // cachepolicy10629 DAG.getTargetConstant(0, DL, MVT::i1), // idxen10630 };10631 EVT VT = Op.getValueType();10632 auto *M = cast<MemSDNode>(Op);10633 10634 return DAG.getMemIntrinsicNode(AMDGPUISD::BUFFER_ATOMIC_CMPSWAP, DL,10635 Op->getVTList(), Ops, VT,10636 M->getMemOperand());10637 }10638 case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap:10639 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap: {10640 SDValue Rsrc = bufferRsrcPtrToVector(Op->getOperand(4), DAG);10641 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(6), DAG);10642 auto SOffset = selectSOffset(Op.getOperand(7), DAG, Subtarget);10643 SDValue Ops[] = {10644 Op.getOperand(0), // Chain10645 Op.getOperand(2), // src10646 Op.getOperand(3), // cmp10647 Rsrc, // rsrc10648 Op.getOperand(5), // vindex10649 VOffset, // voffset10650 SOffset, // soffset10651 Offset, // offset10652 Op.getOperand(8), // cachepolicy10653 DAG.getTargetConstant(1, DL, MVT::i1), // idxen10654 };10655 EVT VT = Op.getValueType();10656 auto *M = cast<MemSDNode>(Op);10657 10658 return DAG.getMemIntrinsicNode(AMDGPUISD::BUFFER_ATOMIC_CMPSWAP, DL,10659 Op->getVTList(), Ops, VT,10660 M->getMemOperand());10661 }10662 case Intrinsic::amdgcn_image_bvh_dual_intersect_ray:10663 case Intrinsic::amdgcn_image_bvh8_intersect_ray: {10664 MemSDNode *M = cast<MemSDNode>(Op);10665 SDValue NodePtr = M->getOperand(2);10666 SDValue RayExtent = M->getOperand(3);10667 SDValue InstanceMask = M->getOperand(4);10668 SDValue RayOrigin = M->getOperand(5);10669 SDValue RayDir = M->getOperand(6);10670 SDValue Offsets = M->getOperand(7);10671 SDValue TDescr = M->getOperand(8);10672 10673 assert(NodePtr.getValueType() == MVT::i64);10674 assert(RayDir.getValueType() == MVT::v3f32);10675 10676 if (!Subtarget->hasBVHDualAndBVH8Insts()) {10677 emitRemovedIntrinsicError(DAG, DL, Op.getValueType());10678 return SDValue();10679 }10680 10681 bool IsBVH8 = IntrID == Intrinsic::amdgcn_image_bvh8_intersect_ray;10682 const unsigned NumVDataDwords = 10;10683 const unsigned NumVAddrDwords = IsBVH8 ? 11 : 12;10684 int Opcode = AMDGPU::getMIMGOpcode(10685 IsBVH8 ? AMDGPU::IMAGE_BVH8_INTERSECT_RAY10686 : AMDGPU::IMAGE_BVH_DUAL_INTERSECT_RAY,10687 AMDGPU::MIMGEncGfx12, NumVDataDwords, NumVAddrDwords);10688 assert(Opcode != -1);10689 10690 SmallVector<SDValue, 7> Ops;10691 Ops.push_back(NodePtr);10692 Ops.push_back(DAG.getBuildVector(10693 MVT::v2i32, DL,10694 {DAG.getBitcast(MVT::i32, RayExtent),10695 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, InstanceMask)}));10696 Ops.push_back(RayOrigin);10697 Ops.push_back(RayDir);10698 Ops.push_back(Offsets);10699 Ops.push_back(TDescr);10700 Ops.push_back(M->getChain());10701 10702 auto *NewNode = DAG.getMachineNode(Opcode, DL, M->getVTList(), Ops);10703 MachineMemOperand *MemRef = M->getMemOperand();10704 DAG.setNodeMemRefs(NewNode, {MemRef});10705 return SDValue(NewNode, 0);10706 }10707 case Intrinsic::amdgcn_image_bvh_intersect_ray: {10708 MemSDNode *M = cast<MemSDNode>(Op);10709 SDValue NodePtr = M->getOperand(2);10710 SDValue RayExtent = M->getOperand(3);10711 SDValue RayOrigin = M->getOperand(4);10712 SDValue RayDir = M->getOperand(5);10713 SDValue RayInvDir = M->getOperand(6);10714 SDValue TDescr = M->getOperand(7);10715 10716 assert(NodePtr.getValueType() == MVT::i32 ||10717 NodePtr.getValueType() == MVT::i64);10718 assert(RayDir.getValueType() == MVT::v3f16 ||10719 RayDir.getValueType() == MVT::v3f32);10720 10721 if (!Subtarget->hasGFX10_AEncoding()) {10722 emitRemovedIntrinsicError(DAG, DL, Op.getValueType());10723 return SDValue();10724 }10725 10726 const bool IsGFX11 = AMDGPU::isGFX11(*Subtarget);10727 const bool IsGFX11Plus = AMDGPU::isGFX11Plus(*Subtarget);10728 const bool IsGFX12Plus = AMDGPU::isGFX12Plus(*Subtarget);10729 const bool IsA16 = RayDir.getValueType().getVectorElementType() == MVT::f16;10730 const bool Is64 = NodePtr.getValueType() == MVT::i64;10731 const unsigned NumVDataDwords = 4;10732 const unsigned NumVAddrDwords = IsA16 ? (Is64 ? 9 : 8) : (Is64 ? 12 : 11);10733 const unsigned NumVAddrs = IsGFX11Plus ? (IsA16 ? 4 : 5) : NumVAddrDwords;10734 const bool UseNSA = (Subtarget->hasNSAEncoding() &&10735 NumVAddrs <= Subtarget->getNSAMaxSize()) ||10736 IsGFX12Plus;10737 const unsigned BaseOpcodes[2][2] = {10738 {AMDGPU::IMAGE_BVH_INTERSECT_RAY, AMDGPU::IMAGE_BVH_INTERSECT_RAY_a16},10739 {AMDGPU::IMAGE_BVH64_INTERSECT_RAY,10740 AMDGPU::IMAGE_BVH64_INTERSECT_RAY_a16}};10741 int Opcode;10742 if (UseNSA) {10743 Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],10744 IsGFX12Plus ? AMDGPU::MIMGEncGfx1210745 : IsGFX11 ? AMDGPU::MIMGEncGfx11NSA10746 : AMDGPU::MIMGEncGfx10NSA,10747 NumVDataDwords, NumVAddrDwords);10748 } else {10749 assert(!IsGFX12Plus);10750 Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],10751 IsGFX11 ? AMDGPU::MIMGEncGfx11Default10752 : AMDGPU::MIMGEncGfx10Default,10753 NumVDataDwords, NumVAddrDwords);10754 }10755 assert(Opcode != -1);10756 10757 SmallVector<SDValue, 16> Ops;10758 10759 auto packLanes = [&DAG, &Ops, &DL](SDValue Op, bool IsAligned) {10760 SmallVector<SDValue, 3> Lanes;10761 DAG.ExtractVectorElements(Op, Lanes, 0, 3);10762 if (Lanes[0].getValueSizeInBits() == 32) {10763 for (unsigned I = 0; I < 3; ++I)10764 Ops.push_back(DAG.getBitcast(MVT::i32, Lanes[I]));10765 } else {10766 if (IsAligned) {10767 Ops.push_back(DAG.getBitcast(10768 MVT::i32,10769 DAG.getBuildVector(MVT::v2f16, DL, {Lanes[0], Lanes[1]})));10770 Ops.push_back(Lanes[2]);10771 } else {10772 SDValue Elt0 = Ops.pop_back_val();10773 Ops.push_back(DAG.getBitcast(10774 MVT::i32, DAG.getBuildVector(MVT::v2f16, DL, {Elt0, Lanes[0]})));10775 Ops.push_back(DAG.getBitcast(10776 MVT::i32,10777 DAG.getBuildVector(MVT::v2f16, DL, {Lanes[1], Lanes[2]})));10778 }10779 }10780 };10781 10782 if (UseNSA && IsGFX11Plus) {10783 Ops.push_back(NodePtr);10784 Ops.push_back(DAG.getBitcast(MVT::i32, RayExtent));10785 Ops.push_back(RayOrigin);10786 if (IsA16) {10787 SmallVector<SDValue, 3> DirLanes, InvDirLanes, MergedLanes;10788 DAG.ExtractVectorElements(RayDir, DirLanes, 0, 3);10789 DAG.ExtractVectorElements(RayInvDir, InvDirLanes, 0, 3);10790 for (unsigned I = 0; I < 3; ++I) {10791 MergedLanes.push_back(DAG.getBitcast(10792 MVT::i32, DAG.getBuildVector(MVT::v2f16, DL,10793 {DirLanes[I], InvDirLanes[I]})));10794 }10795 Ops.push_back(DAG.getBuildVector(MVT::v3i32, DL, MergedLanes));10796 } else {10797 Ops.push_back(RayDir);10798 Ops.push_back(RayInvDir);10799 }10800 } else {10801 if (Is64)10802 DAG.ExtractVectorElements(DAG.getBitcast(MVT::v2i32, NodePtr), Ops, 0,10803 2);10804 else10805 Ops.push_back(NodePtr);10806 10807 Ops.push_back(DAG.getBitcast(MVT::i32, RayExtent));10808 packLanes(RayOrigin, true);10809 packLanes(RayDir, true);10810 packLanes(RayInvDir, false);10811 }10812 10813 if (!UseNSA) {10814 // Build a single vector containing all the operands so far prepared.10815 if (NumVAddrDwords > 12) {10816 SDValue Undef = DAG.getPOISON(MVT::i32);10817 Ops.append(16 - Ops.size(), Undef);10818 }10819 assert(Ops.size() >= 8 && Ops.size() <= 12);10820 SDValue MergedOps =10821 DAG.getBuildVector(MVT::getVectorVT(MVT::i32, Ops.size()), DL, Ops);10822 Ops.clear();10823 Ops.push_back(MergedOps);10824 }10825 10826 Ops.push_back(TDescr);10827 Ops.push_back(DAG.getTargetConstant(IsA16, DL, MVT::i1));10828 Ops.push_back(M->getChain());10829 10830 auto *NewNode = DAG.getMachineNode(Opcode, DL, M->getVTList(), Ops);10831 MachineMemOperand *MemRef = M->getMemOperand();10832 DAG.setNodeMemRefs(NewNode, {MemRef});10833 return SDValue(NewNode, 0);10834 }10835 case Intrinsic::amdgcn_global_atomic_fmin_num:10836 case Intrinsic::amdgcn_global_atomic_fmax_num:10837 case Intrinsic::amdgcn_flat_atomic_fmin_num:10838 case Intrinsic::amdgcn_flat_atomic_fmax_num: {10839 MemSDNode *M = cast<MemSDNode>(Op);10840 SDValue Ops[] = {10841 M->getOperand(0), // Chain10842 M->getOperand(2), // Ptr10843 M->getOperand(3) // Value10844 };10845 unsigned Opcode = 0;10846 switch (IntrID) {10847 case Intrinsic::amdgcn_global_atomic_fmin_num:10848 case Intrinsic::amdgcn_flat_atomic_fmin_num: {10849 Opcode = ISD::ATOMIC_LOAD_FMIN;10850 break;10851 }10852 case Intrinsic::amdgcn_global_atomic_fmax_num:10853 case Intrinsic::amdgcn_flat_atomic_fmax_num: {10854 Opcode = ISD::ATOMIC_LOAD_FMAX;10855 break;10856 }10857 default:10858 llvm_unreachable("unhandled atomic opcode");10859 }10860 return DAG.getAtomic(Opcode, SDLoc(Op), M->getMemoryVT(), M->getVTList(),10861 Ops, M->getMemOperand());10862 }10863 case Intrinsic::amdgcn_s_get_barrier_state:10864 case Intrinsic::amdgcn_s_get_named_barrier_state: {10865 SDValue Chain = Op->getOperand(0);10866 SmallVector<SDValue, 2> Ops;10867 unsigned Opc;10868 10869 if (isa<ConstantSDNode>(Op->getOperand(2))) {10870 uint64_t BarID = cast<ConstantSDNode>(Op->getOperand(2))->getZExtValue();10871 if (IntrID == Intrinsic::amdgcn_s_get_named_barrier_state)10872 BarID = (BarID >> 4) & 0x3F;10873 Opc = AMDGPU::S_GET_BARRIER_STATE_IMM;10874 SDValue K = DAG.getTargetConstant(BarID, DL, MVT::i32);10875 Ops.push_back(K);10876 Ops.push_back(Chain);10877 } else {10878 Opc = AMDGPU::S_GET_BARRIER_STATE_M0;10879 if (IntrID == Intrinsic::amdgcn_s_get_named_barrier_state) {10880 SDValue M0Val;10881 M0Val = DAG.getNode(ISD::SRL, DL, MVT::i32, Op->getOperand(2),10882 DAG.getShiftAmountConstant(4, MVT::i32, DL));10883 M0Val = SDValue(10884 DAG.getMachineNode(AMDGPU::S_AND_B32, DL, MVT::i32, M0Val,10885 DAG.getTargetConstant(0x3F, DL, MVT::i32)),10886 0);10887 Ops.push_back(copyToM0(DAG, Chain, DL, M0Val).getValue(0));10888 } else10889 Ops.push_back(copyToM0(DAG, Chain, DL, Op->getOperand(2)).getValue(0));10890 }10891 10892 auto *NewMI = DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops);10893 return SDValue(NewMI, 0);10894 }10895 case Intrinsic::amdgcn_cooperative_atomic_load_32x4B:10896 case Intrinsic::amdgcn_cooperative_atomic_load_16x8B:10897 case Intrinsic::amdgcn_cooperative_atomic_load_8x16B: {10898 MemIntrinsicSDNode *MII = cast<MemIntrinsicSDNode>(Op);10899 SDValue Chain = Op->getOperand(0);10900 SDValue Ptr = Op->getOperand(2);10901 EVT VT = Op->getValueType(0);10902 return DAG.getAtomicLoad(ISD::NON_EXTLOAD, DL, MII->getMemoryVT(), VT,10903 Chain, Ptr, MII->getMemOperand());10904 }10905 default:10906 10907 if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr =10908 AMDGPU::getImageDimIntrinsicInfo(IntrID))10909 return lowerImage(Op, ImageDimIntr, DAG, true);10910 10911 return SDValue();10912 }10913}10914 10915// Call DAG.getMemIntrinsicNode for a load, but first widen a dwordx3 type to10916// dwordx4 if on SI and handle TFE loads.10917SDValue SITargetLowering::getMemIntrinsicNode(unsigned Opcode, const SDLoc &DL,10918 SDVTList VTList,10919 ArrayRef<SDValue> Ops, EVT MemVT,10920 MachineMemOperand *MMO,10921 SelectionDAG &DAG) const {10922 LLVMContext &C = *DAG.getContext();10923 MachineFunction &MF = DAG.getMachineFunction();10924 EVT VT = VTList.VTs[0];10925 10926 assert(VTList.NumVTs == 2 || VTList.NumVTs == 3);10927 bool IsTFE = VTList.NumVTs == 3;10928 if (IsTFE) {10929 unsigned NumValueDWords = divideCeil(VT.getSizeInBits(), 32);10930 unsigned NumOpDWords = NumValueDWords + 1;10931 EVT OpDWordsVT = EVT::getVectorVT(C, MVT::i32, NumOpDWords);10932 SDVTList OpDWordsVTList = DAG.getVTList(OpDWordsVT, VTList.VTs[2]);10933 MachineMemOperand *OpDWordsMMO =10934 MF.getMachineMemOperand(MMO, 0, NumOpDWords * 4);10935 SDValue Op = getMemIntrinsicNode(Opcode, DL, OpDWordsVTList, Ops,10936 OpDWordsVT, OpDWordsMMO, DAG);10937 SDValue Status = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, Op,10938 DAG.getVectorIdxConstant(NumValueDWords, DL));10939 SDValue ZeroIdx = DAG.getVectorIdxConstant(0, DL);10940 SDValue ValueDWords =10941 NumValueDWords == 110942 ? DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, Op, ZeroIdx)10943 : DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL,10944 EVT::getVectorVT(C, MVT::i32, NumValueDWords), Op,10945 ZeroIdx);10946 SDValue Value = DAG.getNode(ISD::BITCAST, DL, VT, ValueDWords);10947 return DAG.getMergeValues({Value, Status, SDValue(Op.getNode(), 1)}, DL);10948 }10949 10950 if (!Subtarget->hasDwordx3LoadStores() &&10951 (VT == MVT::v3i32 || VT == MVT::v3f32)) {10952 EVT WidenedVT = EVT::getVectorVT(C, VT.getVectorElementType(), 4);10953 EVT WidenedMemVT = EVT::getVectorVT(C, MemVT.getVectorElementType(), 4);10954 MachineMemOperand *WidenedMMO = MF.getMachineMemOperand(MMO, 0, 16);10955 SDVTList WidenedVTList = DAG.getVTList(WidenedVT, VTList.VTs[1]);10956 SDValue Op = DAG.getMemIntrinsicNode(Opcode, DL, WidenedVTList, Ops,10957 WidenedMemVT, WidenedMMO);10958 SDValue Value = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, VT, Op,10959 DAG.getVectorIdxConstant(0, DL));10960 return DAG.getMergeValues({Value, SDValue(Op.getNode(), 1)}, DL);10961 }10962 10963 return DAG.getMemIntrinsicNode(Opcode, DL, VTList, Ops, MemVT, MMO);10964}10965 10966SDValue SITargetLowering::handleD16VData(SDValue VData, SelectionDAG &DAG,10967 bool ImageStore) const {10968 EVT StoreVT = VData.getValueType();10969 10970 // No change for f16 and legal vector D16 types.10971 if (!StoreVT.isVector())10972 return VData;10973 10974 SDLoc DL(VData);10975 unsigned NumElements = StoreVT.getVectorNumElements();10976 10977 if (Subtarget->hasUnpackedD16VMem()) {10978 // We need to unpack the packed data to store.10979 EVT IntStoreVT = StoreVT.changeTypeToInteger();10980 SDValue IntVData = DAG.getNode(ISD::BITCAST, DL, IntStoreVT, VData);10981 10982 EVT EquivStoreVT =10983 EVT::getVectorVT(*DAG.getContext(), MVT::i32, NumElements);10984 SDValue ZExt = DAG.getNode(ISD::ZERO_EXTEND, DL, EquivStoreVT, IntVData);10985 return DAG.UnrollVectorOp(ZExt.getNode());10986 }10987 10988 // The sq block of gfx8.1 does not estimate register use correctly for d1610989 // image store instructions. The data operand is computed as if it were not a10990 // d16 image instruction.10991 if (ImageStore && Subtarget->hasImageStoreD16Bug()) {10992 // Bitcast to i1610993 EVT IntStoreVT = StoreVT.changeTypeToInteger();10994 SDValue IntVData = DAG.getNode(ISD::BITCAST, DL, IntStoreVT, VData);10995 10996 // Decompose into scalars10997 SmallVector<SDValue, 4> Elts;10998 DAG.ExtractVectorElements(IntVData, Elts);10999 11000 // Group pairs of i16 into v2i16 and bitcast to i3211001 SmallVector<SDValue, 4> PackedElts;11002 for (unsigned I = 0; I < Elts.size() / 2; I += 1) {11003 SDValue Pair =11004 DAG.getBuildVector(MVT::v2i16, DL, {Elts[I * 2], Elts[I * 2 + 1]});11005 SDValue IntPair = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Pair);11006 PackedElts.push_back(IntPair);11007 }11008 if ((NumElements % 2) == 1) {11009 // Handle v3i1611010 unsigned I = Elts.size() / 2;11011 SDValue Pair = DAG.getBuildVector(MVT::v2i16, DL,11012 {Elts[I * 2], DAG.getPOISON(MVT::i16)});11013 SDValue IntPair = DAG.getNode(ISD::BITCAST, DL, MVT::i32, Pair);11014 PackedElts.push_back(IntPair);11015 }11016 11017 // Pad using UNDEF11018 PackedElts.resize(Elts.size(), DAG.getPOISON(MVT::i32));11019 11020 // Build final vector11021 EVT VecVT =11022 EVT::getVectorVT(*DAG.getContext(), MVT::i32, PackedElts.size());11023 return DAG.getBuildVector(VecVT, DL, PackedElts);11024 }11025 11026 if (NumElements == 3) {11027 EVT IntStoreVT =11028 EVT::getIntegerVT(*DAG.getContext(), StoreVT.getStoreSizeInBits());11029 SDValue IntVData = DAG.getNode(ISD::BITCAST, DL, IntStoreVT, VData);11030 11031 EVT WidenedStoreVT = EVT::getVectorVT(11032 *DAG.getContext(), StoreVT.getVectorElementType(), NumElements + 1);11033 EVT WidenedIntVT = EVT::getIntegerVT(*DAG.getContext(),11034 WidenedStoreVT.getStoreSizeInBits());11035 SDValue ZExt = DAG.getNode(ISD::ZERO_EXTEND, DL, WidenedIntVT, IntVData);11036 return DAG.getNode(ISD::BITCAST, DL, WidenedStoreVT, ZExt);11037 }11038 11039 assert(isTypeLegal(StoreVT));11040 return VData;11041}11042 11043SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op,11044 SelectionDAG &DAG) const {11045 SDLoc DL(Op);11046 SDValue Chain = Op.getOperand(0);11047 unsigned IntrinsicID = Op.getConstantOperandVal(1);11048 MachineFunction &MF = DAG.getMachineFunction();11049 11050 switch (IntrinsicID) {11051 case Intrinsic::amdgcn_exp_compr: {11052 if (!Subtarget->hasCompressedExport()) {11053 DAG.getContext()->diagnose(DiagnosticInfoUnsupported(11054 DAG.getMachineFunction().getFunction(),11055 "intrinsic not supported on subtarget", DL.getDebugLoc()));11056 }11057 SDValue Src0 = Op.getOperand(4);11058 SDValue Src1 = Op.getOperand(5);11059 // Hack around illegal type on SI by directly selecting it.11060 if (isTypeLegal(Src0.getValueType()))11061 return SDValue();11062 11063 const ConstantSDNode *Done = cast<ConstantSDNode>(Op.getOperand(6));11064 SDValue Undef = DAG.getPOISON(MVT::f32);11065 const SDValue Ops[] = {11066 Op.getOperand(2), // tgt11067 DAG.getNode(ISD::BITCAST, DL, MVT::f32, Src0), // src011068 DAG.getNode(ISD::BITCAST, DL, MVT::f32, Src1), // src111069 Undef, // src211070 Undef, // src311071 Op.getOperand(7), // vm11072 DAG.getTargetConstant(1, DL, MVT::i1), // compr11073 Op.getOperand(3), // en11074 Op.getOperand(0) // Chain11075 };11076 11077 unsigned Opc = Done->isZero() ? AMDGPU::EXP : AMDGPU::EXP_DONE;11078 return SDValue(DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops), 0);11079 }11080 11081 case Intrinsic::amdgcn_struct_tbuffer_store:11082 case Intrinsic::amdgcn_struct_ptr_tbuffer_store: {11083 SDValue VData = Op.getOperand(2);11084 bool IsD16 = (VData.getValueType().getScalarType() == MVT::f16);11085 if (IsD16)11086 VData = handleD16VData(VData, DAG);11087 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);11088 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(5), DAG);11089 auto SOffset = selectSOffset(Op.getOperand(6), DAG, Subtarget);11090 SDValue Ops[] = {11091 Chain,11092 VData, // vdata11093 Rsrc, // rsrc11094 Op.getOperand(4), // vindex11095 VOffset, // voffset11096 SOffset, // soffset11097 Offset, // offset11098 Op.getOperand(7), // format11099 Op.getOperand(8), // cachepolicy, swizzled buffer11100 DAG.getTargetConstant(1, DL, MVT::i1), // idxen11101 };11102 unsigned Opc = IsD16 ? AMDGPUISD::TBUFFER_STORE_FORMAT_D1611103 : AMDGPUISD::TBUFFER_STORE_FORMAT;11104 MemSDNode *M = cast<MemSDNode>(Op);11105 return DAG.getMemIntrinsicNode(Opc, DL, Op->getVTList(), Ops,11106 M->getMemoryVT(), M->getMemOperand());11107 }11108 11109 case Intrinsic::amdgcn_raw_tbuffer_store:11110 case Intrinsic::amdgcn_raw_ptr_tbuffer_store: {11111 SDValue VData = Op.getOperand(2);11112 bool IsD16 = (VData.getValueType().getScalarType() == MVT::f16);11113 if (IsD16)11114 VData = handleD16VData(VData, DAG);11115 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);11116 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(4), DAG);11117 auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);11118 SDValue Ops[] = {11119 Chain,11120 VData, // vdata11121 Rsrc, // rsrc11122 DAG.getConstant(0, DL, MVT::i32), // vindex11123 VOffset, // voffset11124 SOffset, // soffset11125 Offset, // offset11126 Op.getOperand(6), // format11127 Op.getOperand(7), // cachepolicy, swizzled buffer11128 DAG.getTargetConstant(0, DL, MVT::i1), // idxen11129 };11130 unsigned Opc = IsD16 ? AMDGPUISD::TBUFFER_STORE_FORMAT_D1611131 : AMDGPUISD::TBUFFER_STORE_FORMAT;11132 MemSDNode *M = cast<MemSDNode>(Op);11133 return DAG.getMemIntrinsicNode(Opc, DL, Op->getVTList(), Ops,11134 M->getMemoryVT(), M->getMemOperand());11135 }11136 11137 case Intrinsic::amdgcn_raw_buffer_store:11138 case Intrinsic::amdgcn_raw_ptr_buffer_store:11139 case Intrinsic::amdgcn_raw_buffer_store_format:11140 case Intrinsic::amdgcn_raw_ptr_buffer_store_format: {11141 const bool IsFormat =11142 IntrinsicID == Intrinsic::amdgcn_raw_buffer_store_format ||11143 IntrinsicID == Intrinsic::amdgcn_raw_ptr_buffer_store_format;11144 11145 SDValue VData = Op.getOperand(2);11146 EVT VDataVT = VData.getValueType();11147 EVT EltType = VDataVT.getScalarType();11148 bool IsD16 = IsFormat && (EltType.getSizeInBits() == 16);11149 if (IsD16) {11150 VData = handleD16VData(VData, DAG);11151 VDataVT = VData.getValueType();11152 }11153 11154 if (!isTypeLegal(VDataVT)) {11155 VData =11156 DAG.getNode(ISD::BITCAST, DL,11157 getEquivalentMemType(*DAG.getContext(), VDataVT), VData);11158 }11159 11160 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);11161 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(4), DAG);11162 auto SOffset = selectSOffset(Op.getOperand(5), DAG, Subtarget);11163 SDValue Ops[] = {11164 Chain,11165 VData,11166 Rsrc,11167 DAG.getConstant(0, DL, MVT::i32), // vindex11168 VOffset, // voffset11169 SOffset, // soffset11170 Offset, // offset11171 Op.getOperand(6), // cachepolicy, swizzled buffer11172 DAG.getTargetConstant(0, DL, MVT::i1), // idxen11173 };11174 unsigned Opc =11175 IsFormat ? AMDGPUISD::BUFFER_STORE_FORMAT : AMDGPUISD::BUFFER_STORE;11176 Opc = IsD16 ? AMDGPUISD::BUFFER_STORE_FORMAT_D16 : Opc;11177 MemSDNode *M = cast<MemSDNode>(Op);11178 11179 // Handle BUFFER_STORE_BYTE/SHORT overloaded intrinsics11180 if (!IsD16 && !VDataVT.isVector() && EltType.getSizeInBits() < 32)11181 return handleByteShortBufferStores(DAG, VDataVT, DL, Ops, M);11182 11183 return DAG.getMemIntrinsicNode(Opc, DL, Op->getVTList(), Ops,11184 M->getMemoryVT(), M->getMemOperand());11185 }11186 11187 case Intrinsic::amdgcn_struct_buffer_store:11188 case Intrinsic::amdgcn_struct_ptr_buffer_store:11189 case Intrinsic::amdgcn_struct_buffer_store_format:11190 case Intrinsic::amdgcn_struct_ptr_buffer_store_format: {11191 const bool IsFormat =11192 IntrinsicID == Intrinsic::amdgcn_struct_buffer_store_format ||11193 IntrinsicID == Intrinsic::amdgcn_struct_ptr_buffer_store_format;11194 11195 SDValue VData = Op.getOperand(2);11196 EVT VDataVT = VData.getValueType();11197 EVT EltType = VDataVT.getScalarType();11198 bool IsD16 = IsFormat && (EltType.getSizeInBits() == 16);11199 11200 if (IsD16) {11201 VData = handleD16VData(VData, DAG);11202 VDataVT = VData.getValueType();11203 }11204 11205 if (!isTypeLegal(VDataVT)) {11206 VData =11207 DAG.getNode(ISD::BITCAST, DL,11208 getEquivalentMemType(*DAG.getContext(), VDataVT), VData);11209 }11210 11211 auto Rsrc = bufferRsrcPtrToVector(Op.getOperand(3), DAG);11212 auto [VOffset, Offset] = splitBufferOffsets(Op.getOperand(5), DAG);11213 auto SOffset = selectSOffset(Op.getOperand(6), DAG, Subtarget);11214 SDValue Ops[] = {11215 Chain,11216 VData,11217 Rsrc,11218 Op.getOperand(4), // vindex11219 VOffset, // voffset11220 SOffset, // soffset11221 Offset, // offset11222 Op.getOperand(7), // cachepolicy, swizzled buffer11223 DAG.getTargetConstant(1, DL, MVT::i1), // idxen11224 };11225 unsigned Opc =11226 !IsFormat ? AMDGPUISD::BUFFER_STORE : AMDGPUISD::BUFFER_STORE_FORMAT;11227 Opc = IsD16 ? AMDGPUISD::BUFFER_STORE_FORMAT_D16 : Opc;11228 MemSDNode *M = cast<MemSDNode>(Op);11229 11230 // Handle BUFFER_STORE_BYTE/SHORT overloaded intrinsics11231 EVT VDataType = VData.getValueType().getScalarType();11232 if (!IsD16 && !VDataVT.isVector() && EltType.getSizeInBits() < 32)11233 return handleByteShortBufferStores(DAG, VDataType, DL, Ops, M);11234 11235 return DAG.getMemIntrinsicNode(Opc, DL, Op->getVTList(), Ops,11236 M->getMemoryVT(), M->getMemOperand());11237 }11238 case Intrinsic::amdgcn_raw_buffer_load_lds:11239 case Intrinsic::amdgcn_raw_ptr_buffer_load_lds:11240 case Intrinsic::amdgcn_struct_buffer_load_lds:11241 case Intrinsic::amdgcn_struct_ptr_buffer_load_lds: {11242 if (!Subtarget->hasVMemToLDSLoad())11243 return SDValue();11244 unsigned Opc;11245 bool HasVIndex =11246 IntrinsicID == Intrinsic::amdgcn_struct_buffer_load_lds ||11247 IntrinsicID == Intrinsic::amdgcn_struct_ptr_buffer_load_lds;11248 unsigned OpOffset = HasVIndex ? 1 : 0;11249 SDValue VOffset = Op.getOperand(5 + OpOffset);11250 bool HasVOffset = !isNullConstant(VOffset);11251 unsigned Size = Op->getConstantOperandVal(4);11252 11253 switch (Size) {11254 default:11255 return SDValue();11256 case 1:11257 Opc = HasVIndex ? HasVOffset ? AMDGPU::BUFFER_LOAD_UBYTE_LDS_BOTHEN11258 : AMDGPU::BUFFER_LOAD_UBYTE_LDS_IDXEN11259 : HasVOffset ? AMDGPU::BUFFER_LOAD_UBYTE_LDS_OFFEN11260 : AMDGPU::BUFFER_LOAD_UBYTE_LDS_OFFSET;11261 break;11262 case 2:11263 Opc = HasVIndex ? HasVOffset ? AMDGPU::BUFFER_LOAD_USHORT_LDS_BOTHEN11264 : AMDGPU::BUFFER_LOAD_USHORT_LDS_IDXEN11265 : HasVOffset ? AMDGPU::BUFFER_LOAD_USHORT_LDS_OFFEN11266 : AMDGPU::BUFFER_LOAD_USHORT_LDS_OFFSET;11267 break;11268 case 4:11269 Opc = HasVIndex ? HasVOffset ? AMDGPU::BUFFER_LOAD_DWORD_LDS_BOTHEN11270 : AMDGPU::BUFFER_LOAD_DWORD_LDS_IDXEN11271 : HasVOffset ? AMDGPU::BUFFER_LOAD_DWORD_LDS_OFFEN11272 : AMDGPU::BUFFER_LOAD_DWORD_LDS_OFFSET;11273 break;11274 case 12:11275 if (!Subtarget->hasLDSLoadB96_B128())11276 return SDValue();11277 Opc = HasVIndex ? HasVOffset ? AMDGPU::BUFFER_LOAD_DWORDX3_LDS_BOTHEN11278 : AMDGPU::BUFFER_LOAD_DWORDX3_LDS_IDXEN11279 : HasVOffset ? AMDGPU::BUFFER_LOAD_DWORDX3_LDS_OFFEN11280 : AMDGPU::BUFFER_LOAD_DWORDX3_LDS_OFFSET;11281 break;11282 case 16:11283 if (!Subtarget->hasLDSLoadB96_B128())11284 return SDValue();11285 Opc = HasVIndex ? HasVOffset ? AMDGPU::BUFFER_LOAD_DWORDX4_LDS_BOTHEN11286 : AMDGPU::BUFFER_LOAD_DWORDX4_LDS_IDXEN11287 : HasVOffset ? AMDGPU::BUFFER_LOAD_DWORDX4_LDS_OFFEN11288 : AMDGPU::BUFFER_LOAD_DWORDX4_LDS_OFFSET;11289 break;11290 }11291 11292 SDValue M0Val = copyToM0(DAG, Chain, DL, Op.getOperand(3));11293 11294 SmallVector<SDValue, 8> Ops;11295 11296 if (HasVIndex && HasVOffset)11297 Ops.push_back(DAG.getBuildVector(MVT::v2i32, DL,11298 {Op.getOperand(5), // VIndex11299 VOffset}));11300 else if (HasVIndex)11301 Ops.push_back(Op.getOperand(5));11302 else if (HasVOffset)11303 Ops.push_back(VOffset);11304 11305 SDValue Rsrc = bufferRsrcPtrToVector(Op.getOperand(2), DAG);11306 Ops.push_back(Rsrc);11307 Ops.push_back(Op.getOperand(6 + OpOffset)); // soffset11308 Ops.push_back(Op.getOperand(7 + OpOffset)); // imm offset11309 bool IsGFX12Plus = AMDGPU::isGFX12Plus(*Subtarget);11310 unsigned Aux = Op.getConstantOperandVal(8 + OpOffset);11311 Ops.push_back(DAG.getTargetConstant(11312 Aux & (IsGFX12Plus ? AMDGPU::CPol::ALL : AMDGPU::CPol::ALL_pregfx12),11313 DL, MVT::i8)); // cpol11314 Ops.push_back(DAG.getTargetConstant(11315 Aux & (IsGFX12Plus ? AMDGPU::CPol::SWZ : AMDGPU::CPol::SWZ_pregfx12)11316 ? 111317 : 0,11318 DL, MVT::i8)); // swz11319 Ops.push_back(M0Val.getValue(0)); // Chain11320 Ops.push_back(M0Val.getValue(1)); // Glue11321 11322 auto *M = cast<MemSDNode>(Op);11323 MachineMemOperand *LoadMMO = M->getMemOperand();11324 // Don't set the offset value here because the pointer points to the base of11325 // the buffer.11326 MachinePointerInfo LoadPtrI = LoadMMO->getPointerInfo();11327 11328 MachinePointerInfo StorePtrI = LoadPtrI;11329 LoadPtrI.V = PoisonValue::get(11330 PointerType::get(*DAG.getContext(), AMDGPUAS::BUFFER_RESOURCE));11331 LoadPtrI.AddrSpace = AMDGPUAS::BUFFER_RESOURCE;11332 StorePtrI.AddrSpace = AMDGPUAS::LOCAL_ADDRESS;11333 11334 auto F = LoadMMO->getFlags() &11335 ~(MachineMemOperand::MOStore | MachineMemOperand::MOLoad);11336 LoadMMO =11337 MF.getMachineMemOperand(LoadPtrI, F | MachineMemOperand::MOLoad, Size,11338 LoadMMO->getBaseAlign(), LoadMMO->getAAInfo());11339 11340 MachineMemOperand *StoreMMO = MF.getMachineMemOperand(11341 StorePtrI, F | MachineMemOperand::MOStore, sizeof(int32_t),11342 LoadMMO->getBaseAlign(), LoadMMO->getAAInfo());11343 11344 auto *Load = DAG.getMachineNode(Opc, DL, M->getVTList(), Ops);11345 DAG.setNodeMemRefs(Load, {LoadMMO, StoreMMO});11346 11347 return SDValue(Load, 0);11348 }11349 // Buffers are handled by LowerBufferFatPointers, and we're going to go11350 // for "trust me" that the remaining cases are global pointers until11351 // such time as we can put two mem operands on an intrinsic.11352 case Intrinsic::amdgcn_load_to_lds:11353 case Intrinsic::amdgcn_global_load_lds: {11354 if (!Subtarget->hasVMemToLDSLoad())11355 return SDValue();11356 11357 unsigned Opc;11358 unsigned Size = Op->getConstantOperandVal(4);11359 switch (Size) {11360 default:11361 return SDValue();11362 case 1:11363 Opc = AMDGPU::GLOBAL_LOAD_LDS_UBYTE;11364 break;11365 case 2:11366 Opc = AMDGPU::GLOBAL_LOAD_LDS_USHORT;11367 break;11368 case 4:11369 Opc = AMDGPU::GLOBAL_LOAD_LDS_DWORD;11370 break;11371 case 12:11372 if (!Subtarget->hasLDSLoadB96_B128())11373 return SDValue();11374 Opc = AMDGPU::GLOBAL_LOAD_LDS_DWORDX3;11375 break;11376 case 16:11377 if (!Subtarget->hasLDSLoadB96_B128())11378 return SDValue();11379 Opc = AMDGPU::GLOBAL_LOAD_LDS_DWORDX4;11380 break;11381 }11382 11383 SDValue M0Val = copyToM0(DAG, Chain, DL, Op.getOperand(3));11384 11385 SmallVector<SDValue, 6> Ops;11386 11387 SDValue Addr = Op.getOperand(2); // Global ptr11388 SDValue VOffset;11389 // Try to split SAddr and VOffset. Global and LDS pointers share the same11390 // immediate offset, so we cannot use a regular SelectGlobalSAddr().11391 if (Addr->isDivergent() && Addr->isAnyAdd()) {11392 SDValue LHS = Addr.getOperand(0);11393 SDValue RHS = Addr.getOperand(1);11394 11395 if (LHS->isDivergent())11396 std::swap(LHS, RHS);11397 11398 if (!LHS->isDivergent() && RHS.getOpcode() == ISD::ZERO_EXTEND &&11399 RHS.getOperand(0).getValueType() == MVT::i32) {11400 // add (i64 sgpr), (zero_extend (i32 vgpr))11401 Addr = LHS;11402 VOffset = RHS.getOperand(0);11403 }11404 }11405 11406 Ops.push_back(Addr);11407 if (!Addr->isDivergent()) {11408 Opc = AMDGPU::getGlobalSaddrOp(Opc);11409 if (!VOffset)11410 VOffset =11411 SDValue(DAG.getMachineNode(AMDGPU::V_MOV_B32_e32, DL, MVT::i32,11412 DAG.getTargetConstant(0, DL, MVT::i32)),11413 0);11414 Ops.push_back(VOffset);11415 }11416 11417 Ops.push_back(Op.getOperand(5)); // Offset11418 11419 unsigned Aux = Op.getConstantOperandVal(6);11420 Ops.push_back(DAG.getTargetConstant(Aux & ~AMDGPU::CPol::VIRTUAL_BITS, DL,11421 MVT::i32)); // CPol11422 11423 Ops.push_back(M0Val.getValue(0)); // Chain11424 Ops.push_back(M0Val.getValue(1)); // Glue11425 11426 auto *M = cast<MemSDNode>(Op);11427 MachineMemOperand *LoadMMO = M->getMemOperand();11428 MachinePointerInfo LoadPtrI = LoadMMO->getPointerInfo();11429 LoadPtrI.Offset = Op->getConstantOperandVal(5);11430 MachinePointerInfo StorePtrI = LoadPtrI;11431 LoadPtrI.V = PoisonValue::get(11432 PointerType::get(*DAG.getContext(), AMDGPUAS::GLOBAL_ADDRESS));11433 LoadPtrI.AddrSpace = AMDGPUAS::GLOBAL_ADDRESS;11434 StorePtrI.AddrSpace = AMDGPUAS::LOCAL_ADDRESS;11435 auto F = LoadMMO->getFlags() &11436 ~(MachineMemOperand::MOStore | MachineMemOperand::MOLoad);11437 LoadMMO =11438 MF.getMachineMemOperand(LoadPtrI, F | MachineMemOperand::MOLoad, Size,11439 LoadMMO->getBaseAlign(), LoadMMO->getAAInfo());11440 MachineMemOperand *StoreMMO = MF.getMachineMemOperand(11441 StorePtrI, F | MachineMemOperand::MOStore, sizeof(int32_t), Align(4),11442 LoadMMO->getAAInfo());11443 11444 auto *Load = DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops);11445 DAG.setNodeMemRefs(Load, {LoadMMO, StoreMMO});11446 11447 return SDValue(Load, 0);11448 }11449 case Intrinsic::amdgcn_end_cf:11450 return SDValue(DAG.getMachineNode(AMDGPU::SI_END_CF, DL, MVT::Other,11451 Op->getOperand(2), Chain),11452 0);11453 case Intrinsic::amdgcn_s_barrier_init:11454 case Intrinsic::amdgcn_s_barrier_signal_var: {11455 // these two intrinsics have two operands: barrier pointer and member count11456 SDValue Chain = Op->getOperand(0);11457 SmallVector<SDValue, 2> Ops;11458 SDValue BarOp = Op->getOperand(2);11459 SDValue CntOp = Op->getOperand(3);11460 SDValue M0Val;11461 unsigned Opc = IntrinsicID == Intrinsic::amdgcn_s_barrier_init11462 ? AMDGPU::S_BARRIER_INIT_M011463 : AMDGPU::S_BARRIER_SIGNAL_M0;11464 // extract the BarrierID from bits 4-9 of BarOp11465 SDValue BarID;11466 BarID = DAG.getNode(ISD::SRL, DL, MVT::i32, BarOp,11467 DAG.getShiftAmountConstant(4, MVT::i32, DL));11468 BarID =11469 SDValue(DAG.getMachineNode(AMDGPU::S_AND_B32, DL, MVT::i32, BarID,11470 DAG.getTargetConstant(0x3F, DL, MVT::i32)),11471 0);11472 // Member count should be put into M0[ShAmt:+6]11473 // Barrier ID should be put into M0[5:0]11474 M0Val =11475 SDValue(DAG.getMachineNode(AMDGPU::S_AND_B32, DL, MVT::i32, CntOp,11476 DAG.getTargetConstant(0x3F, DL, MVT::i32)),11477 0);11478 constexpr unsigned ShAmt = 16;11479 M0Val = DAG.getNode(ISD::SHL, DL, MVT::i32, CntOp,11480 DAG.getShiftAmountConstant(ShAmt, MVT::i32, DL));11481 11482 M0Val = SDValue(11483 DAG.getMachineNode(AMDGPU::S_OR_B32, DL, MVT::i32, M0Val, BarID), 0);11484 11485 Ops.push_back(copyToM0(DAG, Chain, DL, M0Val).getValue(0));11486 11487 auto *NewMI = DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops);11488 return SDValue(NewMI, 0);11489 }11490 case Intrinsic::amdgcn_s_barrier_join: {11491 // these three intrinsics have one operand: barrier pointer11492 SDValue Chain = Op->getOperand(0);11493 SmallVector<SDValue, 2> Ops;11494 SDValue BarOp = Op->getOperand(2);11495 unsigned Opc;11496 11497 if (isa<ConstantSDNode>(BarOp)) {11498 uint64_t BarVal = cast<ConstantSDNode>(BarOp)->getZExtValue();11499 Opc = AMDGPU::S_BARRIER_JOIN_IMM;11500 11501 // extract the BarrierID from bits 4-9 of the immediate11502 unsigned BarID = (BarVal >> 4) & 0x3F;11503 SDValue K = DAG.getTargetConstant(BarID, DL, MVT::i32);11504 Ops.push_back(K);11505 Ops.push_back(Chain);11506 } else {11507 Opc = AMDGPU::S_BARRIER_JOIN_M0;11508 11509 // extract the BarrierID from bits 4-9 of BarOp, copy to M0[5:0]11510 SDValue M0Val;11511 M0Val = DAG.getNode(ISD::SRL, DL, MVT::i32, BarOp,11512 DAG.getShiftAmountConstant(4, MVT::i32, DL));11513 M0Val =11514 SDValue(DAG.getMachineNode(AMDGPU::S_AND_B32, DL, MVT::i32, M0Val,11515 DAG.getTargetConstant(0x3F, DL, MVT::i32)),11516 0);11517 Ops.push_back(copyToM0(DAG, Chain, DL, M0Val).getValue(0));11518 }11519 11520 auto *NewMI = DAG.getMachineNode(Opc, DL, Op->getVTList(), Ops);11521 return SDValue(NewMI, 0);11522 }11523 case Intrinsic::amdgcn_s_prefetch_data: {11524 // For non-global address space preserve the chain and remove the call.11525 if (!AMDGPU::isFlatGlobalAddrSpace(cast<MemSDNode>(Op)->getAddressSpace()))11526 return Op.getOperand(0);11527 return Op;11528 }11529 case Intrinsic::amdgcn_s_buffer_prefetch_data: {11530 SDValue Ops[] = {11531 Chain, bufferRsrcPtrToVector(Op.getOperand(2), DAG),11532 Op.getOperand(3), // offset11533 Op.getOperand(4), // length11534 };11535 11536 MemSDNode *M = cast<MemSDNode>(Op);11537 return DAG.getMemIntrinsicNode(AMDGPUISD::SBUFFER_PREFETCH_DATA, DL,11538 Op->getVTList(), Ops, M->getMemoryVT(),11539 M->getMemOperand());11540 }11541 case Intrinsic::amdgcn_cooperative_atomic_store_32x4B:11542 case Intrinsic::amdgcn_cooperative_atomic_store_16x8B:11543 case Intrinsic::amdgcn_cooperative_atomic_store_8x16B: {11544 MemIntrinsicSDNode *MII = cast<MemIntrinsicSDNode>(Op);11545 SDValue Chain = Op->getOperand(0);11546 SDValue Ptr = Op->getOperand(2);11547 SDValue Val = Op->getOperand(3);11548 return DAG.getAtomic(ISD::ATOMIC_STORE, DL, MII->getMemoryVT(), Chain, Val,11549 Ptr, MII->getMemOperand());11550 }11551 default: {11552 if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr =11553 AMDGPU::getImageDimIntrinsicInfo(IntrinsicID))11554 return lowerImage(Op, ImageDimIntr, DAG, true);11555 11556 return Op;11557 }11558 }11559}11560 11561// Return whether the operation has NoUnsignedWrap property.11562static bool isNoUnsignedWrap(SDValue Addr) {11563 return (Addr.getOpcode() == ISD::ADD &&11564 Addr->getFlags().hasNoUnsignedWrap()) ||11565 Addr->getOpcode() == ISD::OR;11566}11567 11568bool SITargetLowering::shouldPreservePtrArith(const Function &F,11569 EVT PtrVT) const {11570 return PtrVT == MVT::i64;11571}11572 11573bool SITargetLowering::canTransformPtrArithOutOfBounds(const Function &F,11574 EVT PtrVT) const {11575 return true;11576}11577 11578// The raw.(t)buffer and struct.(t)buffer intrinsics have two offset args:11579// offset (the offset that is included in bounds checking and swizzling, to be11580// split between the instruction's voffset and immoffset fields) and soffset11581// (the offset that is excluded from bounds checking and swizzling, to go in11582// the instruction's soffset field). This function takes the first kind of11583// offset and figures out how to split it between voffset and immoffset.11584std::pair<SDValue, SDValue>11585SITargetLowering::splitBufferOffsets(SDValue Offset, SelectionDAG &DAG) const {11586 SDLoc DL(Offset);11587 const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset(*Subtarget);11588 SDValue N0 = Offset;11589 ConstantSDNode *C1 = nullptr;11590 11591 if ((C1 = dyn_cast<ConstantSDNode>(N0)))11592 N0 = SDValue();11593 else if (DAG.isBaseWithConstantOffset(N0)) {11594 // On GFX1250+, voffset and immoffset are zero-extended from 32 bits before11595 // being added, so we can only safely match a 32-bit addition with no11596 // unsigned overflow.11597 bool CheckNUW = AMDGPU::isGFX1250(*Subtarget);11598 if (!CheckNUW || isNoUnsignedWrap(N0)) {11599 C1 = cast<ConstantSDNode>(N0.getOperand(1));11600 N0 = N0.getOperand(0);11601 }11602 }11603 11604 if (C1) {11605 unsigned ImmOffset = C1->getZExtValue();11606 // If the immediate value is too big for the immoffset field, put only bits11607 // that would normally fit in the immoffset field. The remaining value that11608 // is copied/added for the voffset field is a large power of 2, and it11609 // stands more chance of being CSEd with the copy/add for another similar11610 // load/store.11611 // However, do not do that rounding down if that is a negative11612 // number, as it appears to be illegal to have a negative offset in the11613 // vgpr, even if adding the immediate offset makes it positive.11614 unsigned Overflow = ImmOffset & ~MaxImm;11615 ImmOffset -= Overflow;11616 if ((int32_t)Overflow < 0) {11617 Overflow += ImmOffset;11618 ImmOffset = 0;11619 }11620 C1 = cast<ConstantSDNode>(DAG.getTargetConstant(ImmOffset, DL, MVT::i32));11621 if (Overflow) {11622 auto OverflowVal = DAG.getConstant(Overflow, DL, MVT::i32);11623 if (!N0)11624 N0 = OverflowVal;11625 else {11626 SDValue Ops[] = {N0, OverflowVal};11627 N0 = DAG.getNode(ISD::ADD, DL, MVT::i32, Ops);11628 }11629 }11630 }11631 if (!N0)11632 N0 = DAG.getConstant(0, DL, MVT::i32);11633 if (!C1)11634 C1 = cast<ConstantSDNode>(DAG.getTargetConstant(0, DL, MVT::i32));11635 return {N0, SDValue(C1, 0)};11636}11637 11638// Analyze a combined offset from an amdgcn_s_buffer_load intrinsic and store11639// the three offsets (voffset, soffset and instoffset) into the SDValue[3] array11640// pointed to by Offsets.11641void SITargetLowering::setBufferOffsets(SDValue CombinedOffset,11642 SelectionDAG &DAG, SDValue *Offsets,11643 Align Alignment) const {11644 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();11645 SDLoc DL(CombinedOffset);11646 if (auto *C = dyn_cast<ConstantSDNode>(CombinedOffset)) {11647 uint32_t Imm = C->getZExtValue();11648 uint32_t SOffset, ImmOffset;11649 if (TII->splitMUBUFOffset(Imm, SOffset, ImmOffset, Alignment)) {11650 Offsets[0] = DAG.getConstant(0, DL, MVT::i32);11651 Offsets[1] = DAG.getConstant(SOffset, DL, MVT::i32);11652 Offsets[2] = DAG.getTargetConstant(ImmOffset, DL, MVT::i32);11653 return;11654 }11655 }11656 if (DAG.isBaseWithConstantOffset(CombinedOffset)) {11657 SDValue N0 = CombinedOffset.getOperand(0);11658 SDValue N1 = CombinedOffset.getOperand(1);11659 uint32_t SOffset, ImmOffset;11660 int Offset = cast<ConstantSDNode>(N1)->getSExtValue();11661 if (Offset >= 0 &&11662 TII->splitMUBUFOffset(Offset, SOffset, ImmOffset, Alignment)) {11663 Offsets[0] = N0;11664 Offsets[1] = DAG.getConstant(SOffset, DL, MVT::i32);11665 Offsets[2] = DAG.getTargetConstant(ImmOffset, DL, MVT::i32);11666 return;11667 }11668 }11669 11670 SDValue SOffsetZero = Subtarget->hasRestrictedSOffset()11671 ? DAG.getRegister(AMDGPU::SGPR_NULL, MVT::i32)11672 : DAG.getConstant(0, DL, MVT::i32);11673 11674 Offsets[0] = CombinedOffset;11675 Offsets[1] = SOffsetZero;11676 Offsets[2] = DAG.getTargetConstant(0, DL, MVT::i32);11677}11678 11679SDValue SITargetLowering::bufferRsrcPtrToVector(SDValue MaybePointer,11680 SelectionDAG &DAG) const {11681 if (!MaybePointer.getValueType().isScalarInteger())11682 return MaybePointer;11683 11684 SDValue Rsrc = DAG.getBitcast(MVT::v4i32, MaybePointer);11685 return Rsrc;11686}11687 11688// Wrap a global or flat pointer into a buffer intrinsic using the flags11689// specified in the intrinsic.11690SDValue SITargetLowering::lowerPointerAsRsrcIntrin(SDNode *Op,11691 SelectionDAG &DAG) const {11692 SDLoc Loc(Op);11693 11694 SDValue Pointer = Op->getOperand(1);11695 SDValue Stride = Op->getOperand(2);11696 SDValue NumRecords = Op->getOperand(3);11697 SDValue Flags = Op->getOperand(4);11698 11699 SDValue ExtStride = DAG.getAnyExtOrTrunc(Stride, Loc, MVT::i32);11700 SDValue Rsrc;11701 11702 if (Subtarget->has45BitNumRecordsBufferResource()) {11703 SDValue Zero = DAG.getConstant(0, Loc, MVT::i32);11704 // Build the lower 64-bit value, which has a 57-bit base and the lower 7-bit11705 // num_records.11706 SDValue ExtPointer = DAG.getAnyExtOrTrunc(Pointer, Loc, MVT::i64);11707 SDValue NumRecordsLHS =11708 DAG.getNode(ISD::SHL, Loc, MVT::i64, NumRecords,11709 DAG.getShiftAmountConstant(57, MVT::i32, Loc));11710 SDValue LowHalf =11711 DAG.getNode(ISD::OR, Loc, MVT::i64, ExtPointer, NumRecordsLHS);11712 11713 // Build the higher 64-bit value, which has the higher 38-bit num_records,11714 // 6-bit zero (omit), 16-bit stride and scale and 4-bit flag.11715 SDValue NumRecordsRHS =11716 DAG.getNode(ISD::SRL, Loc, MVT::i64, NumRecords,11717 DAG.getShiftAmountConstant(7, MVT::i32, Loc));11718 SDValue ShiftedStride =11719 DAG.getNode(ISD::SHL, Loc, MVT::i32, ExtStride,11720 DAG.getShiftAmountConstant(12, MVT::i32, Loc));11721 SDValue ExtShiftedStrideVec =11722 DAG.getNode(ISD::BUILD_VECTOR, Loc, MVT::v2i32, Zero, ShiftedStride);11723 SDValue ExtShiftedStride =11724 DAG.getNode(ISD::BITCAST, Loc, MVT::i64, ExtShiftedStrideVec);11725 SDValue ShiftedFlags =11726 DAG.getNode(ISD::SHL, Loc, MVT::i32, Flags,11727 DAG.getShiftAmountConstant(28, MVT::i32, Loc));11728 SDValue ExtShiftedFlagsVec =11729 DAG.getNode(ISD::BUILD_VECTOR, Loc, MVT::v2i32, Zero, ShiftedFlags);11730 SDValue ExtShiftedFlags =11731 DAG.getNode(ISD::BITCAST, Loc, MVT::i64, ExtShiftedFlagsVec);11732 SDValue CombinedFields =11733 DAG.getNode(ISD::OR, Loc, MVT::i64, NumRecordsRHS, ExtShiftedStride);11734 SDValue HighHalf =11735 DAG.getNode(ISD::OR, Loc, MVT::i64, CombinedFields, ExtShiftedFlags);11736 11737 Rsrc = DAG.getNode(ISD::BUILD_VECTOR, Loc, MVT::v2i64, LowHalf, HighHalf);11738 } else {11739 NumRecords = DAG.getAnyExtOrTrunc(NumRecords, Loc, MVT::i32);11740 auto [LowHalf, HighHalf] =11741 DAG.SplitScalar(Pointer, Loc, MVT::i32, MVT::i32);11742 SDValue Mask = DAG.getConstant(0x0000ffff, Loc, MVT::i32);11743 SDValue Masked = DAG.getNode(ISD::AND, Loc, MVT::i32, HighHalf, Mask);11744 SDValue ShiftedStride =11745 DAG.getNode(ISD::SHL, Loc, MVT::i32, ExtStride,11746 DAG.getShiftAmountConstant(16, MVT::i32, Loc));11747 SDValue NewHighHalf =11748 DAG.getNode(ISD::OR, Loc, MVT::i32, Masked, ShiftedStride);11749 11750 Rsrc = DAG.getNode(ISD::BUILD_VECTOR, Loc, MVT::v4i32, LowHalf, NewHighHalf,11751 NumRecords, Flags);11752 }11753 11754 SDValue RsrcPtr = DAG.getNode(ISD::BITCAST, Loc, MVT::i128, Rsrc);11755 return RsrcPtr;11756}11757 11758// Handle 8 bit and 16 bit buffer loads11759SDValue SITargetLowering::handleByteShortBufferLoads(SelectionDAG &DAG,11760 EVT LoadVT, SDLoc DL,11761 ArrayRef<SDValue> Ops,11762 MachineMemOperand *MMO,11763 bool IsTFE) const {11764 EVT IntVT = LoadVT.changeTypeToInteger();11765 11766 if (IsTFE) {11767 unsigned Opc = (LoadVT.getScalarType() == MVT::i8)11768 ? AMDGPUISD::BUFFER_LOAD_UBYTE_TFE11769 : AMDGPUISD::BUFFER_LOAD_USHORT_TFE;11770 MachineFunction &MF = DAG.getMachineFunction();11771 MachineMemOperand *OpMMO = MF.getMachineMemOperand(MMO, 0, 8);11772 SDVTList VTs = DAG.getVTList(MVT::v2i32, MVT::Other);11773 SDValue Op = getMemIntrinsicNode(Opc, DL, VTs, Ops, MVT::v2i32, OpMMO, DAG);11774 SDValue Status = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, Op,11775 DAG.getConstant(1, DL, MVT::i32));11776 SDValue Data = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, Op,11777 DAG.getConstant(0, DL, MVT::i32));11778 SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, IntVT, Data);11779 SDValue Value = DAG.getNode(ISD::BITCAST, DL, LoadVT, Trunc);11780 return DAG.getMergeValues({Value, Status, SDValue(Op.getNode(), 1)}, DL);11781 }11782 11783 unsigned Opc = LoadVT.getScalarType() == MVT::i811784 ? AMDGPUISD::BUFFER_LOAD_UBYTE11785 : AMDGPUISD::BUFFER_LOAD_USHORT;11786 11787 SDVTList ResList = DAG.getVTList(MVT::i32, MVT::Other);11788 SDValue BufferLoad =11789 DAG.getMemIntrinsicNode(Opc, DL, ResList, Ops, IntVT, MMO);11790 SDValue LoadVal = DAG.getNode(ISD::TRUNCATE, DL, IntVT, BufferLoad);11791 LoadVal = DAG.getNode(ISD::BITCAST, DL, LoadVT, LoadVal);11792 11793 return DAG.getMergeValues({LoadVal, BufferLoad.getValue(1)}, DL);11794}11795 11796// Handle 8 bit and 16 bit buffer stores11797SDValue SITargetLowering::handleByteShortBufferStores(SelectionDAG &DAG,11798 EVT VDataType, SDLoc DL,11799 SDValue Ops[],11800 MemSDNode *M) const {11801 if (VDataType == MVT::f16 || VDataType == MVT::bf16)11802 Ops[1] = DAG.getNode(ISD::BITCAST, DL, MVT::i16, Ops[1]);11803 11804 SDValue BufferStoreExt = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Ops[1]);11805 Ops[1] = BufferStoreExt;11806 unsigned Opc = (VDataType == MVT::i8) ? AMDGPUISD::BUFFER_STORE_BYTE11807 : AMDGPUISD::BUFFER_STORE_SHORT;11808 ArrayRef<SDValue> OpsRef = ArrayRef(&Ops[0], 9);11809 return DAG.getMemIntrinsicNode(Opc, DL, M->getVTList(), OpsRef, VDataType,11810 M->getMemOperand());11811}11812 11813static SDValue getLoadExtOrTrunc(SelectionDAG &DAG, ISD::LoadExtType ExtType,11814 SDValue Op, const SDLoc &SL, EVT VT) {11815 if (VT.bitsLT(Op.getValueType()))11816 return DAG.getNode(ISD::TRUNCATE, SL, VT, Op);11817 11818 switch (ExtType) {11819 case ISD::SEXTLOAD:11820 return DAG.getNode(ISD::SIGN_EXTEND, SL, VT, Op);11821 case ISD::ZEXTLOAD:11822 return DAG.getNode(ISD::ZERO_EXTEND, SL, VT, Op);11823 case ISD::EXTLOAD:11824 return DAG.getNode(ISD::ANY_EXTEND, SL, VT, Op);11825 case ISD::NON_EXTLOAD:11826 return Op;11827 }11828 11829 llvm_unreachable("invalid ext type");11830}11831 11832// Try to turn 8 and 16-bit scalar loads into SMEM eligible 32-bit loads.11833// TODO: Skip this on GFX12 which does have scalar sub-dword loads.11834SDValue SITargetLowering::widenLoad(LoadSDNode *Ld,11835 DAGCombinerInfo &DCI) const {11836 SelectionDAG &DAG = DCI.DAG;11837 if (Ld->getAlign() < Align(4) || Ld->isDivergent())11838 return SDValue();11839 11840 // FIXME: Constant loads should all be marked invariant.11841 unsigned AS = Ld->getAddressSpace();11842 if (AS != AMDGPUAS::CONSTANT_ADDRESS &&11843 AS != AMDGPUAS::CONSTANT_ADDRESS_32BIT &&11844 (AS != AMDGPUAS::GLOBAL_ADDRESS || !Ld->isInvariant()))11845 return SDValue();11846 11847 // Don't do this early, since it may interfere with adjacent load merging for11848 // illegal types. We can avoid losing alignment information for exotic types11849 // pre-legalize.11850 EVT MemVT = Ld->getMemoryVT();11851 if ((MemVT.isSimple() && !DCI.isAfterLegalizeDAG()) ||11852 MemVT.getSizeInBits() >= 32)11853 return SDValue();11854 11855 SDLoc SL(Ld);11856 11857 assert((!MemVT.isVector() || Ld->getExtensionType() == ISD::NON_EXTLOAD) &&11858 "unexpected vector extload");11859 11860 // TODO: Drop only high part of range.11861 SDValue Ptr = Ld->getBasePtr();11862 SDValue NewLoad = DAG.getLoad(11863 ISD::UNINDEXED, ISD::NON_EXTLOAD, MVT::i32, SL, Ld->getChain(), Ptr,11864 Ld->getOffset(), Ld->getPointerInfo(), MVT::i32, Ld->getAlign(),11865 Ld->getMemOperand()->getFlags(), Ld->getAAInfo(),11866 nullptr); // Drop ranges11867 11868 EVT TruncVT = EVT::getIntegerVT(*DAG.getContext(), MemVT.getSizeInBits());11869 if (MemVT.isFloatingPoint()) {11870 assert(Ld->getExtensionType() == ISD::NON_EXTLOAD &&11871 "unexpected fp extload");11872 TruncVT = MemVT.changeTypeToInteger();11873 }11874 11875 SDValue Cvt = NewLoad;11876 if (Ld->getExtensionType() == ISD::SEXTLOAD) {11877 Cvt = DAG.getNode(ISD::SIGN_EXTEND_INREG, SL, MVT::i32, NewLoad,11878 DAG.getValueType(TruncVT));11879 } else if (Ld->getExtensionType() == ISD::ZEXTLOAD ||11880 Ld->getExtensionType() == ISD::NON_EXTLOAD) {11881 Cvt = DAG.getZeroExtendInReg(NewLoad, SL, TruncVT);11882 } else {11883 assert(Ld->getExtensionType() == ISD::EXTLOAD);11884 }11885 11886 EVT VT = Ld->getValueType(0);11887 EVT IntVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits());11888 11889 DCI.AddToWorklist(Cvt.getNode());11890 11891 // We may need to handle exotic cases, such as i16->i64 extloads, so insert11892 // the appropriate extension from the 32-bit load.11893 Cvt = getLoadExtOrTrunc(DAG, Ld->getExtensionType(), Cvt, SL, IntVT);11894 DCI.AddToWorklist(Cvt.getNode());11895 11896 // Handle conversion back to floating point if necessary.11897 Cvt = DAG.getNode(ISD::BITCAST, SL, VT, Cvt);11898 11899 return DAG.getMergeValues({Cvt, NewLoad.getValue(1)}, SL);11900}11901 11902static bool addressMayBeAccessedAsPrivate(const MachineMemOperand *MMO,11903 const SIMachineFunctionInfo &Info) {11904 // TODO: Should check if the address can definitely not access stack.11905 if (Info.isEntryFunction())11906 return Info.getUserSGPRInfo().hasFlatScratchInit();11907 return true;11908}11909 11910SDValue SITargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {11911 SDLoc DL(Op);11912 LoadSDNode *Load = cast<LoadSDNode>(Op);11913 ISD::LoadExtType ExtType = Load->getExtensionType();11914 EVT MemVT = Load->getMemoryVT();11915 MachineMemOperand *MMO = Load->getMemOperand();11916 11917 if (ExtType == ISD::NON_EXTLOAD && MemVT.getSizeInBits() < 32) {11918 if (MemVT == MVT::i16 && isTypeLegal(MVT::i16))11919 return SDValue();11920 11921 // FIXME: Copied from PPC11922 // First, load into 32 bits, then truncate to 1 bit.11923 11924 SDValue Chain = Load->getChain();11925 SDValue BasePtr = Load->getBasePtr();11926 11927 EVT RealMemVT = (MemVT == MVT::i1) ? MVT::i8 : MVT::i16;11928 11929 SDValue NewLD = DAG.getExtLoad(ISD::EXTLOAD, DL, MVT::i32, Chain, BasePtr,11930 RealMemVT, MMO);11931 11932 if (!MemVT.isVector()) {11933 SDValue Ops[] = {DAG.getNode(ISD::TRUNCATE, DL, MemVT, NewLD),11934 NewLD.getValue(1)};11935 11936 return DAG.getMergeValues(Ops, DL);11937 }11938 11939 SmallVector<SDValue, 3> Elts;11940 for (unsigned I = 0, N = MemVT.getVectorNumElements(); I != N; ++I) {11941 SDValue Elt = DAG.getNode(ISD::SRL, DL, MVT::i32, NewLD,11942 DAG.getConstant(I, DL, MVT::i32));11943 11944 Elts.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i1, Elt));11945 }11946 11947 SDValue Ops[] = {DAG.getBuildVector(MemVT, DL, Elts), NewLD.getValue(1)};11948 11949 return DAG.getMergeValues(Ops, DL);11950 }11951 11952 if (!MemVT.isVector())11953 return SDValue();11954 11955 assert(Op.getValueType().getVectorElementType() == MVT::i32 &&11956 "Custom lowering for non-i32 vectors hasn't been implemented.");11957 11958 Align Alignment = Load->getAlign();11959 unsigned AS = Load->getAddressSpace();11960 if (Subtarget->hasLDSMisalignedBug() && AS == AMDGPUAS::FLAT_ADDRESS &&11961 Alignment.value() < MemVT.getStoreSize() && MemVT.getSizeInBits() > 32) {11962 return SplitVectorLoad(Op, DAG);11963 }11964 11965 MachineFunction &MF = DAG.getMachineFunction();11966 SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();11967 // If there is a possibility that flat instruction access scratch memory11968 // then we need to use the same legalization rules we use for private.11969 if (AS == AMDGPUAS::FLAT_ADDRESS &&11970 !Subtarget->hasMultiDwordFlatScratchAddressing())11971 AS = addressMayBeAccessedAsPrivate(Load->getMemOperand(), *MFI)11972 ? AMDGPUAS::PRIVATE_ADDRESS11973 : AMDGPUAS::GLOBAL_ADDRESS;11974 11975 unsigned NumElements = MemVT.getVectorNumElements();11976 11977 if (AS == AMDGPUAS::CONSTANT_ADDRESS ||11978 AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT ||11979 (AS == AMDGPUAS::GLOBAL_ADDRESS &&11980 Subtarget->getScalarizeGlobalBehavior() && Load->isSimple() &&11981 (Load->isInvariant() || isMemOpHasNoClobberedMemOperand(Load)))) {11982 if ((!Op->isDivergent() || AMDGPU::isUniformMMO(MMO)) &&11983 Alignment >= Align(4) && NumElements < 32) {11984 if (MemVT.isPow2VectorType() ||11985 (Subtarget->hasScalarDwordx3Loads() && NumElements == 3))11986 return SDValue();11987 return WidenOrSplitVectorLoad(Op, DAG);11988 }11989 // Non-uniform loads will be selected to MUBUF instructions, so they11990 // have the same legalization requirements as global and private11991 // loads.11992 //11993 }11994 if (AS == AMDGPUAS::CONSTANT_ADDRESS ||11995 AS == AMDGPUAS::CONSTANT_ADDRESS_32BIT ||11996 AS == AMDGPUAS::GLOBAL_ADDRESS || AS == AMDGPUAS::FLAT_ADDRESS) {11997 if (NumElements > 4)11998 return SplitVectorLoad(Op, DAG);11999 // v3 loads not supported on SI.12000 if (NumElements == 3 && !Subtarget->hasDwordx3LoadStores())12001 return WidenOrSplitVectorLoad(Op, DAG);12002 12003 // v3 and v4 loads are supported for private and global memory.12004 return SDValue();12005 }12006 if (AS == AMDGPUAS::PRIVATE_ADDRESS) {12007 // Depending on the setting of the private_element_size field in the12008 // resource descriptor, we can only make private accesses up to a certain12009 // size.12010 switch (Subtarget->getMaxPrivateElementSize()) {12011 case 4: {12012 auto [Op0, Op1] = scalarizeVectorLoad(Load, DAG);12013 return DAG.getMergeValues({Op0, Op1}, DL);12014 }12015 case 8:12016 if (NumElements > 2)12017 return SplitVectorLoad(Op, DAG);12018 return SDValue();12019 case 16:12020 // Same as global/flat12021 if (NumElements > 4)12022 return SplitVectorLoad(Op, DAG);12023 // v3 loads not supported on SI.12024 if (NumElements == 3 && !Subtarget->hasDwordx3LoadStores())12025 return WidenOrSplitVectorLoad(Op, DAG);12026 12027 return SDValue();12028 default:12029 llvm_unreachable("unsupported private_element_size");12030 }12031 } else if (AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::REGION_ADDRESS) {12032 unsigned Fast = 0;12033 auto Flags = Load->getMemOperand()->getFlags();12034 if (allowsMisalignedMemoryAccessesImpl(MemVT.getSizeInBits(), AS,12035 Load->getAlign(), Flags, &Fast) &&12036 Fast > 1)12037 return SDValue();12038 12039 if (MemVT.isVector())12040 return SplitVectorLoad(Op, DAG);12041 }12042 12043 if (!allowsMemoryAccessForAlignment(*DAG.getContext(), DAG.getDataLayout(),12044 MemVT, *Load->getMemOperand())) {12045 auto [Op0, Op1] = expandUnalignedLoad(Load, DAG);12046 return DAG.getMergeValues({Op0, Op1}, DL);12047 }12048 12049 return SDValue();12050}12051 12052SDValue SITargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {12053 EVT VT = Op.getValueType();12054 if (VT.getSizeInBits() == 128 || VT.getSizeInBits() == 256 ||12055 VT.getSizeInBits() == 512)12056 return splitTernaryVectorOp(Op, DAG);12057 12058 assert(VT.getSizeInBits() == 64);12059 12060 SDLoc DL(Op);12061 SDValue Cond = DAG.getFreeze(Op.getOperand(0));12062 12063 SDValue Zero = DAG.getConstant(0, DL, MVT::i32);12064 SDValue One = DAG.getConstant(1, DL, MVT::i32);12065 12066 SDValue LHS = DAG.getNode(ISD::BITCAST, DL, MVT::v2i32, Op.getOperand(1));12067 SDValue RHS = DAG.getNode(ISD::BITCAST, DL, MVT::v2i32, Op.getOperand(2));12068 12069 SDValue Lo0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, LHS, Zero);12070 SDValue Lo1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, RHS, Zero);12071 12072 SDValue Lo = DAG.getSelect(DL, MVT::i32, Cond, Lo0, Lo1);12073 12074 SDValue Hi0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, LHS, One);12075 SDValue Hi1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i32, RHS, One);12076 12077 SDValue Hi = DAG.getSelect(DL, MVT::i32, Cond, Hi0, Hi1);12078 12079 SDValue Res = DAG.getBuildVector(MVT::v2i32, DL, {Lo, Hi});12080 return DAG.getNode(ISD::BITCAST, DL, VT, Res);12081}12082 12083// Catch division cases where we can use shortcuts with rcp and rsq12084// instructions.12085SDValue SITargetLowering::lowerFastUnsafeFDIV(SDValue Op,12086 SelectionDAG &DAG) const {12087 SDLoc SL(Op);12088 SDValue LHS = Op.getOperand(0);12089 SDValue RHS = Op.getOperand(1);12090 EVT VT = Op.getValueType();12091 const SDNodeFlags Flags = Op->getFlags();12092 12093 bool AllowInaccurateRcp = Flags.hasApproximateFuncs();12094 12095 if (const ConstantFPSDNode *CLHS = dyn_cast<ConstantFPSDNode>(LHS)) {12096 // Without !fpmath accuracy information, we can't do more because we don't12097 // know exactly whether rcp is accurate enough to meet !fpmath requirement.12098 // f16 is always accurate enough12099 if (!AllowInaccurateRcp && VT != MVT::f16 && VT != MVT::bf16)12100 return SDValue();12101 12102 if (CLHS->isExactlyValue(1.0)) {12103 // v_rcp_f32 and v_rsq_f32 do not support denormals, and according to12104 // the CI documentation has a worst case error of 1 ulp.12105 // OpenCL requires <= 2.5 ulp for 1.0 / x, so it should always be OK to12106 // use it as long as we aren't trying to use denormals.12107 //12108 // v_rcp_f16 and v_rsq_f16 DO support denormals and 0.51ulp.12109 12110 // 1.0 / sqrt(x) -> rsq(x)12111 12112 // XXX - Is afn sufficient to do this for f64? The maximum ULP12113 // error seems really high at 2^29 ULP.12114 // 1.0 / x -> rcp(x)12115 return DAG.getNode(AMDGPUISD::RCP, SL, VT, RHS);12116 }12117 12118 // Same as for 1.0, but expand the sign out of the constant.12119 if (CLHS->isExactlyValue(-1.0)) {12120 // -1.0 / x -> rcp (fneg x)12121 SDValue FNegRHS = DAG.getNode(ISD::FNEG, SL, VT, RHS);12122 return DAG.getNode(AMDGPUISD::RCP, SL, VT, FNegRHS);12123 }12124 }12125 12126 // For f16 and bf16 require afn or arcp.12127 // For f32 require afn.12128 if (!AllowInaccurateRcp &&12129 ((VT != MVT::f16 && VT != MVT::bf16) || !Flags.hasAllowReciprocal()))12130 return SDValue();12131 12132 // Turn into multiply by the reciprocal.12133 // x / y -> x * (1.0 / y)12134 SDValue Recip = DAG.getNode(AMDGPUISD::RCP, SL, VT, RHS);12135 return DAG.getNode(ISD::FMUL, SL, VT, LHS, Recip, Flags);12136}12137 12138SDValue SITargetLowering::lowerFastUnsafeFDIV64(SDValue Op,12139 SelectionDAG &DAG) const {12140 SDLoc SL(Op);12141 SDValue X = Op.getOperand(0);12142 SDValue Y = Op.getOperand(1);12143 EVT VT = Op.getValueType();12144 const SDNodeFlags Flags = Op->getFlags();12145 12146 bool AllowInaccurateDiv = Flags.hasApproximateFuncs();12147 if (!AllowInaccurateDiv)12148 return SDValue();12149 12150 SDValue NegY = DAG.getNode(ISD::FNEG, SL, VT, Y);12151 SDValue One = DAG.getConstantFP(1.0, SL, VT);12152 12153 SDValue R = DAG.getNode(AMDGPUISD::RCP, SL, VT, Y);12154 SDValue Tmp0 = DAG.getNode(ISD::FMA, SL, VT, NegY, R, One);12155 12156 R = DAG.getNode(ISD::FMA, SL, VT, Tmp0, R, R);12157 SDValue Tmp1 = DAG.getNode(ISD::FMA, SL, VT, NegY, R, One);12158 R = DAG.getNode(ISD::FMA, SL, VT, Tmp1, R, R);12159 SDValue Ret = DAG.getNode(ISD::FMUL, SL, VT, X, R);12160 SDValue Tmp2 = DAG.getNode(ISD::FMA, SL, VT, NegY, Ret, X);12161 return DAG.getNode(ISD::FMA, SL, VT, Tmp2, R, Ret);12162}12163 12164static SDValue getFPBinOp(SelectionDAG &DAG, unsigned Opcode, const SDLoc &SL,12165 EVT VT, SDValue A, SDValue B, SDValue GlueChain,12166 SDNodeFlags Flags) {12167 if (GlueChain->getNumValues() <= 1) {12168 return DAG.getNode(Opcode, SL, VT, A, B, Flags);12169 }12170 12171 assert(GlueChain->getNumValues() == 3);12172 12173 SDVTList VTList = DAG.getVTList(VT, MVT::Other, MVT::Glue);12174 switch (Opcode) {12175 default:12176 llvm_unreachable("no chain equivalent for opcode");12177 case ISD::FMUL:12178 Opcode = AMDGPUISD::FMUL_W_CHAIN;12179 break;12180 }12181 12182 return DAG.getNode(Opcode, SL, VTList,12183 {GlueChain.getValue(1), A, B, GlueChain.getValue(2)},12184 Flags);12185}12186 12187static SDValue getFPTernOp(SelectionDAG &DAG, unsigned Opcode, const SDLoc &SL,12188 EVT VT, SDValue A, SDValue B, SDValue C,12189 SDValue GlueChain, SDNodeFlags Flags) {12190 if (GlueChain->getNumValues() <= 1) {12191 return DAG.getNode(Opcode, SL, VT, {A, B, C}, Flags);12192 }12193 12194 assert(GlueChain->getNumValues() == 3);12195 12196 SDVTList VTList = DAG.getVTList(VT, MVT::Other, MVT::Glue);12197 switch (Opcode) {12198 default:12199 llvm_unreachable("no chain equivalent for opcode");12200 case ISD::FMA:12201 Opcode = AMDGPUISD::FMA_W_CHAIN;12202 break;12203 }12204 12205 return DAG.getNode(Opcode, SL, VTList,12206 {GlueChain.getValue(1), A, B, C, GlueChain.getValue(2)},12207 Flags);12208}12209 12210SDValue SITargetLowering::LowerFDIV16(SDValue Op, SelectionDAG &DAG) const {12211 if (SDValue FastLowered = lowerFastUnsafeFDIV(Op, DAG))12212 return FastLowered;12213 12214 SDLoc SL(Op);12215 EVT VT = Op.getValueType();12216 SDValue LHS = Op.getOperand(0);12217 SDValue RHS = Op.getOperand(1);12218 12219 SDValue LHSExt = DAG.getNode(ISD::FP_EXTEND, SL, MVT::f32, LHS);12220 SDValue RHSExt = DAG.getNode(ISD::FP_EXTEND, SL, MVT::f32, RHS);12221 12222 if (VT == MVT::bf16) {12223 SDValue ExtDiv =12224 DAG.getNode(ISD::FDIV, SL, MVT::f32, LHSExt, RHSExt, Op->getFlags());12225 return DAG.getNode(ISD::FP_ROUND, SL, MVT::bf16, ExtDiv,12226 DAG.getTargetConstant(0, SL, MVT::i32));12227 }12228 12229 assert(VT == MVT::f16);12230 12231 // a32.u = opx(V_CVT_F32_F16, a.u); // CVT to F3212232 // b32.u = opx(V_CVT_F32_F16, b.u); // CVT to F3212233 // r32.u = opx(V_RCP_F32, b32.u); // rcp = 1 / d12234 // q32.u = opx(V_MUL_F32, a32.u, r32.u); // q = n * rcp12235 // e32.u = opx(V_MAD_F32, (b32.u^_neg32), q32.u, a32.u); // err = -d * q + n12236 // q32.u = opx(V_MAD_F32, e32.u, r32.u, q32.u); // q = n * rcp12237 // e32.u = opx(V_MAD_F32, (b32.u^_neg32), q32.u, a32.u); // err = -d * q + n12238 // tmp.u = opx(V_MUL_F32, e32.u, r32.u);12239 // tmp.u = opx(V_AND_B32, tmp.u, 0xff800000)12240 // q32.u = opx(V_ADD_F32, tmp.u, q32.u);12241 // q16.u = opx(V_CVT_F16_F32, q32.u);12242 // q16.u = opx(V_DIV_FIXUP_F16, q16.u, b.u, a.u); // q = touchup(q, d, n)12243 12244 // We will use ISD::FMA on targets that don't support ISD::FMAD.12245 unsigned FMADOpCode =12246 isOperationLegal(ISD::FMAD, MVT::f32) ? ISD::FMAD : ISD::FMA;12247 SDValue NegRHSExt = DAG.getNode(ISD::FNEG, SL, MVT::f32, RHSExt);12248 SDValue Rcp =12249 DAG.getNode(AMDGPUISD::RCP, SL, MVT::f32, RHSExt, Op->getFlags());12250 SDValue Quot =12251 DAG.getNode(ISD::FMUL, SL, MVT::f32, LHSExt, Rcp, Op->getFlags());12252 SDValue Err = DAG.getNode(FMADOpCode, SL, MVT::f32, NegRHSExt, Quot, LHSExt,12253 Op->getFlags());12254 Quot = DAG.getNode(FMADOpCode, SL, MVT::f32, Err, Rcp, Quot, Op->getFlags());12255 Err = DAG.getNode(FMADOpCode, SL, MVT::f32, NegRHSExt, Quot, LHSExt,12256 Op->getFlags());12257 SDValue Tmp = DAG.getNode(ISD::FMUL, SL, MVT::f32, Err, Rcp, Op->getFlags());12258 SDValue TmpCast = DAG.getNode(ISD::BITCAST, SL, MVT::i32, Tmp);12259 TmpCast = DAG.getNode(ISD::AND, SL, MVT::i32, TmpCast,12260 DAG.getConstant(0xff800000, SL, MVT::i32));12261 Tmp = DAG.getNode(ISD::BITCAST, SL, MVT::f32, TmpCast);12262 Quot = DAG.getNode(ISD::FADD, SL, MVT::f32, Tmp, Quot, Op->getFlags());12263 SDValue RDst = DAG.getNode(ISD::FP_ROUND, SL, MVT::f16, Quot,12264 DAG.getTargetConstant(0, SL, MVT::i32));12265 return DAG.getNode(AMDGPUISD::DIV_FIXUP, SL, MVT::f16, RDst, RHS, LHS,12266 Op->getFlags());12267}12268 12269// Faster 2.5 ULP division that does not support denormals.12270SDValue SITargetLowering::lowerFDIV_FAST(SDValue Op, SelectionDAG &DAG) const {12271 SDNodeFlags Flags = Op->getFlags();12272 SDLoc SL(Op);12273 SDValue LHS = Op.getOperand(1);12274 SDValue RHS = Op.getOperand(2);12275 12276 SDValue r1 = DAG.getNode(ISD::FABS, SL, MVT::f32, RHS, Flags);12277 12278 const APFloat K0Val(0x1p+96f);12279 const SDValue K0 = DAG.getConstantFP(K0Val, SL, MVT::f32);12280 12281 const APFloat K1Val(0x1p-32f);12282 const SDValue K1 = DAG.getConstantFP(K1Val, SL, MVT::f32);12283 12284 const SDValue One = DAG.getConstantFP(1.0, SL, MVT::f32);12285 12286 EVT SetCCVT =12287 getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), MVT::f32);12288 12289 SDValue r2 = DAG.getSetCC(SL, SetCCVT, r1, K0, ISD::SETOGT);12290 12291 SDValue r3 = DAG.getNode(ISD::SELECT, SL, MVT::f32, r2, K1, One, Flags);12292 12293 r1 = DAG.getNode(ISD::FMUL, SL, MVT::f32, RHS, r3, Flags);12294 12295 // rcp does not support denormals.12296 SDValue r0 = DAG.getNode(AMDGPUISD::RCP, SL, MVT::f32, r1, Flags);12297 12298 SDValue Mul = DAG.getNode(ISD::FMUL, SL, MVT::f32, LHS, r0, Flags);12299 12300 return DAG.getNode(ISD::FMUL, SL, MVT::f32, r3, Mul, Flags);12301}12302 12303// Returns immediate value for setting the F32 denorm mode when using the12304// S_DENORM_MODE instruction.12305static SDValue getSPDenormModeValue(uint32_t SPDenormMode, SelectionDAG &DAG,12306 const SIMachineFunctionInfo *Info,12307 const GCNSubtarget *ST) {12308 assert(ST->hasDenormModeInst() && "Requires S_DENORM_MODE");12309 uint32_t DPDenormModeDefault = Info->getMode().fpDenormModeDPValue();12310 uint32_t Mode = SPDenormMode | (DPDenormModeDefault << 2);12311 return DAG.getTargetConstant(Mode, SDLoc(), MVT::i32);12312}12313 12314SDValue SITargetLowering::LowerFDIV32(SDValue Op, SelectionDAG &DAG) const {12315 if (SDValue FastLowered = lowerFastUnsafeFDIV(Op, DAG))12316 return FastLowered;12317 12318 // The selection matcher assumes anything with a chain selecting to a12319 // mayRaiseFPException machine instruction. Since we're introducing a chain12320 // here, we need to explicitly report nofpexcept for the regular fdiv12321 // lowering.12322 SDNodeFlags Flags = Op->getFlags();12323 Flags.setNoFPExcept(true);12324 12325 SDLoc SL(Op);12326 SDValue LHS = Op.getOperand(0);12327 SDValue RHS = Op.getOperand(1);12328 12329 const SDValue One = DAG.getConstantFP(1.0, SL, MVT::f32);12330 12331 SDVTList ScaleVT = DAG.getVTList(MVT::f32, MVT::i1);12332 12333 SDValue DenominatorScaled =12334 DAG.getNode(AMDGPUISD::DIV_SCALE, SL, ScaleVT, {RHS, RHS, LHS}, Flags);12335 SDValue NumeratorScaled =12336 DAG.getNode(AMDGPUISD::DIV_SCALE, SL, ScaleVT, {LHS, RHS, LHS}, Flags);12337 12338 // Denominator is scaled to not be denormal, so using rcp is ok.12339 SDValue ApproxRcp =12340 DAG.getNode(AMDGPUISD::RCP, SL, MVT::f32, DenominatorScaled, Flags);12341 SDValue NegDivScale0 =12342 DAG.getNode(ISD::FNEG, SL, MVT::f32, DenominatorScaled, Flags);12343 12344 using namespace AMDGPU::Hwreg;12345 const unsigned Denorm32Reg = HwregEncoding::encode(ID_MODE, 4, 2);12346 const SDValue BitField = DAG.getTargetConstant(Denorm32Reg, SL, MVT::i32);12347 12348 const MachineFunction &MF = DAG.getMachineFunction();12349 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();12350 const DenormalMode DenormMode = Info->getMode().FP32Denormals;12351 12352 const bool PreservesDenormals = DenormMode == DenormalMode::getIEEE();12353 const bool HasDynamicDenormals =12354 (DenormMode.Input == DenormalMode::Dynamic) ||12355 (DenormMode.Output == DenormalMode::Dynamic);12356 12357 SDValue SavedDenormMode;12358 12359 if (!PreservesDenormals) {12360 // Note we can't use the STRICT_FMA/STRICT_FMUL for the non-strict FDIV12361 // lowering. The chain dependence is insufficient, and we need glue. We do12362 // not need the glue variants in a strictfp function.12363 12364 SDVTList BindParamVTs = DAG.getVTList(MVT::Other, MVT::Glue);12365 12366 SDValue Glue = DAG.getEntryNode();12367 if (HasDynamicDenormals) {12368 SDNode *GetReg = DAG.getMachineNode(AMDGPU::S_GETREG_B32, SL,12369 DAG.getVTList(MVT::i32, MVT::Glue),12370 {BitField, Glue});12371 SavedDenormMode = SDValue(GetReg, 0);12372 12373 Glue = DAG.getMergeValues(12374 {DAG.getEntryNode(), SDValue(GetReg, 0), SDValue(GetReg, 1)}, SL);12375 }12376 12377 SDNode *EnableDenorm;12378 if (Subtarget->hasDenormModeInst()) {12379 const SDValue EnableDenormValue =12380 getSPDenormModeValue(FP_DENORM_FLUSH_NONE, DAG, Info, Subtarget);12381 12382 EnableDenorm = DAG.getNode(AMDGPUISD::DENORM_MODE, SL, BindParamVTs, Glue,12383 EnableDenormValue)12384 .getNode();12385 } else {12386 const SDValue EnableDenormValue =12387 DAG.getConstant(FP_DENORM_FLUSH_NONE, SL, MVT::i32);12388 EnableDenorm = DAG.getMachineNode(AMDGPU::S_SETREG_B32, SL, BindParamVTs,12389 {EnableDenormValue, BitField, Glue});12390 }12391 12392 SDValue Ops[3] = {NegDivScale0, SDValue(EnableDenorm, 0),12393 SDValue(EnableDenorm, 1)};12394 12395 NegDivScale0 = DAG.getMergeValues(Ops, SL);12396 }12397 12398 SDValue Fma0 = getFPTernOp(DAG, ISD::FMA, SL, MVT::f32, NegDivScale0,12399 ApproxRcp, One, NegDivScale0, Flags);12400 12401 SDValue Fma1 = getFPTernOp(DAG, ISD::FMA, SL, MVT::f32, Fma0, ApproxRcp,12402 ApproxRcp, Fma0, Flags);12403 12404 SDValue Mul = getFPBinOp(DAG, ISD::FMUL, SL, MVT::f32, NumeratorScaled, Fma1,12405 Fma1, Flags);12406 12407 SDValue Fma2 = getFPTernOp(DAG, ISD::FMA, SL, MVT::f32, NegDivScale0, Mul,12408 NumeratorScaled, Mul, Flags);12409 12410 SDValue Fma3 =12411 getFPTernOp(DAG, ISD::FMA, SL, MVT::f32, Fma2, Fma1, Mul, Fma2, Flags);12412 12413 SDValue Fma4 = getFPTernOp(DAG, ISD::FMA, SL, MVT::f32, NegDivScale0, Fma3,12414 NumeratorScaled, Fma3, Flags);12415 12416 if (!PreservesDenormals) {12417 SDNode *DisableDenorm;12418 if (!HasDynamicDenormals && Subtarget->hasDenormModeInst()) {12419 const SDValue DisableDenormValue = getSPDenormModeValue(12420 FP_DENORM_FLUSH_IN_FLUSH_OUT, DAG, Info, Subtarget);12421 12422 SDVTList BindParamVTs = DAG.getVTList(MVT::Other, MVT::Glue);12423 DisableDenorm =12424 DAG.getNode(AMDGPUISD::DENORM_MODE, SL, BindParamVTs,12425 Fma4.getValue(1), DisableDenormValue, Fma4.getValue(2))12426 .getNode();12427 } else {12428 assert(HasDynamicDenormals == (bool)SavedDenormMode);12429 const SDValue DisableDenormValue =12430 HasDynamicDenormals12431 ? SavedDenormMode12432 : DAG.getConstant(FP_DENORM_FLUSH_IN_FLUSH_OUT, SL, MVT::i32);12433 12434 DisableDenorm = DAG.getMachineNode(12435 AMDGPU::S_SETREG_B32, SL, MVT::Other,12436 {DisableDenormValue, BitField, Fma4.getValue(1), Fma4.getValue(2)});12437 }12438 12439 SDValue OutputChain = DAG.getNode(ISD::TokenFactor, SL, MVT::Other,12440 SDValue(DisableDenorm, 0), DAG.getRoot());12441 DAG.setRoot(OutputChain);12442 }12443 12444 SDValue Scale = NumeratorScaled.getValue(1);12445 SDValue Fmas = DAG.getNode(AMDGPUISD::DIV_FMAS, SL, MVT::f32,12446 {Fma4, Fma1, Fma3, Scale}, Flags);12447 12448 return DAG.getNode(AMDGPUISD::DIV_FIXUP, SL, MVT::f32, Fmas, RHS, LHS, Flags);12449}12450 12451SDValue SITargetLowering::LowerFDIV64(SDValue Op, SelectionDAG &DAG) const {12452 if (SDValue FastLowered = lowerFastUnsafeFDIV64(Op, DAG))12453 return FastLowered;12454 12455 SDLoc SL(Op);12456 SDValue X = Op.getOperand(0);12457 SDValue Y = Op.getOperand(1);12458 12459 const SDValue One = DAG.getConstantFP(1.0, SL, MVT::f64);12460 12461 SDVTList ScaleVT = DAG.getVTList(MVT::f64, MVT::i1);12462 12463 SDValue DivScale0 = DAG.getNode(AMDGPUISD::DIV_SCALE, SL, ScaleVT, Y, Y, X);12464 12465 SDValue NegDivScale0 = DAG.getNode(ISD::FNEG, SL, MVT::f64, DivScale0);12466 12467 SDValue Rcp = DAG.getNode(AMDGPUISD::RCP, SL, MVT::f64, DivScale0);12468 12469 SDValue Fma0 = DAG.getNode(ISD::FMA, SL, MVT::f64, NegDivScale0, Rcp, One);12470 12471 SDValue Fma1 = DAG.getNode(ISD::FMA, SL, MVT::f64, Rcp, Fma0, Rcp);12472 12473 SDValue Fma2 = DAG.getNode(ISD::FMA, SL, MVT::f64, NegDivScale0, Fma1, One);12474 12475 SDValue DivScale1 = DAG.getNode(AMDGPUISD::DIV_SCALE, SL, ScaleVT, X, Y, X);12476 12477 SDValue Fma3 = DAG.getNode(ISD::FMA, SL, MVT::f64, Fma1, Fma2, Fma1);12478 SDValue Mul = DAG.getNode(ISD::FMUL, SL, MVT::f64, DivScale1, Fma3);12479 12480 SDValue Fma4 =12481 DAG.getNode(ISD::FMA, SL, MVT::f64, NegDivScale0, Mul, DivScale1);12482 12483 SDValue Scale;12484 12485 if (!Subtarget->hasUsableDivScaleConditionOutput()) {12486 // Workaround a hardware bug on SI where the condition output from div_scale12487 // is not usable.12488 12489 const SDValue Hi = DAG.getConstant(1, SL, MVT::i32);12490 12491 // Figure out if the scale to use for div_fmas.12492 SDValue NumBC = DAG.getNode(ISD::BITCAST, SL, MVT::v2i32, X);12493 SDValue DenBC = DAG.getNode(ISD::BITCAST, SL, MVT::v2i32, Y);12494 SDValue Scale0BC = DAG.getNode(ISD::BITCAST, SL, MVT::v2i32, DivScale0);12495 SDValue Scale1BC = DAG.getNode(ISD::BITCAST, SL, MVT::v2i32, DivScale1);12496 12497 SDValue NumHi =12498 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, NumBC, Hi);12499 SDValue DenHi =12500 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, DenBC, Hi);12501 12502 SDValue Scale0Hi =12503 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, Scale0BC, Hi);12504 SDValue Scale1Hi =12505 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, Scale1BC, Hi);12506 12507 SDValue CmpDen = DAG.getSetCC(SL, MVT::i1, DenHi, Scale0Hi, ISD::SETEQ);12508 SDValue CmpNum = DAG.getSetCC(SL, MVT::i1, NumHi, Scale1Hi, ISD::SETEQ);12509 Scale = DAG.getNode(ISD::XOR, SL, MVT::i1, CmpNum, CmpDen);12510 } else {12511 Scale = DivScale1.getValue(1);12512 }12513 12514 SDValue Fmas =12515 DAG.getNode(AMDGPUISD::DIV_FMAS, SL, MVT::f64, Fma4, Fma3, Mul, Scale);12516 12517 return DAG.getNode(AMDGPUISD::DIV_FIXUP, SL, MVT::f64, Fmas, Y, X);12518}12519 12520SDValue SITargetLowering::LowerFDIV(SDValue Op, SelectionDAG &DAG) const {12521 EVT VT = Op.getValueType();12522 12523 if (VT == MVT::f32)12524 return LowerFDIV32(Op, DAG);12525 12526 if (VT == MVT::f64)12527 return LowerFDIV64(Op, DAG);12528 12529 if (VT == MVT::f16 || VT == MVT::bf16)12530 return LowerFDIV16(Op, DAG);12531 12532 llvm_unreachable("Unexpected type for fdiv");12533}12534 12535SDValue SITargetLowering::LowerFFREXP(SDValue Op, SelectionDAG &DAG) const {12536 SDLoc dl(Op);12537 SDValue Val = Op.getOperand(0);12538 EVT VT = Val.getValueType();12539 EVT ResultExpVT = Op->getValueType(1);12540 EVT InstrExpVT = VT == MVT::f16 ? MVT::i16 : MVT::i32;12541 12542 SDValue Mant = DAG.getNode(12543 ISD::INTRINSIC_WO_CHAIN, dl, VT,12544 DAG.getTargetConstant(Intrinsic::amdgcn_frexp_mant, dl, MVT::i32), Val);12545 12546 SDValue Exp = DAG.getNode(12547 ISD::INTRINSIC_WO_CHAIN, dl, InstrExpVT,12548 DAG.getTargetConstant(Intrinsic::amdgcn_frexp_exp, dl, MVT::i32), Val);12549 12550 if (Subtarget->hasFractBug()) {12551 SDValue Fabs = DAG.getNode(ISD::FABS, dl, VT, Val);12552 SDValue Inf =12553 DAG.getConstantFP(APFloat::getInf(VT.getFltSemantics()), dl, VT);12554 12555 SDValue IsFinite = DAG.getSetCC(dl, MVT::i1, Fabs, Inf, ISD::SETOLT);12556 SDValue Zero = DAG.getConstant(0, dl, InstrExpVT);12557 Exp = DAG.getNode(ISD::SELECT, dl, InstrExpVT, IsFinite, Exp, Zero);12558 Mant = DAG.getNode(ISD::SELECT, dl, VT, IsFinite, Mant, Val);12559 }12560 12561 SDValue CastExp = DAG.getSExtOrTrunc(Exp, dl, ResultExpVT);12562 return DAG.getMergeValues({Mant, CastExp}, dl);12563}12564 12565SDValue SITargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const {12566 SDLoc DL(Op);12567 StoreSDNode *Store = cast<StoreSDNode>(Op);12568 EVT VT = Store->getMemoryVT();12569 12570 if (VT == MVT::i1) {12571 return DAG.getTruncStore(12572 Store->getChain(), DL,12573 DAG.getSExtOrTrunc(Store->getValue(), DL, MVT::i32),12574 Store->getBasePtr(), MVT::i1, Store->getMemOperand());12575 }12576 12577 assert(VT.isVector() &&12578 Store->getValue().getValueType().getScalarType() == MVT::i32);12579 12580 unsigned AS = Store->getAddressSpace();12581 if (Subtarget->hasLDSMisalignedBug() && AS == AMDGPUAS::FLAT_ADDRESS &&12582 Store->getAlign().value() < VT.getStoreSize() &&12583 VT.getSizeInBits() > 32) {12584 return SplitVectorStore(Op, DAG);12585 }12586 12587 MachineFunction &MF = DAG.getMachineFunction();12588 SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();12589 // If there is a possibility that flat instruction access scratch memory12590 // then we need to use the same legalization rules we use for private.12591 if (AS == AMDGPUAS::FLAT_ADDRESS &&12592 !Subtarget->hasMultiDwordFlatScratchAddressing())12593 AS = addressMayBeAccessedAsPrivate(Store->getMemOperand(), *MFI)12594 ? AMDGPUAS::PRIVATE_ADDRESS12595 : AMDGPUAS::GLOBAL_ADDRESS;12596 12597 unsigned NumElements = VT.getVectorNumElements();12598 if (AS == AMDGPUAS::GLOBAL_ADDRESS || AS == AMDGPUAS::FLAT_ADDRESS) {12599 if (NumElements > 4)12600 return SplitVectorStore(Op, DAG);12601 // v3 stores not supported on SI.12602 if (NumElements == 3 && !Subtarget->hasDwordx3LoadStores())12603 return SplitVectorStore(Op, DAG);12604 12605 if (!allowsMemoryAccessForAlignment(*DAG.getContext(), DAG.getDataLayout(),12606 VT, *Store->getMemOperand()))12607 return expandUnalignedStore(Store, DAG);12608 12609 return SDValue();12610 }12611 if (AS == AMDGPUAS::PRIVATE_ADDRESS) {12612 switch (Subtarget->getMaxPrivateElementSize()) {12613 case 4:12614 return scalarizeVectorStore(Store, DAG);12615 case 8:12616 if (NumElements > 2)12617 return SplitVectorStore(Op, DAG);12618 return SDValue();12619 case 16:12620 if (NumElements > 4 ||12621 (NumElements == 3 && !Subtarget->enableFlatScratch()))12622 return SplitVectorStore(Op, DAG);12623 return SDValue();12624 default:12625 llvm_unreachable("unsupported private_element_size");12626 }12627 } else if (AS == AMDGPUAS::LOCAL_ADDRESS || AS == AMDGPUAS::REGION_ADDRESS) {12628 unsigned Fast = 0;12629 auto Flags = Store->getMemOperand()->getFlags();12630 if (allowsMisalignedMemoryAccessesImpl(VT.getSizeInBits(), AS,12631 Store->getAlign(), Flags, &Fast) &&12632 Fast > 1)12633 return SDValue();12634 12635 if (VT.isVector())12636 return SplitVectorStore(Op, DAG);12637 12638 return expandUnalignedStore(Store, DAG);12639 }12640 12641 // Probably an invalid store. If so we'll end up emitting a selection error.12642 return SDValue();12643}12644 12645// Avoid the full correct expansion for f32 sqrt when promoting from f16.12646SDValue SITargetLowering::lowerFSQRTF16(SDValue Op, SelectionDAG &DAG) const {12647 SDLoc SL(Op);12648 assert(!Subtarget->has16BitInsts());12649 SDNodeFlags Flags = Op->getFlags();12650 SDValue Ext =12651 DAG.getNode(ISD::FP_EXTEND, SL, MVT::f32, Op.getOperand(0), Flags);12652 12653 SDValue SqrtID = DAG.getTargetConstant(Intrinsic::amdgcn_sqrt, SL, MVT::i32);12654 SDValue Sqrt =12655 DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, MVT::f32, SqrtID, Ext, Flags);12656 12657 return DAG.getNode(ISD::FP_ROUND, SL, MVT::f16, Sqrt,12658 DAG.getTargetConstant(0, SL, MVT::i32), Flags);12659}12660 12661SDValue SITargetLowering::lowerFSQRTF32(SDValue Op, SelectionDAG &DAG) const {12662 SDLoc DL(Op);12663 SDNodeFlags Flags = Op->getFlags();12664 MVT VT = Op.getValueType().getSimpleVT();12665 const SDValue X = Op.getOperand(0);12666 12667 if (allowApproxFunc(DAG, Flags)) {12668 // Instruction is 1ulp but ignores denormals.12669 return DAG.getNode(12670 ISD::INTRINSIC_WO_CHAIN, DL, VT,12671 DAG.getTargetConstant(Intrinsic::amdgcn_sqrt, DL, MVT::i32), X, Flags);12672 }12673 12674 SDValue ScaleThreshold = DAG.getConstantFP(0x1.0p-96f, DL, VT);12675 SDValue NeedScale = DAG.getSetCC(DL, MVT::i1, X, ScaleThreshold, ISD::SETOLT);12676 12677 SDValue ScaleUpFactor = DAG.getConstantFP(0x1.0p+32f, DL, VT);12678 12679 SDValue ScaledX = DAG.getNode(ISD::FMUL, DL, VT, X, ScaleUpFactor, Flags);12680 12681 SDValue SqrtX =12682 DAG.getNode(ISD::SELECT, DL, VT, NeedScale, ScaledX, X, Flags);12683 12684 SDValue SqrtS;12685 if (needsDenormHandlingF32(DAG, X, Flags)) {12686 SDValue SqrtID =12687 DAG.getTargetConstant(Intrinsic::amdgcn_sqrt, DL, MVT::i32);12688 SqrtS = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, VT, SqrtID, SqrtX, Flags);12689 12690 SDValue SqrtSAsInt = DAG.getNode(ISD::BITCAST, DL, MVT::i32, SqrtS);12691 SDValue SqrtSNextDownInt =12692 DAG.getNode(ISD::ADD, DL, MVT::i32, SqrtSAsInt,12693 DAG.getAllOnesConstant(DL, MVT::i32));12694 SDValue SqrtSNextDown = DAG.getNode(ISD::BITCAST, DL, VT, SqrtSNextDownInt);12695 12696 SDValue NegSqrtSNextDown =12697 DAG.getNode(ISD::FNEG, DL, VT, SqrtSNextDown, Flags);12698 12699 SDValue SqrtVP =12700 DAG.getNode(ISD::FMA, DL, VT, NegSqrtSNextDown, SqrtS, SqrtX, Flags);12701 12702 SDValue SqrtSNextUpInt = DAG.getNode(ISD::ADD, DL, MVT::i32, SqrtSAsInt,12703 DAG.getConstant(1, DL, MVT::i32));12704 SDValue SqrtSNextUp = DAG.getNode(ISD::BITCAST, DL, VT, SqrtSNextUpInt);12705 12706 SDValue NegSqrtSNextUp = DAG.getNode(ISD::FNEG, DL, VT, SqrtSNextUp, Flags);12707 SDValue SqrtVS =12708 DAG.getNode(ISD::FMA, DL, VT, NegSqrtSNextUp, SqrtS, SqrtX, Flags);12709 12710 SDValue Zero = DAG.getConstantFP(0.0f, DL, VT);12711 SDValue SqrtVPLE0 = DAG.getSetCC(DL, MVT::i1, SqrtVP, Zero, ISD::SETOLE);12712 12713 SqrtS = DAG.getNode(ISD::SELECT, DL, VT, SqrtVPLE0, SqrtSNextDown, SqrtS,12714 Flags);12715 12716 SDValue SqrtVPVSGT0 = DAG.getSetCC(DL, MVT::i1, SqrtVS, Zero, ISD::SETOGT);12717 SqrtS = DAG.getNode(ISD::SELECT, DL, VT, SqrtVPVSGT0, SqrtSNextUp, SqrtS,12718 Flags);12719 } else {12720 SDValue SqrtR = DAG.getNode(AMDGPUISD::RSQ, DL, VT, SqrtX, Flags);12721 12722 SqrtS = DAG.getNode(ISD::FMUL, DL, VT, SqrtX, SqrtR, Flags);12723 12724 SDValue Half = DAG.getConstantFP(0.5f, DL, VT);12725 SDValue SqrtH = DAG.getNode(ISD::FMUL, DL, VT, SqrtR, Half, Flags);12726 SDValue NegSqrtH = DAG.getNode(ISD::FNEG, DL, VT, SqrtH, Flags);12727 12728 SDValue SqrtE = DAG.getNode(ISD::FMA, DL, VT, NegSqrtH, SqrtS, Half, Flags);12729 SqrtH = DAG.getNode(ISD::FMA, DL, VT, SqrtH, SqrtE, SqrtH, Flags);12730 SqrtS = DAG.getNode(ISD::FMA, DL, VT, SqrtS, SqrtE, SqrtS, Flags);12731 12732 SDValue NegSqrtS = DAG.getNode(ISD::FNEG, DL, VT, SqrtS, Flags);12733 SDValue SqrtD =12734 DAG.getNode(ISD::FMA, DL, VT, NegSqrtS, SqrtS, SqrtX, Flags);12735 SqrtS = DAG.getNode(ISD::FMA, DL, VT, SqrtD, SqrtH, SqrtS, Flags);12736 }12737 12738 SDValue ScaleDownFactor = DAG.getConstantFP(0x1.0p-16f, DL, VT);12739 12740 SDValue ScaledDown =12741 DAG.getNode(ISD::FMUL, DL, VT, SqrtS, ScaleDownFactor, Flags);12742 12743 SqrtS = DAG.getNode(ISD::SELECT, DL, VT, NeedScale, ScaledDown, SqrtS, Flags);12744 SDValue IsZeroOrInf =12745 DAG.getNode(ISD::IS_FPCLASS, DL, MVT::i1, SqrtX,12746 DAG.getTargetConstant(fcZero | fcPosInf, DL, MVT::i32));12747 12748 return DAG.getNode(ISD::SELECT, DL, VT, IsZeroOrInf, SqrtX, SqrtS, Flags);12749}12750 12751SDValue SITargetLowering::lowerFSQRTF64(SDValue Op, SelectionDAG &DAG) const {12752 // For double type, the SQRT and RSQ instructions don't have required12753 // precision, we apply Goldschmidt's algorithm to improve the result:12754 //12755 // y0 = rsq(x)12756 // g0 = x * y012757 // h0 = 0.5 * y012758 //12759 // r0 = 0.5 - h0 * g012760 // g1 = g0 * r0 + g012761 // h1 = h0 * r0 + h012762 //12763 // r1 = 0.5 - h1 * g1 => d0 = x - g1 * g112764 // g2 = g1 * r1 + g1 g2 = d0 * h1 + g112765 // h2 = h1 * r1 + h112766 //12767 // r2 = 0.5 - h2 * g2 => d1 = x - g2 * g212768 // g3 = g2 * r2 + g2 g3 = d1 * h1 + g212769 //12770 // sqrt(x) = g312771 12772 SDNodeFlags Flags = Op->getFlags();12773 12774 SDLoc DL(Op);12775 12776 SDValue X = Op.getOperand(0);12777 SDValue ScaleConstant = DAG.getConstantFP(0x1.0p-767, DL, MVT::f64);12778 12779 SDValue Scaling = DAG.getSetCC(DL, MVT::i1, X, ScaleConstant, ISD::SETOLT);12780 12781 SDValue ZeroInt = DAG.getConstant(0, DL, MVT::i32);12782 12783 // Scale up input if it is too small.12784 SDValue ScaleUpFactor = DAG.getConstant(256, DL, MVT::i32);12785 SDValue ScaleUp =12786 DAG.getNode(ISD::SELECT, DL, MVT::i32, Scaling, ScaleUpFactor, ZeroInt);12787 SDValue SqrtX = DAG.getNode(ISD::FLDEXP, DL, MVT::f64, X, ScaleUp, Flags);12788 12789 SDValue SqrtY = DAG.getNode(AMDGPUISD::RSQ, DL, MVT::f64, SqrtX);12790 12791 SDValue SqrtS0 = DAG.getNode(ISD::FMUL, DL, MVT::f64, SqrtX, SqrtY);12792 12793 SDValue Half = DAG.getConstantFP(0.5, DL, MVT::f64);12794 SDValue SqrtH0 = DAG.getNode(ISD::FMUL, DL, MVT::f64, SqrtY, Half);12795 12796 SDValue NegSqrtH0 = DAG.getNode(ISD::FNEG, DL, MVT::f64, SqrtH0);12797 SDValue SqrtR0 = DAG.getNode(ISD::FMA, DL, MVT::f64, NegSqrtH0, SqrtS0, Half);12798 12799 SDValue SqrtH1 = DAG.getNode(ISD::FMA, DL, MVT::f64, SqrtH0, SqrtR0, SqrtH0);12800 12801 SDValue SqrtS1 = DAG.getNode(ISD::FMA, DL, MVT::f64, SqrtS0, SqrtR0, SqrtS0);12802 12803 SDValue NegSqrtS1 = DAG.getNode(ISD::FNEG, DL, MVT::f64, SqrtS1);12804 SDValue SqrtD0 =12805 DAG.getNode(ISD::FMA, DL, MVT::f64, NegSqrtS1, SqrtS1, SqrtX);12806 12807 SDValue SqrtS2 = DAG.getNode(ISD::FMA, DL, MVT::f64, SqrtD0, SqrtH1, SqrtS1);12808 12809 SDValue NegSqrtS2 = DAG.getNode(ISD::FNEG, DL, MVT::f64, SqrtS2);12810 SDValue SqrtD1 =12811 DAG.getNode(ISD::FMA, DL, MVT::f64, NegSqrtS2, SqrtS2, SqrtX);12812 12813 SDValue SqrtRet = DAG.getNode(ISD::FMA, DL, MVT::f64, SqrtD1, SqrtH1, SqrtS2);12814 12815 SDValue ScaleDownFactor = DAG.getSignedConstant(-128, DL, MVT::i32);12816 SDValue ScaleDown =12817 DAG.getNode(ISD::SELECT, DL, MVT::i32, Scaling, ScaleDownFactor, ZeroInt);12818 SqrtRet = DAG.getNode(ISD::FLDEXP, DL, MVT::f64, SqrtRet, ScaleDown, Flags);12819 12820 // TODO: Switch to fcmp oeq 0 for finite only. Can't fully remove this check12821 // with finite only or nsz because rsq(+/-0) = +/-inf12822 12823 // TODO: Check for DAZ and expand to subnormals12824 SDValue IsZeroOrInf =12825 DAG.getNode(ISD::IS_FPCLASS, DL, MVT::i1, SqrtX,12826 DAG.getTargetConstant(fcZero | fcPosInf, DL, MVT::i32));12827 12828 // If x is +INF, +0, or -0, use its original value12829 return DAG.getNode(ISD::SELECT, DL, MVT::f64, IsZeroOrInf, SqrtX, SqrtRet,12830 Flags);12831}12832 12833SDValue SITargetLowering::LowerTrig(SDValue Op, SelectionDAG &DAG) const {12834 SDLoc DL(Op);12835 EVT VT = Op.getValueType();12836 SDValue Arg = Op.getOperand(0);12837 SDValue TrigVal;12838 12839 // Propagate fast-math flags so that the multiply we introduce can be folded12840 // if Arg is already the result of a multiply by constant.12841 auto Flags = Op->getFlags();12842 12843 SDValue OneOver2Pi = DAG.getConstantFP(0.5 * numbers::inv_pi, DL, VT);12844 12845 if (Subtarget->hasTrigReducedRange()) {12846 SDValue MulVal = DAG.getNode(ISD::FMUL, DL, VT, Arg, OneOver2Pi, Flags);12847 TrigVal = DAG.getNode(AMDGPUISD::FRACT, DL, VT, MulVal, Flags);12848 } else {12849 TrigVal = DAG.getNode(ISD::FMUL, DL, VT, Arg, OneOver2Pi, Flags);12850 }12851 12852 switch (Op.getOpcode()) {12853 case ISD::FCOS:12854 return DAG.getNode(AMDGPUISD::COS_HW, SDLoc(Op), VT, TrigVal, Flags);12855 case ISD::FSIN:12856 return DAG.getNode(AMDGPUISD::SIN_HW, SDLoc(Op), VT, TrigVal, Flags);12857 default:12858 llvm_unreachable("Wrong trig opcode");12859 }12860}12861 12862SDValue SITargetLowering::LowerATOMIC_CMP_SWAP(SDValue Op,12863 SelectionDAG &DAG) const {12864 AtomicSDNode *AtomicNode = cast<AtomicSDNode>(Op);12865 assert(AtomicNode->isCompareAndSwap());12866 unsigned AS = AtomicNode->getAddressSpace();12867 12868 // No custom lowering required for local address space12869 if (!AMDGPU::isFlatGlobalAddrSpace(AS))12870 return Op;12871 12872 // Non-local address space requires custom lowering for atomic compare12873 // and swap; cmp and swap should be in a v2i32 or v2i64 in case of _X212874 SDLoc DL(Op);12875 SDValue ChainIn = Op.getOperand(0);12876 SDValue Addr = Op.getOperand(1);12877 SDValue Old = Op.getOperand(2);12878 SDValue New = Op.getOperand(3);12879 EVT VT = Op.getValueType();12880 MVT SimpleVT = VT.getSimpleVT();12881 MVT VecType = MVT::getVectorVT(SimpleVT, 2);12882 12883 SDValue NewOld = DAG.getBuildVector(VecType, DL, {New, Old});12884 SDValue Ops[] = {ChainIn, Addr, NewOld};12885 12886 return DAG.getMemIntrinsicNode(AMDGPUISD::ATOMIC_CMP_SWAP, DL,12887 Op->getVTList(), Ops, VT,12888 AtomicNode->getMemOperand());12889}12890 12891//===----------------------------------------------------------------------===//12892// Custom DAG optimizations12893//===----------------------------------------------------------------------===//12894 12895SDValue12896SITargetLowering::performUCharToFloatCombine(SDNode *N,12897 DAGCombinerInfo &DCI) const {12898 EVT VT = N->getValueType(0);12899 EVT ScalarVT = VT.getScalarType();12900 if (ScalarVT != MVT::f32 && ScalarVT != MVT::f16)12901 return SDValue();12902 12903 SelectionDAG &DAG = DCI.DAG;12904 SDLoc DL(N);12905 12906 SDValue Src = N->getOperand(0);12907 EVT SrcVT = Src.getValueType();12908 12909 // TODO: We could try to match extracting the higher bytes, which would be12910 // easier if i8 vectors weren't promoted to i32 vectors, particularly after12911 // types are legalized. v4i8 -> v4f32 is probably the only case to worry12912 // about in practice.12913 if (DCI.isAfterLegalizeDAG() && SrcVT == MVT::i32) {12914 if (DAG.MaskedValueIsZero(Src, APInt::getHighBitsSet(32, 24))) {12915 SDValue Cvt = DAG.getNode(AMDGPUISD::CVT_F32_UBYTE0, DL, MVT::f32, Src);12916 DCI.AddToWorklist(Cvt.getNode());12917 12918 // For the f16 case, fold to a cast to f32 and then cast back to f16.12919 if (ScalarVT != MVT::f32) {12920 Cvt = DAG.getNode(ISD::FP_ROUND, DL, VT, Cvt,12921 DAG.getTargetConstant(0, DL, MVT::i32));12922 }12923 return Cvt;12924 }12925 }12926 12927 return SDValue();12928}12929 12930SDValue SITargetLowering::performFCopySignCombine(SDNode *N,12931 DAGCombinerInfo &DCI) const {12932 SDValue MagnitudeOp = N->getOperand(0);12933 SDValue SignOp = N->getOperand(1);12934 12935 // The generic combine for fcopysign + fp cast is too conservative with12936 // vectors, and also gets confused by the splitting we will perform here, so12937 // peek through FP casts.12938 if (SignOp.getOpcode() == ISD::FP_EXTEND ||12939 SignOp.getOpcode() == ISD::FP_ROUND)12940 SignOp = SignOp.getOperand(0);12941 12942 SelectionDAG &DAG = DCI.DAG;12943 SDLoc DL(N);12944 EVT SignVT = SignOp.getValueType();12945 12946 // f64 fcopysign is really an f32 copysign on the high bits, so replace the12947 // lower half with a copy.12948 // fcopysign f64:x, _:y -> x.lo32, (fcopysign (f32 x.hi32), _:y)12949 EVT MagVT = MagnitudeOp.getValueType();12950 12951 unsigned NumElts = MagVT.isVector() ? MagVT.getVectorNumElements() : 1;12952 12953 if (MagVT.getScalarType() == MVT::f64) {12954 EVT F32VT = MagVT.isVector()12955 ? EVT::getVectorVT(*DAG.getContext(), MVT::f32, 2 * NumElts)12956 : MVT::v2f32;12957 12958 SDValue MagAsVector = DAG.getNode(ISD::BITCAST, DL, F32VT, MagnitudeOp);12959 12960 SmallVector<SDValue, 8> NewElts;12961 for (unsigned I = 0; I != NumElts; ++I) {12962 SDValue MagLo =12963 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, MagAsVector,12964 DAG.getConstant(2 * I, DL, MVT::i32));12965 SDValue MagHi =12966 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, MagAsVector,12967 DAG.getConstant(2 * I + 1, DL, MVT::i32));12968 12969 SDValue SignOpElt =12970 MagVT.isVector()12971 ? DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, SignVT.getScalarType(),12972 SignOp, DAG.getConstant(I, DL, MVT::i32))12973 : SignOp;12974 12975 SDValue HiOp =12976 DAG.getNode(ISD::FCOPYSIGN, DL, MVT::f32, MagHi, SignOpElt);12977 12978 SDValue Vector =12979 DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v2f32, MagLo, HiOp);12980 12981 SDValue NewElt = DAG.getNode(ISD::BITCAST, DL, MVT::f64, Vector);12982 NewElts.push_back(NewElt);12983 }12984 12985 if (NewElts.size() == 1)12986 return NewElts[0];12987 12988 return DAG.getNode(ISD::BUILD_VECTOR, DL, MagVT, NewElts);12989 }12990 12991 if (SignVT.getScalarType() != MVT::f64)12992 return SDValue();12993 12994 // Reduce width of sign operand, we only need the highest bit.12995 //12996 // fcopysign f64:x, f64:y ->12997 // fcopysign f64:x, (extract_vector_elt (bitcast f64:y to v2f32), 1)12998 // TODO: In some cases it might make sense to go all the way to f16.12999 13000 EVT F32VT = MagVT.isVector()13001 ? EVT::getVectorVT(*DAG.getContext(), MVT::f32, 2 * NumElts)13002 : MVT::v2f32;13003 13004 SDValue SignAsVector = DAG.getNode(ISD::BITCAST, DL, F32VT, SignOp);13005 13006 SmallVector<SDValue, 8> F32Signs;13007 for (unsigned I = 0; I != NumElts; ++I) {13008 // Take sign from odd elements of cast vector13009 SDValue SignAsF32 =13010 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, SignAsVector,13011 DAG.getConstant(2 * I + 1, DL, MVT::i32));13012 F32Signs.push_back(SignAsF32);13013 }13014 13015 SDValue NewSign =13016 NumElts == 113017 ? F32Signs.back()13018 : DAG.getNode(ISD::BUILD_VECTOR, DL,13019 EVT::getVectorVT(*DAG.getContext(), MVT::f32, NumElts),13020 F32Signs);13021 13022 return DAG.getNode(ISD::FCOPYSIGN, DL, N->getValueType(0), N->getOperand(0),13023 NewSign);13024}13025 13026// (shl (add x, c1), c2) -> add (shl x, c2), (shl c1, c2)13027// (shl (or x, c1), c2) -> add (shl x, c2), (shl c1, c2) iff x and c1 share no13028// bits13029 13030// This is a variant of13031// (mul (add x, c1), c2) -> add (mul x, c2), (mul c1, c2),13032//13033// The normal DAG combiner will do this, but only if the add has one use since13034// that would increase the number of instructions.13035//13036// This prevents us from seeing a constant offset that can be folded into a13037// memory instruction's addressing mode. If we know the resulting add offset of13038// a pointer can be folded into an addressing offset, we can replace the pointer13039// operand with the add of new constant offset. This eliminates one of the uses,13040// and may allow the remaining use to also be simplified.13041//13042SDValue SITargetLowering::performSHLPtrCombine(SDNode *N, unsigned AddrSpace,13043 EVT MemVT,13044 DAGCombinerInfo &DCI) const {13045 SDValue N0 = N->getOperand(0);13046 SDValue N1 = N->getOperand(1);13047 13048 // We only do this to handle cases where it's profitable when there are13049 // multiple uses of the add, so defer to the standard combine.13050 if ((!N0->isAnyAdd() && N0.getOpcode() != ISD::OR) || N0->hasOneUse())13051 return SDValue();13052 13053 const ConstantSDNode *CN1 = dyn_cast<ConstantSDNode>(N1);13054 if (!CN1)13055 return SDValue();13056 13057 const ConstantSDNode *CAdd = dyn_cast<ConstantSDNode>(N0.getOperand(1));13058 if (!CAdd)13059 return SDValue();13060 13061 SelectionDAG &DAG = DCI.DAG;13062 13063 if (N0->getOpcode() == ISD::OR &&13064 !DAG.haveNoCommonBitsSet(N0.getOperand(0), N0.getOperand(1)))13065 return SDValue();13066 13067 // If the resulting offset is too large, we can't fold it into the13068 // addressing mode offset.13069 APInt Offset = CAdd->getAPIntValue() << CN1->getAPIntValue();13070 Type *Ty = MemVT.getTypeForEVT(*DCI.DAG.getContext());13071 13072 AddrMode AM;13073 AM.HasBaseReg = true;13074 AM.BaseOffs = Offset.getSExtValue();13075 if (!isLegalAddressingMode(DCI.DAG.getDataLayout(), AM, Ty, AddrSpace))13076 return SDValue();13077 13078 SDLoc SL(N);13079 EVT VT = N->getValueType(0);13080 13081 SDValue ShlX = DAG.getNode(ISD::SHL, SL, VT, N0.getOperand(0), N1);13082 SDValue COffset = DAG.getConstant(Offset, SL, VT);13083 13084 SDNodeFlags Flags;13085 Flags.setNoUnsignedWrap(13086 N->getFlags().hasNoUnsignedWrap() &&13087 (N0.getOpcode() == ISD::OR || N0->getFlags().hasNoUnsignedWrap()));13088 13089 // Use ISD::ADD even if the original operation was ISD::PTRADD, since we can't13090 // be sure that the new left operand is a proper base pointer.13091 return DAG.getNode(ISD::ADD, SL, VT, ShlX, COffset, Flags);13092}13093 13094/// MemSDNode::getBasePtr() does not work for intrinsics, which needs to offset13095/// by the chain and intrinsic ID. Theoretically we would also need to check the13096/// specific intrinsic, but they all place the pointer operand first.13097static unsigned getBasePtrIndex(const MemSDNode *N) {13098 switch (N->getOpcode()) {13099 case ISD::STORE:13100 case ISD::INTRINSIC_W_CHAIN:13101 case ISD::INTRINSIC_VOID:13102 return 2;13103 default:13104 return 1;13105 }13106}13107 13108SDValue SITargetLowering::performMemSDNodeCombine(MemSDNode *N,13109 DAGCombinerInfo &DCI) const {13110 SelectionDAG &DAG = DCI.DAG;13111 13112 unsigned PtrIdx = getBasePtrIndex(N);13113 SDValue Ptr = N->getOperand(PtrIdx);13114 13115 // TODO: We could also do this for multiplies.13116 if (Ptr.getOpcode() == ISD::SHL) {13117 SDValue NewPtr = performSHLPtrCombine(Ptr.getNode(), N->getAddressSpace(),13118 N->getMemoryVT(), DCI);13119 if (NewPtr) {13120 SmallVector<SDValue, 8> NewOps(N->ops());13121 13122 NewOps[PtrIdx] = NewPtr;13123 return SDValue(DAG.UpdateNodeOperands(N, NewOps), 0);13124 }13125 }13126 13127 return SDValue();13128}13129 13130static bool bitOpWithConstantIsReducible(unsigned Opc, uint32_t Val) {13131 return (Opc == ISD::AND && (Val == 0 || Val == 0xffffffff)) ||13132 (Opc == ISD::OR && (Val == 0xffffffff || Val == 0)) ||13133 (Opc == ISD::XOR && Val == 0);13134}13135 13136// Break up 64-bit bit operation of a constant into two 32-bit and/or/xor. This13137// will typically happen anyway for a VALU 64-bit and. This exposes other 32-bit13138// integer combine opportunities since most 64-bit operations are decomposed13139// this way. TODO: We won't want this for SALU especially if it is an inline13140// immediate.13141SDValue SITargetLowering::splitBinaryBitConstantOp(13142 DAGCombinerInfo &DCI, const SDLoc &SL, unsigned Opc, SDValue LHS,13143 const ConstantSDNode *CRHS) const {13144 uint64_t Val = CRHS->getZExtValue();13145 uint32_t ValLo = Lo_32(Val);13146 uint32_t ValHi = Hi_32(Val);13147 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();13148 13149 if ((bitOpWithConstantIsReducible(Opc, ValLo) ||13150 bitOpWithConstantIsReducible(Opc, ValHi)) ||13151 (CRHS->hasOneUse() && !TII->isInlineConstant(CRHS->getAPIntValue()))) {13152 // We have 64-bit scalar and/or/xor, but do not have vector forms.13153 if (Subtarget->has64BitLiterals() && CRHS->hasOneUse() &&13154 !CRHS->user_begin()->isDivergent())13155 return SDValue();13156 13157 // If we need to materialize a 64-bit immediate, it will be split up later13158 // anyway. Avoid creating the harder to understand 64-bit immediate13159 // materialization.13160 return splitBinaryBitConstantOpImpl(DCI, SL, Opc, LHS, ValLo, ValHi);13161 }13162 13163 return SDValue();13164}13165 13166bool llvm::isBoolSGPR(SDValue V) {13167 if (V.getValueType() != MVT::i1)13168 return false;13169 switch (V.getOpcode()) {13170 default:13171 break;13172 case ISD::SETCC:13173 case ISD::IS_FPCLASS:13174 case AMDGPUISD::FP_CLASS:13175 return true;13176 case ISD::AND:13177 case ISD::OR:13178 case ISD::XOR:13179 return isBoolSGPR(V.getOperand(0)) && isBoolSGPR(V.getOperand(1));13180 case ISD::SADDO:13181 case ISD::UADDO:13182 case ISD::SSUBO:13183 case ISD::USUBO:13184 case ISD::SMULO:13185 case ISD::UMULO:13186 return V.getResNo() == 1;13187 case ISD::INTRINSIC_WO_CHAIN: {13188 unsigned IntrinsicID = V.getConstantOperandVal(0);13189 switch (IntrinsicID) {13190 case Intrinsic::amdgcn_is_shared:13191 case Intrinsic::amdgcn_is_private:13192 return true;13193 default:13194 return false;13195 }13196 13197 return false;13198 }13199 }13200 return false;13201}13202 13203// If a constant has all zeroes or all ones within each byte return it.13204// Otherwise return 0.13205static uint32_t getConstantPermuteMask(uint32_t C) {13206 // 0xff for any zero byte in the mask13207 uint32_t ZeroByteMask = 0;13208 if (!(C & 0x000000ff))13209 ZeroByteMask |= 0x000000ff;13210 if (!(C & 0x0000ff00))13211 ZeroByteMask |= 0x0000ff00;13212 if (!(C & 0x00ff0000))13213 ZeroByteMask |= 0x00ff0000;13214 if (!(C & 0xff000000))13215 ZeroByteMask |= 0xff000000;13216 uint32_t NonZeroByteMask = ~ZeroByteMask; // 0xff for any non-zero byte13217 if ((NonZeroByteMask & C) != NonZeroByteMask)13218 return 0; // Partial bytes selected.13219 return C;13220}13221 13222// Check if a node selects whole bytes from its operand 0 starting at a byte13223// boundary while masking the rest. Returns select mask as in the v_perm_b3213224// or -1 if not succeeded.13225// Note byte select encoding:13226// value 0-3 selects corresponding source byte;13227// value 0xc selects zero;13228// value 0xff selects 0xff.13229static uint32_t getPermuteMask(SDValue V) {13230 assert(V.getValueSizeInBits() == 32);13231 13232 if (V.getNumOperands() != 2)13233 return ~0;13234 13235 ConstantSDNode *N1 = dyn_cast<ConstantSDNode>(V.getOperand(1));13236 if (!N1)13237 return ~0;13238 13239 uint32_t C = N1->getZExtValue();13240 13241 switch (V.getOpcode()) {13242 default:13243 break;13244 case ISD::AND:13245 if (uint32_t ConstMask = getConstantPermuteMask(C))13246 return (0x03020100 & ConstMask) | (0x0c0c0c0c & ~ConstMask);13247 break;13248 13249 case ISD::OR:13250 if (uint32_t ConstMask = getConstantPermuteMask(C))13251 return (0x03020100 & ~ConstMask) | ConstMask;13252 break;13253 13254 case ISD::SHL:13255 if (C % 8)13256 return ~0;13257 13258 return uint32_t((0x030201000c0c0c0cull << C) >> 32);13259 13260 case ISD::SRL:13261 if (C % 8)13262 return ~0;13263 13264 return uint32_t(0x0c0c0c0c03020100ull >> C);13265 }13266 13267 return ~0;13268}13269 13270SDValue SITargetLowering::performAndCombine(SDNode *N,13271 DAGCombinerInfo &DCI) const {13272 if (DCI.isBeforeLegalize())13273 return SDValue();13274 13275 SelectionDAG &DAG = DCI.DAG;13276 EVT VT = N->getValueType(0);13277 SDValue LHS = N->getOperand(0);13278 SDValue RHS = N->getOperand(1);13279 13280 const ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(RHS);13281 if (VT == MVT::i64 && CRHS) {13282 if (SDValue Split =13283 splitBinaryBitConstantOp(DCI, SDLoc(N), ISD::AND, LHS, CRHS))13284 return Split;13285 }13286 13287 if (CRHS && VT == MVT::i32) {13288 // and (srl x, c), mask => shl (bfe x, nb + c, mask >> nb), nb13289 // nb = number of trailing zeroes in mask13290 // It can be optimized out using SDWA for GFX8+ in the SDWA peephole pass,13291 // given that we are selecting 8 or 16 bit fields starting at byte boundary.13292 uint64_t Mask = CRHS->getZExtValue();13293 unsigned Bits = llvm::popcount(Mask);13294 if (getSubtarget()->hasSDWA() && LHS->getOpcode() == ISD::SRL &&13295 (Bits == 8 || Bits == 16) && isShiftedMask_64(Mask) && !(Mask & 1)) {13296 if (auto *CShift = dyn_cast<ConstantSDNode>(LHS->getOperand(1))) {13297 unsigned Shift = CShift->getZExtValue();13298 unsigned NB = CRHS->getAPIntValue().countr_zero();13299 unsigned Offset = NB + Shift;13300 if ((Offset & (Bits - 1)) == 0) { // Starts at a byte or word boundary.13301 SDLoc SL(N);13302 SDValue BFE =13303 DAG.getNode(AMDGPUISD::BFE_U32, SL, MVT::i32, LHS->getOperand(0),13304 DAG.getConstant(Offset, SL, MVT::i32),13305 DAG.getConstant(Bits, SL, MVT::i32));13306 EVT NarrowVT = EVT::getIntegerVT(*DAG.getContext(), Bits);13307 SDValue Ext = DAG.getNode(ISD::AssertZext, SL, VT, BFE,13308 DAG.getValueType(NarrowVT));13309 SDValue Shl = DAG.getNode(ISD::SHL, SDLoc(LHS), VT, Ext,13310 DAG.getConstant(NB, SDLoc(CRHS), MVT::i32));13311 return Shl;13312 }13313 }13314 }13315 13316 // and (perm x, y, c1), c2 -> perm x, y, permute_mask(c1, c2)13317 if (LHS.hasOneUse() && LHS.getOpcode() == AMDGPUISD::PERM &&13318 isa<ConstantSDNode>(LHS.getOperand(2))) {13319 uint32_t Sel = getConstantPermuteMask(Mask);13320 if (!Sel)13321 return SDValue();13322 13323 // Select 0xc for all zero bytes13324 Sel = (LHS.getConstantOperandVal(2) & Sel) | (~Sel & 0x0c0c0c0c);13325 SDLoc DL(N);13326 return DAG.getNode(AMDGPUISD::PERM, DL, MVT::i32, LHS.getOperand(0),13327 LHS.getOperand(1), DAG.getConstant(Sel, DL, MVT::i32));13328 }13329 }13330 13331 // (and (fcmp ord x, x), (fcmp une (fabs x), inf)) ->13332 // fp_class x, ~(s_nan | q_nan | n_infinity | p_infinity)13333 if (LHS.getOpcode() == ISD::SETCC && RHS.getOpcode() == ISD::SETCC) {13334 ISD::CondCode LCC = cast<CondCodeSDNode>(LHS.getOperand(2))->get();13335 ISD::CondCode RCC = cast<CondCodeSDNode>(RHS.getOperand(2))->get();13336 13337 SDValue X = LHS.getOperand(0);13338 SDValue Y = RHS.getOperand(0);13339 if (Y.getOpcode() != ISD::FABS || Y.getOperand(0) != X ||13340 !isTypeLegal(X.getValueType()))13341 return SDValue();13342 13343 if (LCC == ISD::SETO) {13344 if (X != LHS.getOperand(1))13345 return SDValue();13346 13347 if (RCC == ISD::SETUNE) {13348 const ConstantFPSDNode *C1 =13349 dyn_cast<ConstantFPSDNode>(RHS.getOperand(1));13350 if (!C1 || !C1->isInfinity() || C1->isNegative())13351 return SDValue();13352 13353 const uint32_t Mask = SIInstrFlags::N_NORMAL |13354 SIInstrFlags::N_SUBNORMAL | SIInstrFlags::N_ZERO |13355 SIInstrFlags::P_ZERO | SIInstrFlags::P_SUBNORMAL |13356 SIInstrFlags::P_NORMAL;13357 13358 static_assert(13359 ((~(SIInstrFlags::S_NAN | SIInstrFlags::Q_NAN |13360 SIInstrFlags::N_INFINITY | SIInstrFlags::P_INFINITY)) &13361 0x3ff) == Mask,13362 "mask not equal");13363 13364 SDLoc DL(N);13365 return DAG.getNode(AMDGPUISD::FP_CLASS, DL, MVT::i1, X,13366 DAG.getConstant(Mask, DL, MVT::i32));13367 }13368 }13369 }13370 13371 if (RHS.getOpcode() == ISD::SETCC && LHS.getOpcode() == AMDGPUISD::FP_CLASS)13372 std::swap(LHS, RHS);13373 13374 if (LHS.getOpcode() == ISD::SETCC && RHS.getOpcode() == AMDGPUISD::FP_CLASS &&13375 RHS.hasOneUse()) {13376 ISD::CondCode LCC = cast<CondCodeSDNode>(LHS.getOperand(2))->get();13377 // and (fcmp seto), (fp_class x, mask) -> fp_class x, mask & ~(p_nan |13378 // n_nan) and (fcmp setuo), (fp_class x, mask) -> fp_class x, mask & (p_nan13379 // | n_nan)13380 const ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(RHS.getOperand(1));13381 if ((LCC == ISD::SETO || LCC == ISD::SETUO) && Mask &&13382 (RHS.getOperand(0) == LHS.getOperand(0) &&13383 LHS.getOperand(0) == LHS.getOperand(1))) {13384 const unsigned OrdMask = SIInstrFlags::S_NAN | SIInstrFlags::Q_NAN;13385 unsigned NewMask = LCC == ISD::SETO ? Mask->getZExtValue() & ~OrdMask13386 : Mask->getZExtValue() & OrdMask;13387 13388 SDLoc DL(N);13389 return DAG.getNode(AMDGPUISD::FP_CLASS, DL, MVT::i1, RHS.getOperand(0),13390 DAG.getConstant(NewMask, DL, MVT::i32));13391 }13392 }13393 13394 if (VT == MVT::i32 && (RHS.getOpcode() == ISD::SIGN_EXTEND ||13395 LHS.getOpcode() == ISD::SIGN_EXTEND)) {13396 // and x, (sext cc from i1) => select cc, x, 013397 if (RHS.getOpcode() != ISD::SIGN_EXTEND)13398 std::swap(LHS, RHS);13399 if (isBoolSGPR(RHS.getOperand(0)))13400 return DAG.getSelect(SDLoc(N), MVT::i32, RHS.getOperand(0), LHS,13401 DAG.getConstant(0, SDLoc(N), MVT::i32));13402 }13403 13404 // and (op x, c1), (op y, c2) -> perm x, y, permute_mask(c1, c2)13405 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();13406 if (VT == MVT::i32 && LHS.hasOneUse() && RHS.hasOneUse() &&13407 N->isDivergent() && TII->pseudoToMCOpcode(AMDGPU::V_PERM_B32_e64) != -1) {13408 uint32_t LHSMask = getPermuteMask(LHS);13409 uint32_t RHSMask = getPermuteMask(RHS);13410 if (LHSMask != ~0u && RHSMask != ~0u) {13411 // Canonicalize the expression in an attempt to have fewer unique masks13412 // and therefore fewer registers used to hold the masks.13413 if (LHSMask > RHSMask) {13414 std::swap(LHSMask, RHSMask);13415 std::swap(LHS, RHS);13416 }13417 13418 // Select 0xc for each lane used from source operand. Zero has 0xc mask13419 // set, 0xff have 0xff in the mask, actual lanes are in the 0-3 range.13420 uint32_t LHSUsedLanes = ~(LHSMask & 0x0c0c0c0c) & 0x0c0c0c0c;13421 uint32_t RHSUsedLanes = ~(RHSMask & 0x0c0c0c0c) & 0x0c0c0c0c;13422 13423 // Check of we need to combine values from two sources within a byte.13424 if (!(LHSUsedLanes & RHSUsedLanes) &&13425 // If we select high and lower word keep it for SDWA.13426 // TODO: teach SDWA to work with v_perm_b32 and remove the check.13427 !(LHSUsedLanes == 0x0c0c0000 && RHSUsedLanes == 0x00000c0c)) {13428 // Each byte in each mask is either selector mask 0-3, or has higher13429 // bits set in either of masks, which can be 0xff for 0xff or 0x0c for13430 // zero. If 0x0c is in either mask it shall always be 0x0c. Otherwise13431 // mask which is not 0xff wins. By anding both masks we have a correct13432 // result except that 0x0c shall be corrected to give 0x0c only.13433 uint32_t Mask = LHSMask & RHSMask;13434 for (unsigned I = 0; I < 32; I += 8) {13435 uint32_t ByteSel = 0xff << I;13436 if ((LHSMask & ByteSel) == 0x0c || (RHSMask & ByteSel) == 0x0c)13437 Mask &= (0x0c << I) & 0xffffffff;13438 }13439 13440 // Add 4 to each active LHS lane. It will not affect any existing 0xff13441 // or 0x0c.13442 uint32_t Sel = Mask | (LHSUsedLanes & 0x04040404);13443 SDLoc DL(N);13444 13445 return DAG.getNode(AMDGPUISD::PERM, DL, MVT::i32, LHS.getOperand(0),13446 RHS.getOperand(0),13447 DAG.getConstant(Sel, DL, MVT::i32));13448 }13449 }13450 }13451 13452 return SDValue();13453}13454 13455// A key component of v_perm is a mapping between byte position of the src13456// operands, and the byte position of the dest. To provide such, we need: 1. the13457// node that provides x byte of the dest of the OR, and 2. the byte of the node13458// used to provide that x byte. calculateByteProvider finds which node provides13459// a certain byte of the dest of the OR, and calculateSrcByte takes that node,13460// and finds an ultimate src and byte position For example: The supported13461// LoadCombine pattern for vector loads is as follows13462// t113463// or13464// / \13465// t2 t313466// zext shl13467// | | \13468// t4 t5 1613469// or anyext13470// / \ |13471// t6 t7 t813472// srl shl or13473// / | / \ / \13474// t9 t10 t11 t12 t13 t1413475// trunc* 8 trunc* 8 and and13476// | | / | | \13477// t15 t16 t17 t18 t19 t2013478// trunc* 255 srl -25613479// | / \13480// t15 t15 1613481//13482// *In this example, the truncs are from i32->i1613483//13484// calculateByteProvider would find t6, t7, t13, and t14 for bytes 0-313485// respectively. calculateSrcByte would find (given node) -> ultimate src &13486// byteposition: t6 -> t15 & 1, t7 -> t16 & 0, t13 -> t15 & 0, t14 -> t15 & 3.13487// After finding the mapping, we can combine the tree into vperm t15, t16,13488// 0x0500040713489 13490// Find the source and byte position from a node.13491// \p DestByte is the byte position of the dest of the or that the src13492// ultimately provides. \p SrcIndex is the byte of the src that maps to this13493// dest of the or byte. \p Depth tracks how many recursive iterations we have13494// performed.13495static const std::optional<ByteProvider<SDValue>>13496calculateSrcByte(const SDValue Op, uint64_t DestByte, uint64_t SrcIndex = 0,13497 unsigned Depth = 0) {13498 // We may need to recursively traverse a series of SRLs13499 if (Depth >= 6)13500 return std::nullopt;13501 13502 if (Op.getValueSizeInBits() < 8)13503 return std::nullopt;13504 13505 if (Op.getValueType().isVector())13506 return ByteProvider<SDValue>::getSrc(Op, DestByte, SrcIndex);13507 13508 switch (Op->getOpcode()) {13509 case ISD::TRUNCATE: {13510 return calculateSrcByte(Op->getOperand(0), DestByte, SrcIndex, Depth + 1);13511 }13512 13513 case ISD::SIGN_EXTEND:13514 case ISD::ZERO_EXTEND:13515 case ISD::SIGN_EXTEND_INREG: {13516 SDValue NarrowOp = Op->getOperand(0);13517 auto NarrowVT = NarrowOp.getValueType();13518 if (Op->getOpcode() == ISD::SIGN_EXTEND_INREG) {13519 auto *VTSign = cast<VTSDNode>(Op->getOperand(1));13520 NarrowVT = VTSign->getVT();13521 }13522 if (!NarrowVT.isByteSized())13523 return std::nullopt;13524 uint64_t NarrowByteWidth = NarrowVT.getStoreSize();13525 13526 if (SrcIndex >= NarrowByteWidth)13527 return std::nullopt;13528 return calculateSrcByte(Op->getOperand(0), DestByte, SrcIndex, Depth + 1);13529 }13530 13531 case ISD::SRA:13532 case ISD::SRL: {13533 auto *ShiftOp = dyn_cast<ConstantSDNode>(Op->getOperand(1));13534 if (!ShiftOp)13535 return std::nullopt;13536 13537 uint64_t BitShift = ShiftOp->getZExtValue();13538 13539 if (BitShift % 8 != 0)13540 return std::nullopt;13541 13542 SrcIndex += BitShift / 8;13543 13544 return calculateSrcByte(Op->getOperand(0), DestByte, SrcIndex, Depth + 1);13545 }13546 13547 default: {13548 return ByteProvider<SDValue>::getSrc(Op, DestByte, SrcIndex);13549 }13550 }13551 llvm_unreachable("fully handled switch");13552}13553 13554// For a byte position in the result of an Or, traverse the tree and find the13555// node (and the byte of the node) which ultimately provides this {Or,13556// BytePosition}. \p Op is the operand we are currently examining. \p Index is13557// the byte position of the Op that corresponds with the originally requested13558// byte of the Or \p Depth tracks how many recursive iterations we have13559// performed. \p StartingIndex is the originally requested byte of the Or13560static const std::optional<ByteProvider<SDValue>>13561calculateByteProvider(const SDValue &Op, unsigned Index, unsigned Depth,13562 unsigned StartingIndex = 0) {13563 // Finding Src tree of RHS of or typically requires at least 1 additional13564 // depth13565 if (Depth > 6)13566 return std::nullopt;13567 13568 unsigned BitWidth = Op.getScalarValueSizeInBits();13569 if (BitWidth % 8 != 0)13570 return std::nullopt;13571 if (Index > BitWidth / 8 - 1)13572 return std::nullopt;13573 13574 bool IsVec = Op.getValueType().isVector();13575 switch (Op.getOpcode()) {13576 case ISD::OR: {13577 if (IsVec)13578 return std::nullopt;13579 13580 auto RHS = calculateByteProvider(Op.getOperand(1), Index, Depth + 1,13581 StartingIndex);13582 if (!RHS)13583 return std::nullopt;13584 auto LHS = calculateByteProvider(Op.getOperand(0), Index, Depth + 1,13585 StartingIndex);13586 if (!LHS)13587 return std::nullopt;13588 // A well formed Or will have two ByteProviders for each byte, one of which13589 // is constant zero13590 if (!LHS->isConstantZero() && !RHS->isConstantZero())13591 return std::nullopt;13592 if (!LHS || LHS->isConstantZero())13593 return RHS;13594 if (!RHS || RHS->isConstantZero())13595 return LHS;13596 return std::nullopt;13597 }13598 13599 case ISD::AND: {13600 if (IsVec)13601 return std::nullopt;13602 13603 auto *BitMaskOp = dyn_cast<ConstantSDNode>(Op->getOperand(1));13604 if (!BitMaskOp)13605 return std::nullopt;13606 13607 uint32_t BitMask = BitMaskOp->getZExtValue();13608 // Bits we expect for our StartingIndex13609 uint32_t IndexMask = 0xFF << (Index * 8);13610 13611 if ((IndexMask & BitMask) != IndexMask) {13612 // If the result of the and partially provides the byte, then it13613 // is not well formatted13614 if (IndexMask & BitMask)13615 return std::nullopt;13616 return ByteProvider<SDValue>::getConstantZero();13617 }13618 13619 return calculateSrcByte(Op->getOperand(0), StartingIndex, Index);13620 }13621 13622 case ISD::FSHR: {13623 if (IsVec)13624 return std::nullopt;13625 13626 // fshr(X,Y,Z): (X << (BW - (Z % BW))) | (Y >> (Z % BW))13627 auto *ShiftOp = dyn_cast<ConstantSDNode>(Op->getOperand(2));13628 if (!ShiftOp || Op.getValueType().isVector())13629 return std::nullopt;13630 13631 uint64_t BitsProvided = Op.getValueSizeInBits();13632 if (BitsProvided % 8 != 0)13633 return std::nullopt;13634 13635 uint64_t BitShift = ShiftOp->getAPIntValue().urem(BitsProvided);13636 if (BitShift % 8)13637 return std::nullopt;13638 13639 uint64_t ConcatSizeInBytes = BitsProvided / 4;13640 uint64_t ByteShift = BitShift / 8;13641 13642 uint64_t NewIndex = (Index + ByteShift) % ConcatSizeInBytes;13643 uint64_t BytesProvided = BitsProvided / 8;13644 SDValue NextOp = Op.getOperand(NewIndex >= BytesProvided ? 0 : 1);13645 NewIndex %= BytesProvided;13646 return calculateByteProvider(NextOp, NewIndex, Depth + 1, StartingIndex);13647 }13648 13649 case ISD::SRA:13650 case ISD::SRL: {13651 if (IsVec)13652 return std::nullopt;13653 13654 auto *ShiftOp = dyn_cast<ConstantSDNode>(Op->getOperand(1));13655 if (!ShiftOp)13656 return std::nullopt;13657 13658 uint64_t BitShift = ShiftOp->getZExtValue();13659 if (BitShift % 8)13660 return std::nullopt;13661 13662 auto BitsProvided = Op.getScalarValueSizeInBits();13663 if (BitsProvided % 8 != 0)13664 return std::nullopt;13665 13666 uint64_t BytesProvided = BitsProvided / 8;13667 uint64_t ByteShift = BitShift / 8;13668 // The dest of shift will have good [0 : (BytesProvided - ByteShift)] bytes.13669 // If the byte we are trying to provide (as tracked by index) falls in this13670 // range, then the SRL provides the byte. The byte of interest of the src of13671 // the SRL is Index + ByteShift13672 return BytesProvided - ByteShift > Index13673 ? calculateSrcByte(Op->getOperand(0), StartingIndex,13674 Index + ByteShift)13675 : ByteProvider<SDValue>::getConstantZero();13676 }13677 13678 case ISD::SHL: {13679 if (IsVec)13680 return std::nullopt;13681 13682 auto *ShiftOp = dyn_cast<ConstantSDNode>(Op->getOperand(1));13683 if (!ShiftOp)13684 return std::nullopt;13685 13686 uint64_t BitShift = ShiftOp->getZExtValue();13687 if (BitShift % 8 != 0)13688 return std::nullopt;13689 uint64_t ByteShift = BitShift / 8;13690 13691 // If we are shifting by an amount greater than (or equal to)13692 // the index we are trying to provide, then it provides 0s. If not,13693 // then this bytes are not definitively 0s, and the corresponding byte13694 // of interest is Index - ByteShift of the src13695 return Index < ByteShift13696 ? ByteProvider<SDValue>::getConstantZero()13697 : calculateByteProvider(Op.getOperand(0), Index - ByteShift,13698 Depth + 1, StartingIndex);13699 }13700 case ISD::ANY_EXTEND:13701 case ISD::SIGN_EXTEND:13702 case ISD::ZERO_EXTEND:13703 case ISD::SIGN_EXTEND_INREG:13704 case ISD::AssertZext:13705 case ISD::AssertSext: {13706 if (IsVec)13707 return std::nullopt;13708 13709 SDValue NarrowOp = Op->getOperand(0);13710 unsigned NarrowBitWidth = NarrowOp.getValueSizeInBits();13711 if (Op->getOpcode() == ISD::SIGN_EXTEND_INREG ||13712 Op->getOpcode() == ISD::AssertZext ||13713 Op->getOpcode() == ISD::AssertSext) {13714 auto *VTSign = cast<VTSDNode>(Op->getOperand(1));13715 NarrowBitWidth = VTSign->getVT().getSizeInBits();13716 }13717 if (NarrowBitWidth % 8 != 0)13718 return std::nullopt;13719 uint64_t NarrowByteWidth = NarrowBitWidth / 8;13720 13721 if (Index >= NarrowByteWidth)13722 return Op.getOpcode() == ISD::ZERO_EXTEND13723 ? std::optional<ByteProvider<SDValue>>(13724 ByteProvider<SDValue>::getConstantZero())13725 : std::nullopt;13726 return calculateByteProvider(NarrowOp, Index, Depth + 1, StartingIndex);13727 }13728 13729 case ISD::TRUNCATE: {13730 if (IsVec)13731 return std::nullopt;13732 13733 uint64_t NarrowByteWidth = BitWidth / 8;13734 13735 if (NarrowByteWidth >= Index) {13736 return calculateByteProvider(Op.getOperand(0), Index, Depth + 1,13737 StartingIndex);13738 }13739 13740 return std::nullopt;13741 }13742 13743 case ISD::CopyFromReg: {13744 if (BitWidth / 8 > Index)13745 return calculateSrcByte(Op, StartingIndex, Index);13746 13747 return std::nullopt;13748 }13749 13750 case ISD::LOAD: {13751 auto *L = cast<LoadSDNode>(Op.getNode());13752 13753 unsigned NarrowBitWidth = L->getMemoryVT().getSizeInBits();13754 if (NarrowBitWidth % 8 != 0)13755 return std::nullopt;13756 uint64_t NarrowByteWidth = NarrowBitWidth / 8;13757 13758 // If the width of the load does not reach byte we are trying to provide for13759 // and it is not a ZEXTLOAD, then the load does not provide for the byte in13760 // question13761 if (Index >= NarrowByteWidth) {13762 return L->getExtensionType() == ISD::ZEXTLOAD13763 ? std::optional<ByteProvider<SDValue>>(13764 ByteProvider<SDValue>::getConstantZero())13765 : std::nullopt;13766 }13767 13768 if (NarrowByteWidth > Index) {13769 return calculateSrcByte(Op, StartingIndex, Index);13770 }13771 13772 return std::nullopt;13773 }13774 13775 case ISD::BSWAP: {13776 if (IsVec)13777 return std::nullopt;13778 13779 return calculateByteProvider(Op->getOperand(0), BitWidth / 8 - Index - 1,13780 Depth + 1, StartingIndex);13781 }13782 13783 case ISD::EXTRACT_VECTOR_ELT: {13784 auto *IdxOp = dyn_cast<ConstantSDNode>(Op->getOperand(1));13785 if (!IdxOp)13786 return std::nullopt;13787 auto VecIdx = IdxOp->getZExtValue();13788 auto ScalarSize = Op.getScalarValueSizeInBits();13789 if (ScalarSize < 32)13790 Index = ScalarSize == 8 ? VecIdx : VecIdx * 2 + Index;13791 return calculateSrcByte(ScalarSize >= 32 ? Op : Op.getOperand(0),13792 StartingIndex, Index);13793 }13794 13795 case AMDGPUISD::PERM: {13796 if (IsVec)13797 return std::nullopt;13798 13799 auto *PermMask = dyn_cast<ConstantSDNode>(Op->getOperand(2));13800 if (!PermMask)13801 return std::nullopt;13802 13803 auto IdxMask =13804 (PermMask->getZExtValue() & (0xFF << (Index * 8))) >> (Index * 8);13805 if (IdxMask > 0x07 && IdxMask != 0x0c)13806 return std::nullopt;13807 13808 auto NextOp = Op.getOperand(IdxMask > 0x03 ? 0 : 1);13809 auto NextIndex = IdxMask > 0x03 ? IdxMask % 4 : IdxMask;13810 13811 return IdxMask != 0x0c ? calculateSrcByte(NextOp, StartingIndex, NextIndex)13812 : ByteProvider<SDValue>(13813 ByteProvider<SDValue>::getConstantZero());13814 }13815 13816 default: {13817 return std::nullopt;13818 }13819 }13820 13821 llvm_unreachable("fully handled switch");13822}13823 13824// Returns true if the Operand is a scalar and is 16 bits13825static bool isExtendedFrom16Bits(SDValue &Operand) {13826 13827 switch (Operand.getOpcode()) {13828 case ISD::ANY_EXTEND:13829 case ISD::SIGN_EXTEND:13830 case ISD::ZERO_EXTEND: {13831 auto OpVT = Operand.getOperand(0).getValueType();13832 return !OpVT.isVector() && OpVT.getSizeInBits() == 16;13833 }13834 case ISD::LOAD: {13835 LoadSDNode *L = cast<LoadSDNode>(Operand.getNode());13836 auto ExtType = cast<LoadSDNode>(L)->getExtensionType();13837 if (ExtType == ISD::ZEXTLOAD || ExtType == ISD::SEXTLOAD ||13838 ExtType == ISD::EXTLOAD) {13839 auto MemVT = L->getMemoryVT();13840 return !MemVT.isVector() && MemVT.getSizeInBits() == 16;13841 }13842 return L->getMemoryVT().getSizeInBits() == 16;13843 }13844 default:13845 return false;13846 }13847}13848 13849// Returns true if the mask matches consecutive bytes, and the first byte13850// begins at a power of 2 byte offset from 0th byte13851static bool addresses16Bits(int Mask) {13852 int Low8 = Mask & 0xff;13853 int Hi8 = (Mask & 0xff00) >> 8;13854 13855 assert(Low8 < 8 && Hi8 < 8);13856 // Are the bytes contiguous in the order of increasing addresses.13857 bool IsConsecutive = (Hi8 - Low8 == 1);13858 // Is the first byte at location that is aligned for 16 bit instructions.13859 // A counter example is taking 2 consecutive bytes starting at the 8th bit.13860 // In this case, we still need code to extract the 16 bit operand, so it13861 // is better to use i8 v_perm13862 bool Is16Aligned = !(Low8 % 2);13863 13864 return IsConsecutive && Is16Aligned;13865}13866 13867// Do not lower into v_perm if the operands are actually 16 bit13868// and the selected bits (based on PermMask) correspond with two13869// easily addressable 16 bit operands.13870static bool hasNon16BitAccesses(uint64_t PermMask, SDValue &Op,13871 SDValue &OtherOp) {13872 int Low16 = PermMask & 0xffff;13873 int Hi16 = (PermMask & 0xffff0000) >> 16;13874 13875 auto TempOp = peekThroughBitcasts(Op);13876 auto TempOtherOp = peekThroughBitcasts(OtherOp);13877 13878 auto OpIs16Bit =13879 TempOtherOp.getValueSizeInBits() == 16 || isExtendedFrom16Bits(TempOp);13880 if (!OpIs16Bit)13881 return true;13882 13883 auto OtherOpIs16Bit = TempOtherOp.getValueSizeInBits() == 16 ||13884 isExtendedFrom16Bits(TempOtherOp);13885 if (!OtherOpIs16Bit)13886 return true;13887 13888 // Do we cleanly address both13889 return !addresses16Bits(Low16) || !addresses16Bits(Hi16);13890}13891 13892static SDValue getDWordFromOffset(SelectionDAG &DAG, SDLoc SL, SDValue Src,13893 unsigned DWordOffset) {13894 SDValue Ret;13895 13896 auto TypeSize = Src.getValueSizeInBits().getFixedValue();13897 // ByteProvider must be at least 8 bits13898 assert(Src.getValueSizeInBits().isKnownMultipleOf(8));13899 13900 if (TypeSize <= 32)13901 return DAG.getBitcastedAnyExtOrTrunc(Src, SL, MVT::i32);13902 13903 if (Src.getValueType().isVector()) {13904 auto ScalarTySize = Src.getScalarValueSizeInBits();13905 auto ScalarTy = Src.getValueType().getScalarType();13906 if (ScalarTySize == 32) {13907 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, Src,13908 DAG.getConstant(DWordOffset, SL, MVT::i32));13909 }13910 if (ScalarTySize > 32) {13911 Ret = DAG.getNode(13912 ISD::EXTRACT_VECTOR_ELT, SL, ScalarTy, Src,13913 DAG.getConstant(DWordOffset / (ScalarTySize / 32), SL, MVT::i32));13914 auto ShiftVal = 32 * (DWordOffset % (ScalarTySize / 32));13915 if (ShiftVal)13916 Ret = DAG.getNode(ISD::SRL, SL, Ret.getValueType(), Ret,13917 DAG.getConstant(ShiftVal, SL, MVT::i32));13918 return DAG.getBitcastedAnyExtOrTrunc(Ret, SL, MVT::i32);13919 }13920 13921 assert(ScalarTySize < 32);13922 auto NumElements = TypeSize / ScalarTySize;13923 auto Trunc32Elements = (ScalarTySize * NumElements) / 32;13924 auto NormalizedTrunc = Trunc32Elements * 32 / ScalarTySize;13925 auto NumElementsIn32 = 32 / ScalarTySize;13926 auto NumAvailElements = DWordOffset < Trunc32Elements13927 ? NumElementsIn3213928 : NumElements - NormalizedTrunc;13929 13930 SmallVector<SDValue, 4> VecSrcs;13931 DAG.ExtractVectorElements(Src, VecSrcs, DWordOffset * NumElementsIn32,13932 NumAvailElements);13933 13934 Ret = DAG.getBuildVector(13935 MVT::getVectorVT(MVT::getIntegerVT(ScalarTySize), NumAvailElements), SL,13936 VecSrcs);13937 return Ret = DAG.getBitcastedAnyExtOrTrunc(Ret, SL, MVT::i32);13938 }13939 13940 /// Scalar Type13941 auto ShiftVal = 32 * DWordOffset;13942 Ret = DAG.getNode(ISD::SRL, SL, Src.getValueType(), Src,13943 DAG.getConstant(ShiftVal, SL, MVT::i32));13944 return DAG.getBitcastedAnyExtOrTrunc(Ret, SL, MVT::i32);13945}13946 13947static SDValue matchPERM(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) {13948 SelectionDAG &DAG = DCI.DAG;13949 [[maybe_unused]] EVT VT = N->getValueType(0);13950 SmallVector<ByteProvider<SDValue>, 8> PermNodes;13951 13952 // VT is known to be MVT::i32, so we need to provide 4 bytes.13953 assert(VT == MVT::i32);13954 for (int i = 0; i < 4; i++) {13955 // Find the ByteProvider that provides the ith byte of the result of OR13956 std::optional<ByteProvider<SDValue>> P =13957 calculateByteProvider(SDValue(N, 0), i, 0, /*StartingIndex = */ i);13958 // TODO support constantZero13959 if (!P || P->isConstantZero())13960 return SDValue();13961 13962 PermNodes.push_back(*P);13963 }13964 if (PermNodes.size() != 4)13965 return SDValue();13966 13967 std::pair<unsigned, unsigned> FirstSrc(0, PermNodes[0].SrcOffset / 4);13968 std::optional<std::pair<unsigned, unsigned>> SecondSrc;13969 uint64_t PermMask = 0x00000000;13970 for (size_t i = 0; i < PermNodes.size(); i++) {13971 auto PermOp = PermNodes[i];13972 // Since the mask is applied to Src1:Src2, Src1 bytes must be offset13973 // by sizeof(Src2) = 413974 int SrcByteAdjust = 4;13975 13976 // If the Src uses a byte from a different DWORD, then it corresponds13977 // with a difference source13978 if (!PermOp.hasSameSrc(PermNodes[FirstSrc.first]) ||13979 ((PermOp.SrcOffset / 4) != FirstSrc.second)) {13980 if (SecondSrc)13981 if (!PermOp.hasSameSrc(PermNodes[SecondSrc->first]) ||13982 ((PermOp.SrcOffset / 4) != SecondSrc->second))13983 return SDValue();13984 13985 // Set the index of the second distinct Src node13986 SecondSrc = {i, PermNodes[i].SrcOffset / 4};13987 assert(!(PermNodes[SecondSrc->first].Src->getValueSizeInBits() % 8));13988 SrcByteAdjust = 0;13989 }13990 assert((PermOp.SrcOffset % 4) + SrcByteAdjust < 8);13991 assert(!DAG.getDataLayout().isBigEndian());13992 PermMask |= ((PermOp.SrcOffset % 4) + SrcByteAdjust) << (i * 8);13993 }13994 SDLoc DL(N);13995 SDValue Op = *PermNodes[FirstSrc.first].Src;13996 Op = getDWordFromOffset(DAG, DL, Op, FirstSrc.second);13997 assert(Op.getValueSizeInBits() == 32);13998 13999 // Check that we are not just extracting the bytes in order from an op14000 if (!SecondSrc) {14001 int Low16 = PermMask & 0xffff;14002 int Hi16 = (PermMask & 0xffff0000) >> 16;14003 14004 bool WellFormedLow = (Low16 == 0x0504) || (Low16 == 0x0100);14005 bool WellFormedHi = (Hi16 == 0x0706) || (Hi16 == 0x0302);14006 14007 // The perm op would really just produce Op. So combine into Op14008 if (WellFormedLow && WellFormedHi)14009 return DAG.getBitcast(MVT::getIntegerVT(32), Op);14010 }14011 14012 SDValue OtherOp = SecondSrc ? *PermNodes[SecondSrc->first].Src : Op;14013 14014 if (SecondSrc) {14015 OtherOp = getDWordFromOffset(DAG, DL, OtherOp, SecondSrc->second);14016 assert(OtherOp.getValueSizeInBits() == 32);14017 }14018 14019 if (hasNon16BitAccesses(PermMask, Op, OtherOp)) {14020 14021 assert(Op.getValueType().isByteSized() &&14022 OtherOp.getValueType().isByteSized());14023 14024 // If the ultimate src is less than 32 bits, then we will only be14025 // using bytes 0: Op.getValueSizeInBytes() - 1 in the or.14026 // CalculateByteProvider would not have returned Op as source if we14027 // used a byte that is outside its ValueType. Thus, we are free to14028 // ANY_EXTEND as the extended bits are dont-cares.14029 Op = DAG.getBitcastedAnyExtOrTrunc(Op, DL, MVT::i32);14030 OtherOp = DAG.getBitcastedAnyExtOrTrunc(OtherOp, DL, MVT::i32);14031 14032 return DAG.getNode(AMDGPUISD::PERM, DL, MVT::i32, Op, OtherOp,14033 DAG.getConstant(PermMask, DL, MVT::i32));14034 }14035 return SDValue();14036}14037 14038SDValue SITargetLowering::performOrCombine(SDNode *N,14039 DAGCombinerInfo &DCI) const {14040 SelectionDAG &DAG = DCI.DAG;14041 SDValue LHS = N->getOperand(0);14042 SDValue RHS = N->getOperand(1);14043 14044 EVT VT = N->getValueType(0);14045 if (VT == MVT::i1) {14046 // or (fp_class x, c1), (fp_class x, c2) -> fp_class x, (c1 | c2)14047 if (LHS.getOpcode() == AMDGPUISD::FP_CLASS &&14048 RHS.getOpcode() == AMDGPUISD::FP_CLASS) {14049 SDValue Src = LHS.getOperand(0);14050 if (Src != RHS.getOperand(0))14051 return SDValue();14052 14053 const ConstantSDNode *CLHS = dyn_cast<ConstantSDNode>(LHS.getOperand(1));14054 const ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(RHS.getOperand(1));14055 if (!CLHS || !CRHS)14056 return SDValue();14057 14058 // Only 10 bits are used.14059 static const uint32_t MaxMask = 0x3ff;14060 14061 uint32_t NewMask =14062 (CLHS->getZExtValue() | CRHS->getZExtValue()) & MaxMask;14063 SDLoc DL(N);14064 return DAG.getNode(AMDGPUISD::FP_CLASS, DL, MVT::i1, Src,14065 DAG.getConstant(NewMask, DL, MVT::i32));14066 }14067 14068 return SDValue();14069 }14070 14071 // or (perm x, y, c1), c2 -> perm x, y, permute_mask(c1, c2)14072 if (isa<ConstantSDNode>(RHS) && LHS.hasOneUse() &&14073 LHS.getOpcode() == AMDGPUISD::PERM &&14074 isa<ConstantSDNode>(LHS.getOperand(2))) {14075 uint32_t Sel = getConstantPermuteMask(N->getConstantOperandVal(1));14076 if (!Sel)14077 return SDValue();14078 14079 Sel |= LHS.getConstantOperandVal(2);14080 SDLoc DL(N);14081 return DAG.getNode(AMDGPUISD::PERM, DL, MVT::i32, LHS.getOperand(0),14082 LHS.getOperand(1), DAG.getConstant(Sel, DL, MVT::i32));14083 }14084 14085 // or (op x, c1), (op y, c2) -> perm x, y, permute_mask(c1, c2)14086 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();14087 if (VT == MVT::i32 && LHS.hasOneUse() && RHS.hasOneUse() &&14088 N->isDivergent() && TII->pseudoToMCOpcode(AMDGPU::V_PERM_B32_e64) != -1) {14089 14090 // If all the uses of an or need to extract the individual elements, do not14091 // attempt to lower into v_perm14092 auto usesCombinedOperand = [](SDNode *OrUse) {14093 // If we have any non-vectorized use, then it is a candidate for v_perm14094 if (OrUse->getOpcode() != ISD::BITCAST ||14095 !OrUse->getValueType(0).isVector())14096 return true;14097 14098 // If we have any non-vectorized use, then it is a candidate for v_perm14099 for (auto *VUser : OrUse->users()) {14100 if (!VUser->getValueType(0).isVector())14101 return true;14102 14103 // If the use of a vector is a store, then combining via a v_perm14104 // is beneficial.14105 // TODO -- whitelist more uses14106 for (auto VectorwiseOp : {ISD::STORE, ISD::CopyToReg, ISD::CopyFromReg})14107 if (VUser->getOpcode() == VectorwiseOp)14108 return true;14109 }14110 return false;14111 };14112 14113 if (!any_of(N->users(), usesCombinedOperand))14114 return SDValue();14115 14116 uint32_t LHSMask = getPermuteMask(LHS);14117 uint32_t RHSMask = getPermuteMask(RHS);14118 14119 if (LHSMask != ~0u && RHSMask != ~0u) {14120 // Canonicalize the expression in an attempt to have fewer unique masks14121 // and therefore fewer registers used to hold the masks.14122 if (LHSMask > RHSMask) {14123 std::swap(LHSMask, RHSMask);14124 std::swap(LHS, RHS);14125 }14126 14127 // Select 0xc for each lane used from source operand. Zero has 0xc mask14128 // set, 0xff have 0xff in the mask, actual lanes are in the 0-3 range.14129 uint32_t LHSUsedLanes = ~(LHSMask & 0x0c0c0c0c) & 0x0c0c0c0c;14130 uint32_t RHSUsedLanes = ~(RHSMask & 0x0c0c0c0c) & 0x0c0c0c0c;14131 14132 // Check of we need to combine values from two sources within a byte.14133 if (!(LHSUsedLanes & RHSUsedLanes) &&14134 // If we select high and lower word keep it for SDWA.14135 // TODO: teach SDWA to work with v_perm_b32 and remove the check.14136 !(LHSUsedLanes == 0x0c0c0000 && RHSUsedLanes == 0x00000c0c)) {14137 // Kill zero bytes selected by other mask. Zero value is 0xc.14138 LHSMask &= ~RHSUsedLanes;14139 RHSMask &= ~LHSUsedLanes;14140 // Add 4 to each active LHS lane14141 LHSMask |= LHSUsedLanes & 0x04040404;14142 // Combine masks14143 uint32_t Sel = LHSMask | RHSMask;14144 SDLoc DL(N);14145 14146 return DAG.getNode(AMDGPUISD::PERM, DL, MVT::i32, LHS.getOperand(0),14147 RHS.getOperand(0),14148 DAG.getConstant(Sel, DL, MVT::i32));14149 }14150 }14151 if (LHSMask == ~0u || RHSMask == ~0u) {14152 if (SDValue Perm = matchPERM(N, DCI))14153 return Perm;14154 }14155 }14156 14157 // Detect identity v2i32 OR and replace with identity source node.14158 // Specifically an Or that has operands constructed from the same source node14159 // via extract_vector_elt and build_vector. I.E.14160 // v2i32 or(14161 // v2i32 build_vector(14162 // i32 extract_elt(%IdentitySrc, 0),14163 // i32 014164 // ),14165 // v2i32 build_vector(14166 // i32 0,14167 // i32 extract_elt(%IdentitySrc, 1)14168 // ) )14169 // =>14170 // v2i32 %IdentitySrc14171 14172 if (VT == MVT::v2i32 && LHS->getOpcode() == ISD::BUILD_VECTOR &&14173 RHS->getOpcode() == ISD::BUILD_VECTOR) {14174 14175 ConstantSDNode *LC = dyn_cast<ConstantSDNode>(LHS->getOperand(1));14176 ConstantSDNode *RC = dyn_cast<ConstantSDNode>(RHS->getOperand(0));14177 14178 // Test for and normalise build vectors.14179 if (LC && RC && LC->getZExtValue() == 0 && RC->getZExtValue() == 0) {14180 14181 // Get the extract_vector_element operands.14182 SDValue LEVE = LHS->getOperand(0);14183 SDValue REVE = RHS->getOperand(1);14184 14185 if (LEVE->getOpcode() == ISD::EXTRACT_VECTOR_ELT &&14186 REVE->getOpcode() == ISD::EXTRACT_VECTOR_ELT) {14187 // Check that different elements from the same vector are14188 // extracted.14189 if (LEVE->getOperand(0) == REVE->getOperand(0) &&14190 LEVE->getOperand(1) != REVE->getOperand(1)) {14191 SDValue IdentitySrc = LEVE.getOperand(0);14192 return IdentitySrc;14193 }14194 }14195 }14196 }14197 14198 if (VT != MVT::i64 || DCI.isBeforeLegalizeOps())14199 return SDValue();14200 14201 // TODO: This could be a generic combine with a predicate for extracting the14202 // high half of an integer being free.14203 14204 // (or i64:x, (zero_extend i32:y)) ->14205 // i64 (bitcast (v2i32 build_vector (or i32:y, lo_32(x)), hi_32(x)))14206 if (LHS.getOpcode() == ISD::ZERO_EXTEND &&14207 RHS.getOpcode() != ISD::ZERO_EXTEND)14208 std::swap(LHS, RHS);14209 14210 if (RHS.getOpcode() == ISD::ZERO_EXTEND) {14211 SDValue ExtSrc = RHS.getOperand(0);14212 EVT SrcVT = ExtSrc.getValueType();14213 if (SrcVT == MVT::i32) {14214 SDLoc SL(N);14215 auto [LowLHS, HiBits] = split64BitValue(LHS, DAG);14216 SDValue LowOr = DAG.getNode(ISD::OR, SL, MVT::i32, LowLHS, ExtSrc);14217 14218 DCI.AddToWorklist(LowOr.getNode());14219 DCI.AddToWorklist(HiBits.getNode());14220 14221 SDValue Vec =14222 DAG.getNode(ISD::BUILD_VECTOR, SL, MVT::v2i32, LowOr, HiBits);14223 return DAG.getNode(ISD::BITCAST, SL, MVT::i64, Vec);14224 }14225 }14226 14227 const ConstantSDNode *CRHS = dyn_cast<ConstantSDNode>(N->getOperand(1));14228 if (CRHS) {14229 if (SDValue Split = splitBinaryBitConstantOp(DCI, SDLoc(N), ISD::OR,14230 N->getOperand(0), CRHS))14231 return Split;14232 }14233 14234 return SDValue();14235}14236 14237SDValue SITargetLowering::performXorCombine(SDNode *N,14238 DAGCombinerInfo &DCI) const {14239 if (SDValue RV = reassociateScalarOps(N, DCI.DAG))14240 return RV;14241 14242 SDValue LHS = N->getOperand(0);14243 SDValue RHS = N->getOperand(1);14244 14245 const ConstantSDNode *CRHS = isConstOrConstSplat(RHS);14246 SelectionDAG &DAG = DCI.DAG;14247 14248 EVT VT = N->getValueType(0);14249 if (CRHS && VT == MVT::i64) {14250 if (SDValue Split =14251 splitBinaryBitConstantOp(DCI, SDLoc(N), ISD::XOR, LHS, CRHS))14252 return Split;14253 }14254 14255 // v2i32 (xor (vselect cc, x, y), K) ->14256 // (v2i32 svelect cc, (xor x, K), (xor y, K)) This enables the xor to be14257 // replaced with source modifiers when the select is lowered to CNDMASK.14258 unsigned Opc = LHS.getOpcode();14259 if (((Opc == ISD::VSELECT && VT == MVT::v2i32) ||14260 (Opc == ISD::SELECT && VT == MVT::i64)) &&14261 CRHS && CRHS->getAPIntValue().isSignMask()) {14262 SDValue CC = LHS->getOperand(0);14263 SDValue TRUE = LHS->getOperand(1);14264 SDValue FALSE = LHS->getOperand(2);14265 SDValue XTrue = DAG.getNode(ISD::XOR, SDLoc(N), VT, TRUE, RHS);14266 SDValue XFalse = DAG.getNode(ISD::XOR, SDLoc(N), VT, FALSE, RHS);14267 SDValue XSelect =14268 DAG.getNode(ISD::VSELECT, SDLoc(N), VT, CC, XTrue, XFalse);14269 return XSelect;14270 }14271 14272 // Make sure to apply the 64-bit constant splitting fold before trying to fold14273 // fneg-like xors into 64-bit select.14274 if (LHS.getOpcode() == ISD::SELECT && VT == MVT::i32) {14275 // This looks like an fneg, try to fold as a source modifier.14276 if (CRHS && CRHS->getAPIntValue().isSignMask() &&14277 shouldFoldFNegIntoSrc(N, LHS)) {14278 // xor (select c, a, b), 0x80000000 ->14279 // bitcast (select c, (fneg (bitcast a)), (fneg (bitcast b)))14280 SDLoc DL(N);14281 SDValue CastLHS =14282 DAG.getNode(ISD::BITCAST, DL, MVT::f32, LHS->getOperand(1));14283 SDValue CastRHS =14284 DAG.getNode(ISD::BITCAST, DL, MVT::f32, LHS->getOperand(2));14285 SDValue FNegLHS = DAG.getNode(ISD::FNEG, DL, MVT::f32, CastLHS);14286 SDValue FNegRHS = DAG.getNode(ISD::FNEG, DL, MVT::f32, CastRHS);14287 SDValue NewSelect = DAG.getNode(ISD::SELECT, DL, MVT::f32,14288 LHS->getOperand(0), FNegLHS, FNegRHS);14289 return DAG.getNode(ISD::BITCAST, DL, VT, NewSelect);14290 }14291 }14292 14293 return SDValue();14294}14295 14296SDValue SITargetLowering::performZeroExtendCombine(SDNode *N,14297 DAGCombinerInfo &DCI) const {14298 if (!Subtarget->has16BitInsts() ||14299 DCI.getDAGCombineLevel() < AfterLegalizeDAG)14300 return SDValue();14301 14302 EVT VT = N->getValueType(0);14303 if (VT != MVT::i32)14304 return SDValue();14305 14306 SDValue Src = N->getOperand(0);14307 if (Src.getValueType() != MVT::i16)14308 return SDValue();14309 14310 return SDValue();14311}14312 14313SDValue14314SITargetLowering::performSignExtendInRegCombine(SDNode *N,14315 DAGCombinerInfo &DCI) const {14316 SDValue Src = N->getOperand(0);14317 auto *VTSign = cast<VTSDNode>(N->getOperand(1));14318 14319 // Combine s_buffer_load_u8 or s_buffer_load_u16 with sext and replace them14320 // with s_buffer_load_i8 and s_buffer_load_i16 respectively.14321 if (((Src.getOpcode() == AMDGPUISD::SBUFFER_LOAD_UBYTE &&14322 VTSign->getVT() == MVT::i8) ||14323 (Src.getOpcode() == AMDGPUISD::SBUFFER_LOAD_USHORT &&14324 VTSign->getVT() == MVT::i16))) {14325 assert(Subtarget->hasScalarSubwordLoads() &&14326 "s_buffer_load_{u8, i8} are supported "14327 "in GFX12 (or newer) architectures.");14328 EVT VT = Src.getValueType();14329 unsigned Opc = (Src.getOpcode() == AMDGPUISD::SBUFFER_LOAD_UBYTE)14330 ? AMDGPUISD::SBUFFER_LOAD_BYTE14331 : AMDGPUISD::SBUFFER_LOAD_SHORT;14332 SDLoc DL(N);14333 SDVTList ResList = DCI.DAG.getVTList(MVT::i32);14334 SDValue Ops[] = {14335 Src.getOperand(0), // source register14336 Src.getOperand(1), // offset14337 Src.getOperand(2) // cachePolicy14338 };14339 auto *M = cast<MemSDNode>(Src);14340 SDValue BufferLoad = DCI.DAG.getMemIntrinsicNode(14341 Opc, DL, ResList, Ops, M->getMemoryVT(), M->getMemOperand());14342 SDValue LoadVal = DCI.DAG.getNode(ISD::TRUNCATE, DL, VT, BufferLoad);14343 return LoadVal;14344 }14345 if (((Src.getOpcode() == AMDGPUISD::BUFFER_LOAD_UBYTE &&14346 VTSign->getVT() == MVT::i8) ||14347 (Src.getOpcode() == AMDGPUISD::BUFFER_LOAD_USHORT &&14348 VTSign->getVT() == MVT::i16)) &&14349 Src.hasOneUse()) {14350 auto *M = cast<MemSDNode>(Src);14351 SDValue Ops[] = {Src.getOperand(0), // Chain14352 Src.getOperand(1), // rsrc14353 Src.getOperand(2), // vindex14354 Src.getOperand(3), // voffset14355 Src.getOperand(4), // soffset14356 Src.getOperand(5), // offset14357 Src.getOperand(6), Src.getOperand(7)};14358 // replace with BUFFER_LOAD_BYTE/SHORT14359 SDVTList ResList =14360 DCI.DAG.getVTList(MVT::i32, Src.getOperand(0).getValueType());14361 unsigned Opc = (Src.getOpcode() == AMDGPUISD::BUFFER_LOAD_UBYTE)14362 ? AMDGPUISD::BUFFER_LOAD_BYTE14363 : AMDGPUISD::BUFFER_LOAD_SHORT;14364 SDValue BufferLoadSignExt = DCI.DAG.getMemIntrinsicNode(14365 Opc, SDLoc(N), ResList, Ops, M->getMemoryVT(), M->getMemOperand());14366 return DCI.DAG.getMergeValues(14367 {BufferLoadSignExt, BufferLoadSignExt.getValue(1)}, SDLoc(N));14368 }14369 return SDValue();14370}14371 14372SDValue SITargetLowering::performClassCombine(SDNode *N,14373 DAGCombinerInfo &DCI) const {14374 SelectionDAG &DAG = DCI.DAG;14375 SDValue Mask = N->getOperand(1);14376 14377 // fp_class x, 0 -> false14378 if (isNullConstant(Mask))14379 return DAG.getConstant(0, SDLoc(N), MVT::i1);14380 14381 if (N->getOperand(0).isUndef())14382 return DAG.getUNDEF(MVT::i1);14383 14384 return SDValue();14385}14386 14387SDValue SITargetLowering::performRcpCombine(SDNode *N,14388 DAGCombinerInfo &DCI) const {14389 EVT VT = N->getValueType(0);14390 SDValue N0 = N->getOperand(0);14391 14392 if (N0.isUndef()) {14393 return DCI.DAG.getConstantFP(APFloat::getQNaN(VT.getFltSemantics()),14394 SDLoc(N), VT);14395 }14396 14397 if (VT == MVT::f32 && (N0.getOpcode() == ISD::UINT_TO_FP ||14398 N0.getOpcode() == ISD::SINT_TO_FP)) {14399 return DCI.DAG.getNode(AMDGPUISD::RCP_IFLAG, SDLoc(N), VT, N0,14400 N->getFlags());14401 }14402 14403 // TODO: Could handle f32 + amdgcn.sqrt but probably never reaches here.14404 if ((VT == MVT::f16 && N0.getOpcode() == ISD::FSQRT) &&14405 N->getFlags().hasAllowContract() && N0->getFlags().hasAllowContract()) {14406 return DCI.DAG.getNode(AMDGPUISD::RSQ, SDLoc(N), VT, N0.getOperand(0),14407 N->getFlags());14408 }14409 14410 return AMDGPUTargetLowering::performRcpCombine(N, DCI);14411}14412 14413bool SITargetLowering::isCanonicalized(SelectionDAG &DAG, SDValue Op,14414 unsigned MaxDepth) const {14415 unsigned Opcode = Op.getOpcode();14416 if (Opcode == ISD::FCANONICALIZE)14417 return true;14418 14419 if (auto *CFP = dyn_cast<ConstantFPSDNode>(Op)) {14420 const auto &F = CFP->getValueAPF();14421 if (F.isNaN() && F.isSignaling())14422 return false;14423 if (!F.isDenormal())14424 return true;14425 14426 DenormalMode Mode =14427 DAG.getMachineFunction().getDenormalMode(F.getSemantics());14428 return Mode == DenormalMode::getIEEE();14429 }14430 14431 // If source is a result of another standard FP operation it is already in14432 // canonical form.14433 if (MaxDepth == 0)14434 return false;14435 14436 switch (Opcode) {14437 // These will flush denorms if required.14438 case ISD::FADD:14439 case ISD::FSUB:14440 case ISD::FMUL:14441 case ISD::FCEIL:14442 case ISD::FFLOOR:14443 case ISD::FMA:14444 case ISD::FMAD:14445 case ISD::FSQRT:14446 case ISD::FDIV:14447 case ISD::FREM:14448 case ISD::FP_ROUND:14449 case ISD::FP_EXTEND:14450 case ISD::FP16_TO_FP:14451 case ISD::FP_TO_FP16:14452 case ISD::BF16_TO_FP:14453 case ISD::FP_TO_BF16:14454 case ISD::FLDEXP:14455 case AMDGPUISD::FMUL_LEGACY:14456 case AMDGPUISD::FMAD_FTZ:14457 case AMDGPUISD::RCP:14458 case AMDGPUISD::RSQ:14459 case AMDGPUISD::RSQ_CLAMP:14460 case AMDGPUISD::RCP_LEGACY:14461 case AMDGPUISD::RCP_IFLAG:14462 case AMDGPUISD::LOG:14463 case AMDGPUISD::EXP:14464 case AMDGPUISD::DIV_SCALE:14465 case AMDGPUISD::DIV_FMAS:14466 case AMDGPUISD::DIV_FIXUP:14467 case AMDGPUISD::FRACT:14468 case AMDGPUISD::CVT_PKRTZ_F16_F32:14469 case AMDGPUISD::CVT_F32_UBYTE0:14470 case AMDGPUISD::CVT_F32_UBYTE1:14471 case AMDGPUISD::CVT_F32_UBYTE2:14472 case AMDGPUISD::CVT_F32_UBYTE3:14473 case AMDGPUISD::FP_TO_FP16:14474 case AMDGPUISD::SIN_HW:14475 case AMDGPUISD::COS_HW:14476 return true;14477 14478 // It can/will be lowered or combined as a bit operation.14479 // Need to check their input recursively to handle.14480 case ISD::FNEG:14481 case ISD::FABS:14482 case ISD::FCOPYSIGN:14483 return isCanonicalized(DAG, Op.getOperand(0), MaxDepth - 1);14484 14485 case ISD::AND:14486 if (Op.getValueType() == MVT::i32) {14487 // Be careful as we only know it is a bitcast floating point type. It14488 // could be f32, v2f16, we have no way of knowing. Luckily the constant14489 // value that we optimize for, which comes up in fp32 to bf16 conversions,14490 // is valid to optimize for all types.14491 if (auto *RHS = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {14492 if (RHS->getZExtValue() == 0xffff0000) {14493 return isCanonicalized(DAG, Op.getOperand(0), MaxDepth - 1);14494 }14495 }14496 }14497 break;14498 14499 case ISD::FSIN:14500 case ISD::FCOS:14501 case ISD::FSINCOS:14502 return Op.getValueType().getScalarType() != MVT::f16;14503 14504 case ISD::FMINNUM:14505 case ISD::FMAXNUM:14506 case ISD::FMINNUM_IEEE:14507 case ISD::FMAXNUM_IEEE:14508 case ISD::FMINIMUM:14509 case ISD::FMAXIMUM:14510 case ISD::FMINIMUMNUM:14511 case ISD::FMAXIMUMNUM:14512 case AMDGPUISD::CLAMP:14513 case AMDGPUISD::FMED3:14514 case AMDGPUISD::FMAX3:14515 case AMDGPUISD::FMIN3:14516 case AMDGPUISD::FMAXIMUM3:14517 case AMDGPUISD::FMINIMUM3: {14518 // FIXME: Shouldn't treat the generic operations different based these.14519 // However, we aren't really required to flush the result from14520 // minnum/maxnum..14521 14522 // snans will be quieted, so we only need to worry about denormals.14523 if (Subtarget->supportsMinMaxDenormModes() ||14524 // FIXME: denormalsEnabledForType is broken for dynamic14525 denormalsEnabledForType(DAG, Op.getValueType()))14526 return true;14527 14528 // Flushing may be required.14529 // In pre-GFX9 targets V_MIN_F32 and others do not flush denorms. For such14530 // targets need to check their input recursively.14531 14532 // FIXME: Does this apply with clamp? It's implemented with max.14533 for (unsigned I = 0, E = Op.getNumOperands(); I != E; ++I) {14534 if (!isCanonicalized(DAG, Op.getOperand(I), MaxDepth - 1))14535 return false;14536 }14537 14538 return true;14539 }14540 case ISD::SELECT: {14541 return isCanonicalized(DAG, Op.getOperand(1), MaxDepth - 1) &&14542 isCanonicalized(DAG, Op.getOperand(2), MaxDepth - 1);14543 }14544 case ISD::BUILD_VECTOR: {14545 for (unsigned i = 0, e = Op.getNumOperands(); i != e; ++i) {14546 SDValue SrcOp = Op.getOperand(i);14547 if (!isCanonicalized(DAG, SrcOp, MaxDepth - 1))14548 return false;14549 }14550 14551 return true;14552 }14553 case ISD::EXTRACT_VECTOR_ELT:14554 case ISD::EXTRACT_SUBVECTOR: {14555 return isCanonicalized(DAG, Op.getOperand(0), MaxDepth - 1);14556 }14557 case ISD::INSERT_VECTOR_ELT: {14558 return isCanonicalized(DAG, Op.getOperand(0), MaxDepth - 1) &&14559 isCanonicalized(DAG, Op.getOperand(1), MaxDepth - 1);14560 }14561 case ISD::UNDEF:14562 // Could be anything.14563 return false;14564 14565 case ISD::BITCAST:14566 // TODO: This is incorrect as it loses track of the operand's type. We may14567 // end up effectively bitcasting from f32 to v2f16 or vice versa, and the14568 // same bits that are canonicalized in one type need not be in the other.14569 return isCanonicalized(DAG, Op.getOperand(0), MaxDepth - 1);14570 case ISD::TRUNCATE: {14571 // Hack round the mess we make when legalizing extract_vector_elt14572 if (Op.getValueType() == MVT::i16) {14573 SDValue TruncSrc = Op.getOperand(0);14574 if (TruncSrc.getValueType() == MVT::i32 &&14575 TruncSrc.getOpcode() == ISD::BITCAST &&14576 TruncSrc.getOperand(0).getValueType() == MVT::v2f16) {14577 return isCanonicalized(DAG, TruncSrc.getOperand(0), MaxDepth - 1);14578 }14579 }14580 return false;14581 }14582 case ISD::INTRINSIC_WO_CHAIN: {14583 unsigned IntrinsicID = Op.getConstantOperandVal(0);14584 // TODO: Handle more intrinsics14585 switch (IntrinsicID) {14586 case Intrinsic::amdgcn_cvt_pkrtz:14587 case Intrinsic::amdgcn_cubeid:14588 case Intrinsic::amdgcn_frexp_mant:14589 case Intrinsic::amdgcn_fdot2:14590 case Intrinsic::amdgcn_rcp:14591 case Intrinsic::amdgcn_rsq:14592 case Intrinsic::amdgcn_rsq_clamp:14593 case Intrinsic::amdgcn_rcp_legacy:14594 case Intrinsic::amdgcn_rsq_legacy:14595 case Intrinsic::amdgcn_trig_preop:14596 case Intrinsic::amdgcn_tanh:14597 case Intrinsic::amdgcn_log:14598 case Intrinsic::amdgcn_exp2:14599 case Intrinsic::amdgcn_sqrt:14600 return true;14601 default:14602 break;14603 }14604 14605 break;14606 }14607 default:14608 break;14609 }14610 14611 // FIXME: denormalsEnabledForType is broken for dynamic14612 return denormalsEnabledForType(DAG, Op.getValueType()) &&14613 DAG.isKnownNeverSNaN(Op);14614}14615 14616bool SITargetLowering::isCanonicalized(Register Reg, const MachineFunction &MF,14617 unsigned MaxDepth) const {14618 const MachineRegisterInfo &MRI = MF.getRegInfo();14619 MachineInstr *MI = MRI.getVRegDef(Reg);14620 unsigned Opcode = MI->getOpcode();14621 14622 if (Opcode == AMDGPU::G_FCANONICALIZE)14623 return true;14624 14625 std::optional<FPValueAndVReg> FCR;14626 // Constant splat (can be padded with undef) or scalar constant.14627 if (mi_match(Reg, MRI, MIPatternMatch::m_GFCstOrSplat(FCR))) {14628 if (FCR->Value.isSignaling())14629 return false;14630 if (!FCR->Value.isDenormal())14631 return true;14632 14633 DenormalMode Mode = MF.getDenormalMode(FCR->Value.getSemantics());14634 return Mode == DenormalMode::getIEEE();14635 }14636 14637 if (MaxDepth == 0)14638 return false;14639 14640 switch (Opcode) {14641 case AMDGPU::G_FADD:14642 case AMDGPU::G_FSUB:14643 case AMDGPU::G_FMUL:14644 case AMDGPU::G_FCEIL:14645 case AMDGPU::G_FFLOOR:14646 case AMDGPU::G_FRINT:14647 case AMDGPU::G_FNEARBYINT:14648 case AMDGPU::G_INTRINSIC_FPTRUNC_ROUND:14649 case AMDGPU::G_INTRINSIC_TRUNC:14650 case AMDGPU::G_INTRINSIC_ROUNDEVEN:14651 case AMDGPU::G_FMA:14652 case AMDGPU::G_FMAD:14653 case AMDGPU::G_FSQRT:14654 case AMDGPU::G_FDIV:14655 case AMDGPU::G_FREM:14656 case AMDGPU::G_FPOW:14657 case AMDGPU::G_FPEXT:14658 case AMDGPU::G_FLOG:14659 case AMDGPU::G_FLOG2:14660 case AMDGPU::G_FLOG10:14661 case AMDGPU::G_FPTRUNC:14662 case AMDGPU::G_AMDGPU_RCP_IFLAG:14663 case AMDGPU::G_AMDGPU_CVT_F32_UBYTE0:14664 case AMDGPU::G_AMDGPU_CVT_F32_UBYTE1:14665 case AMDGPU::G_AMDGPU_CVT_F32_UBYTE2:14666 case AMDGPU::G_AMDGPU_CVT_F32_UBYTE3:14667 return true;14668 case AMDGPU::G_FNEG:14669 case AMDGPU::G_FABS:14670 case AMDGPU::G_FCOPYSIGN:14671 return isCanonicalized(MI->getOperand(1).getReg(), MF, MaxDepth - 1);14672 case AMDGPU::G_FMINNUM:14673 case AMDGPU::G_FMAXNUM:14674 case AMDGPU::G_FMINNUM_IEEE:14675 case AMDGPU::G_FMAXNUM_IEEE:14676 case AMDGPU::G_FMINIMUM:14677 case AMDGPU::G_FMAXIMUM:14678 case AMDGPU::G_FMINIMUMNUM:14679 case AMDGPU::G_FMAXIMUMNUM: {14680 if (Subtarget->supportsMinMaxDenormModes() ||14681 // FIXME: denormalsEnabledForType is broken for dynamic14682 denormalsEnabledForType(MRI.getType(Reg), MF))14683 return true;14684 14685 [[fallthrough]];14686 }14687 case AMDGPU::G_BUILD_VECTOR:14688 for (const MachineOperand &MO : llvm::drop_begin(MI->operands()))14689 if (!isCanonicalized(MO.getReg(), MF, MaxDepth - 1))14690 return false;14691 return true;14692 case AMDGPU::G_INTRINSIC:14693 case AMDGPU::G_INTRINSIC_CONVERGENT:14694 switch (cast<GIntrinsic>(MI)->getIntrinsicID()) {14695 case Intrinsic::amdgcn_fmul_legacy:14696 case Intrinsic::amdgcn_fmad_ftz:14697 case Intrinsic::amdgcn_sqrt:14698 case Intrinsic::amdgcn_fmed3:14699 case Intrinsic::amdgcn_sin:14700 case Intrinsic::amdgcn_cos:14701 case Intrinsic::amdgcn_log:14702 case Intrinsic::amdgcn_exp2:14703 case Intrinsic::amdgcn_log_clamp:14704 case Intrinsic::amdgcn_rcp:14705 case Intrinsic::amdgcn_rcp_legacy:14706 case Intrinsic::amdgcn_rsq:14707 case Intrinsic::amdgcn_rsq_clamp:14708 case Intrinsic::amdgcn_rsq_legacy:14709 case Intrinsic::amdgcn_div_scale:14710 case Intrinsic::amdgcn_div_fmas:14711 case Intrinsic::amdgcn_div_fixup:14712 case Intrinsic::amdgcn_fract:14713 case Intrinsic::amdgcn_cvt_pkrtz:14714 case Intrinsic::amdgcn_cubeid:14715 case Intrinsic::amdgcn_cubema:14716 case Intrinsic::amdgcn_cubesc:14717 case Intrinsic::amdgcn_cubetc:14718 case Intrinsic::amdgcn_frexp_mant:14719 case Intrinsic::amdgcn_fdot2:14720 case Intrinsic::amdgcn_trig_preop:14721 case Intrinsic::amdgcn_tanh:14722 return true;14723 default:14724 break;14725 }14726 14727 [[fallthrough]];14728 default:14729 return false;14730 }14731 14732 llvm_unreachable("invalid operation");14733}14734 14735// Constant fold canonicalize.14736SDValue SITargetLowering::getCanonicalConstantFP(SelectionDAG &DAG,14737 const SDLoc &SL, EVT VT,14738 const APFloat &C) const {14739 // Flush denormals to 0 if not enabled.14740 if (C.isDenormal()) {14741 DenormalMode Mode =14742 DAG.getMachineFunction().getDenormalMode(C.getSemantics());14743 if (Mode == DenormalMode::getPreserveSign()) {14744 return DAG.getConstantFP(14745 APFloat::getZero(C.getSemantics(), C.isNegative()), SL, VT);14746 }14747 14748 if (Mode != DenormalMode::getIEEE())14749 return SDValue();14750 }14751 14752 if (C.isNaN()) {14753 APFloat CanonicalQNaN = APFloat::getQNaN(C.getSemantics());14754 if (C.isSignaling()) {14755 // Quiet a signaling NaN.14756 // FIXME: Is this supposed to preserve payload bits?14757 return DAG.getConstantFP(CanonicalQNaN, SL, VT);14758 }14759 14760 // Make sure it is the canonical NaN bitpattern.14761 //14762 // TODO: Can we use -1 as the canonical NaN value since it's an inline14763 // immediate?14764 if (C.bitcastToAPInt() != CanonicalQNaN.bitcastToAPInt())14765 return DAG.getConstantFP(CanonicalQNaN, SL, VT);14766 }14767 14768 // Already canonical.14769 return DAG.getConstantFP(C, SL, VT);14770}14771 14772static bool vectorEltWillFoldAway(SDValue Op) {14773 return Op.isUndef() || isa<ConstantFPSDNode>(Op);14774}14775 14776SDValue14777SITargetLowering::performFCanonicalizeCombine(SDNode *N,14778 DAGCombinerInfo &DCI) const {14779 SelectionDAG &DAG = DCI.DAG;14780 SDValue N0 = N->getOperand(0);14781 EVT VT = N->getValueType(0);14782 14783 // fcanonicalize undef -> qnan14784 if (N0.isUndef()) {14785 APFloat QNaN = APFloat::getQNaN(VT.getFltSemantics());14786 return DAG.getConstantFP(QNaN, SDLoc(N), VT);14787 }14788 14789 if (ConstantFPSDNode *CFP = isConstOrConstSplatFP(N0)) {14790 EVT VT = N->getValueType(0);14791 return getCanonicalConstantFP(DAG, SDLoc(N), VT, CFP->getValueAPF());14792 }14793 14794 // fcanonicalize (build_vector x, k) -> build_vector (fcanonicalize x),14795 // (fcanonicalize k)14796 //14797 // fcanonicalize (build_vector x, undef) -> build_vector (fcanonicalize x), 014798 14799 // TODO: This could be better with wider vectors that will be split to v2f16,14800 // and to consider uses since there aren't that many packed operations.14801 if (N0.getOpcode() == ISD::BUILD_VECTOR && VT == MVT::v2f16 &&14802 isTypeLegal(MVT::v2f16)) {14803 SDLoc SL(N);14804 SDValue NewElts[2];14805 SDValue Lo = N0.getOperand(0);14806 SDValue Hi = N0.getOperand(1);14807 EVT EltVT = Lo.getValueType();14808 14809 if (vectorEltWillFoldAway(Lo) || vectorEltWillFoldAway(Hi)) {14810 for (unsigned I = 0; I != 2; ++I) {14811 SDValue Op = N0.getOperand(I);14812 if (ConstantFPSDNode *CFP = dyn_cast<ConstantFPSDNode>(Op)) {14813 NewElts[I] =14814 getCanonicalConstantFP(DAG, SL, EltVT, CFP->getValueAPF());14815 } else if (Op.isUndef()) {14816 // Handled below based on what the other operand is.14817 NewElts[I] = Op;14818 } else {14819 NewElts[I] = DAG.getNode(ISD::FCANONICALIZE, SL, EltVT, Op);14820 }14821 }14822 14823 // If one half is undef, and one is constant, prefer a splat vector rather14824 // than the normal qNaN. If it's a register, prefer 0.0 since that's14825 // cheaper to use and may be free with a packed operation.14826 if (NewElts[0].isUndef()) {14827 if (isa<ConstantFPSDNode>(NewElts[1]))14828 NewElts[0] = isa<ConstantFPSDNode>(NewElts[1])14829 ? NewElts[1]14830 : DAG.getConstantFP(0.0f, SL, EltVT);14831 }14832 14833 if (NewElts[1].isUndef()) {14834 NewElts[1] = isa<ConstantFPSDNode>(NewElts[0])14835 ? NewElts[0]14836 : DAG.getConstantFP(0.0f, SL, EltVT);14837 }14838 14839 return DAG.getBuildVector(VT, SL, NewElts);14840 }14841 }14842 14843 return SDValue();14844}14845 14846static unsigned minMaxOpcToMin3Max3Opc(unsigned Opc) {14847 switch (Opc) {14848 case ISD::FMAXNUM:14849 case ISD::FMAXNUM_IEEE:14850 case ISD::FMAXIMUMNUM:14851 return AMDGPUISD::FMAX3;14852 case ISD::FMAXIMUM:14853 return AMDGPUISD::FMAXIMUM3;14854 case ISD::SMAX:14855 return AMDGPUISD::SMAX3;14856 case ISD::UMAX:14857 return AMDGPUISD::UMAX3;14858 case ISD::FMINNUM:14859 case ISD::FMINNUM_IEEE:14860 case ISD::FMINIMUMNUM:14861 return AMDGPUISD::FMIN3;14862 case ISD::FMINIMUM:14863 return AMDGPUISD::FMINIMUM3;14864 case ISD::SMIN:14865 return AMDGPUISD::SMIN3;14866 case ISD::UMIN:14867 return AMDGPUISD::UMIN3;14868 default:14869 llvm_unreachable("Not a min/max opcode");14870 }14871}14872 14873SDValue SITargetLowering::performIntMed3ImmCombine(SelectionDAG &DAG,14874 const SDLoc &SL, SDValue Src,14875 SDValue MinVal,14876 SDValue MaxVal,14877 bool Signed) const {14878 14879 // med3 comes from14880 // min(max(x, K0), K1), K0 < K114881 // max(min(x, K0), K1), K1 < K014882 //14883 // "MinVal" and "MaxVal" respectively refer to the rhs of the14884 // min/max op.14885 ConstantSDNode *MinK = dyn_cast<ConstantSDNode>(MinVal);14886 ConstantSDNode *MaxK = dyn_cast<ConstantSDNode>(MaxVal);14887 14888 if (!MinK || !MaxK)14889 return SDValue();14890 14891 if (Signed) {14892 if (MaxK->getAPIntValue().sge(MinK->getAPIntValue()))14893 return SDValue();14894 } else {14895 if (MaxK->getAPIntValue().uge(MinK->getAPIntValue()))14896 return SDValue();14897 }14898 14899 EVT VT = MinK->getValueType(0);14900 unsigned Med3Opc = Signed ? AMDGPUISD::SMED3 : AMDGPUISD::UMED3;14901 if (VT == MVT::i32 || (VT == MVT::i16 && Subtarget->hasMed3_16()))14902 return DAG.getNode(Med3Opc, SL, VT, Src, MaxVal, MinVal);14903 14904 // Note: we could also extend to i32 and use i32 med3 if i16 med3 is14905 // not available, but this is unlikely to be profitable as constants14906 // will often need to be materialized & extended, especially on14907 // pre-GFX10 where VOP3 instructions couldn't take literal operands.14908 return SDValue();14909}14910 14911static ConstantFPSDNode *getSplatConstantFP(SDValue Op) {14912 if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Op))14913 return C;14914 14915 if (BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(Op)) {14916 if (ConstantFPSDNode *C = BV->getConstantFPSplatNode())14917 return C;14918 }14919 14920 return nullptr;14921}14922 14923SDValue SITargetLowering::performFPMed3ImmCombine(SelectionDAG &DAG,14924 const SDLoc &SL, SDValue Op0,14925 SDValue Op1) const {14926 ConstantFPSDNode *K1 = getSplatConstantFP(Op1);14927 if (!K1)14928 return SDValue();14929 14930 ConstantFPSDNode *K0 = getSplatConstantFP(Op0.getOperand(1));14931 if (!K0)14932 return SDValue();14933 14934 // Ordered >= (although NaN inputs should have folded away by now).14935 if (K0->getValueAPF() > K1->getValueAPF())14936 return SDValue();14937 14938 // med3 with a nan input acts like14939 // v_min_f32(v_min_f32(S0.f32, S1.f32), S2.f32)14940 //14941 // So the result depends on whether the IEEE mode bit is enabled or not with a14942 // signaling nan input.14943 // ieee=114944 // s0 snan: yields s214945 // s1 snan: yields s214946 // s2 snan: qnan14947 14948 // s0 qnan: min(s1, s2)14949 // s1 qnan: min(s0, s2)14950 // s2 qnan: min(s0, s1)14951 14952 // ieee=014953 // s0 snan: min(s1, s2)14954 // s1 snan: min(s0, s2)14955 // s2 snan: qnan14956 14957 // s0 qnan: min(s1, s2)14958 // s1 qnan: min(s0, s2)14959 // s2 qnan: min(s0, s1)14960 const MachineFunction &MF = DAG.getMachineFunction();14961 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();14962 14963 // TODO: Check IEEE bit enabled. We can form fmed3 with IEEE=0 regardless of14964 // whether the input is a signaling nan if op0 is fmaximum or fmaximumnum. We14965 // can only form if op0 is fmaxnum_ieee if IEEE=1.14966 EVT VT = Op0.getValueType();14967 if (Info->getMode().DX10Clamp) {14968 // If dx10_clamp is enabled, NaNs clamp to 0.0. This is the same as the14969 // hardware fmed3 behavior converting to a min.14970 // FIXME: Should this be allowing -0.0?14971 if (K1->isExactlyValue(1.0) && K0->isExactlyValue(0.0))14972 return DAG.getNode(AMDGPUISD::CLAMP, SL, VT, Op0.getOperand(0));14973 }14974 14975 // med3 for f16 is only available on gfx9+, and not available for v2f16.14976 if (VT == MVT::f32 || (VT == MVT::f16 && Subtarget->hasMed3_16())) {14977 // This isn't safe with signaling NaNs because in IEEE mode, min/max on a14978 // signaling NaN gives a quiet NaN. The quiet NaN input to the min would14979 // then give the other result, which is different from med3 with a NaN14980 // input.14981 SDValue Var = Op0.getOperand(0);14982 if (!DAG.isKnownNeverSNaN(Var))14983 return SDValue();14984 14985 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();14986 14987 if ((!K0->hasOneUse() || TII->isInlineConstant(K0->getValueAPF())) &&14988 (!K1->hasOneUse() || TII->isInlineConstant(K1->getValueAPF()))) {14989 return DAG.getNode(AMDGPUISD::FMED3, SL, K0->getValueType(0), Var,14990 SDValue(K0, 0), SDValue(K1, 0));14991 }14992 }14993 14994 return SDValue();14995}14996 14997/// \return true if the subtarget supports minimum3 and maximum3 with the given14998/// base min/max opcode \p Opc for type \p VT.14999static bool supportsMin3Max3(const GCNSubtarget &Subtarget, unsigned Opc,15000 EVT VT) {15001 switch (Opc) {15002 case ISD::FMINNUM:15003 case ISD::FMAXNUM:15004 case ISD::FMINNUM_IEEE:15005 case ISD::FMAXNUM_IEEE:15006 case ISD::FMINIMUMNUM:15007 case ISD::FMAXIMUMNUM:15008 case AMDGPUISD::FMIN_LEGACY:15009 case AMDGPUISD::FMAX_LEGACY:15010 return (VT == MVT::f32) || (VT == MVT::f16 && Subtarget.hasMin3Max3_16()) ||15011 (VT == MVT::v2f16 && Subtarget.hasMin3Max3PKF16());15012 case ISD::FMINIMUM:15013 case ISD::FMAXIMUM:15014 return (VT == MVT::f32 && Subtarget.hasMinimum3Maximum3F32()) ||15015 (VT == MVT::f16 && Subtarget.hasMinimum3Maximum3F16()) ||15016 (VT == MVT::v2f16 && Subtarget.hasMinimum3Maximum3PKF16());15017 case ISD::SMAX:15018 case ISD::SMIN:15019 case ISD::UMAX:15020 case ISD::UMIN:15021 return (VT == MVT::i32) || (VT == MVT::i16 && Subtarget.hasMin3Max3_16());15022 default:15023 return false;15024 }15025 15026 llvm_unreachable("not a min/max opcode");15027}15028 15029SDValue SITargetLowering::performMinMaxCombine(SDNode *N,15030 DAGCombinerInfo &DCI) const {15031 SelectionDAG &DAG = DCI.DAG;15032 15033 EVT VT = N->getValueType(0);15034 unsigned Opc = N->getOpcode();15035 SDValue Op0 = N->getOperand(0);15036 SDValue Op1 = N->getOperand(1);15037 15038 // Only do this if the inner op has one use since this will just increases15039 // register pressure for no benefit.15040 15041 if (supportsMin3Max3(*Subtarget, Opc, VT)) {15042 // max(max(a, b), c) -> max3(a, b, c)15043 // min(min(a, b), c) -> min3(a, b, c)15044 if (Op0.getOpcode() == Opc && Op0.hasOneUse()) {15045 SDLoc DL(N);15046 return DAG.getNode(minMaxOpcToMin3Max3Opc(Opc), DL, N->getValueType(0),15047 Op0.getOperand(0), Op0.getOperand(1), Op1);15048 }15049 15050 // Try commuted.15051 // max(a, max(b, c)) -> max3(a, b, c)15052 // min(a, min(b, c)) -> min3(a, b, c)15053 if (Op1.getOpcode() == Opc && Op1.hasOneUse()) {15054 SDLoc DL(N);15055 return DAG.getNode(minMaxOpcToMin3Max3Opc(Opc), DL, N->getValueType(0),15056 Op0, Op1.getOperand(0), Op1.getOperand(1));15057 }15058 }15059 15060 // min(max(x, K0), K1), K0 < K1 -> med3(x, K0, K1)15061 // max(min(x, K0), K1), K1 < K0 -> med3(x, K1, K0)15062 if (Opc == ISD::SMIN && Op0.getOpcode() == ISD::SMAX && Op0.hasOneUse()) {15063 if (SDValue Med3 = performIntMed3ImmCombine(15064 DAG, SDLoc(N), Op0->getOperand(0), Op1, Op0->getOperand(1), true))15065 return Med3;15066 }15067 if (Opc == ISD::SMAX && Op0.getOpcode() == ISD::SMIN && Op0.hasOneUse()) {15068 if (SDValue Med3 = performIntMed3ImmCombine(15069 DAG, SDLoc(N), Op0->getOperand(0), Op0->getOperand(1), Op1, true))15070 return Med3;15071 }15072 15073 if (Opc == ISD::UMIN && Op0.getOpcode() == ISD::UMAX && Op0.hasOneUse()) {15074 if (SDValue Med3 = performIntMed3ImmCombine(15075 DAG, SDLoc(N), Op0->getOperand(0), Op1, Op0->getOperand(1), false))15076 return Med3;15077 }15078 if (Opc == ISD::UMAX && Op0.getOpcode() == ISD::UMIN && Op0.hasOneUse()) {15079 if (SDValue Med3 = performIntMed3ImmCombine(15080 DAG, SDLoc(N), Op0->getOperand(0), Op0->getOperand(1), Op1, false))15081 return Med3;15082 }15083 15084 // if !is_snan(x):15085 // fminnum(fmaxnum(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1)15086 // fminnum_ieee(fmaxnum_ieee(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1)15087 // fminnumnum(fmaxnumnum(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1)15088 // fmin_legacy(fmax_legacy(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1)15089 if (((Opc == ISD::FMINNUM && Op0.getOpcode() == ISD::FMAXNUM) ||15090 (Opc == ISD::FMINNUM_IEEE && Op0.getOpcode() == ISD::FMAXNUM_IEEE) ||15091 (Opc == ISD::FMINIMUMNUM && Op0.getOpcode() == ISD::FMAXIMUMNUM) ||15092 (Opc == AMDGPUISD::FMIN_LEGACY &&15093 Op0.getOpcode() == AMDGPUISD::FMAX_LEGACY)) &&15094 (VT == MVT::f32 || VT == MVT::f64 ||15095 (VT == MVT::f16 && Subtarget->has16BitInsts()) ||15096 (VT == MVT::bf16 && Subtarget->hasBF16PackedInsts()) ||15097 (VT == MVT::v2bf16 && Subtarget->hasBF16PackedInsts()) ||15098 (VT == MVT::v2f16 && Subtarget->hasVOP3PInsts())) &&15099 Op0.hasOneUse()) {15100 if (SDValue Res = performFPMed3ImmCombine(DAG, SDLoc(N), Op0, Op1))15101 return Res;15102 }15103 15104 // Prefer fminnum_ieee over fminimum. For gfx950, minimum/maximum are legal15105 // for some types, but at a higher cost since it's implemented with a 315106 // operand form.15107 const SDNodeFlags Flags = N->getFlags();15108 if ((Opc == ISD::FMINIMUM || Opc == ISD::FMAXIMUM) &&15109 !Subtarget->hasIEEEMinimumMaximumInsts() && Flags.hasNoNaNs()) {15110 unsigned NewOpc =15111 Opc == ISD::FMINIMUM ? ISD::FMINNUM_IEEE : ISD::FMAXNUM_IEEE;15112 return DAG.getNode(NewOpc, SDLoc(N), VT, Op0, Op1, Flags);15113 }15114 15115 return SDValue();15116}15117 15118static bool isClampZeroToOne(SDValue A, SDValue B) {15119 if (ConstantFPSDNode *CA = dyn_cast<ConstantFPSDNode>(A)) {15120 if (ConstantFPSDNode *CB = dyn_cast<ConstantFPSDNode>(B)) {15121 // FIXME: Should this be allowing -0.0?15122 return (CA->isExactlyValue(0.0) && CB->isExactlyValue(1.0)) ||15123 (CA->isExactlyValue(1.0) && CB->isExactlyValue(0.0));15124 }15125 }15126 15127 return false;15128}15129 15130// FIXME: Should only worry about snans for version with chain.15131SDValue SITargetLowering::performFMed3Combine(SDNode *N,15132 DAGCombinerInfo &DCI) const {15133 EVT VT = N->getValueType(0);15134 // v_med3_f32 and v_max_f32 behave identically wrt denorms, exceptions and15135 // NaNs. With a NaN input, the order of the operands may change the result.15136 15137 SelectionDAG &DAG = DCI.DAG;15138 SDLoc SL(N);15139 15140 SDValue Src0 = N->getOperand(0);15141 SDValue Src1 = N->getOperand(1);15142 SDValue Src2 = N->getOperand(2);15143 15144 if (isClampZeroToOne(Src0, Src1)) {15145 // const_a, const_b, x -> clamp is safe in all cases including signaling15146 // nans.15147 // FIXME: Should this be allowing -0.0?15148 return DAG.getNode(AMDGPUISD::CLAMP, SL, VT, Src2);15149 }15150 15151 const MachineFunction &MF = DAG.getMachineFunction();15152 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();15153 15154 // FIXME: dx10_clamp behavior assumed in instcombine. Should we really bother15155 // handling no dx10-clamp?15156 if (Info->getMode().DX10Clamp) {15157 // If NaNs is clamped to 0, we are free to reorder the inputs.15158 15159 if (isa<ConstantFPSDNode>(Src0) && !isa<ConstantFPSDNode>(Src1))15160 std::swap(Src0, Src1);15161 15162 if (isa<ConstantFPSDNode>(Src1) && !isa<ConstantFPSDNode>(Src2))15163 std::swap(Src1, Src2);15164 15165 if (isa<ConstantFPSDNode>(Src0) && !isa<ConstantFPSDNode>(Src1))15166 std::swap(Src0, Src1);15167 15168 if (isClampZeroToOne(Src1, Src2))15169 return DAG.getNode(AMDGPUISD::CLAMP, SL, VT, Src0);15170 }15171 15172 return SDValue();15173}15174 15175SDValue SITargetLowering::performCvtPkRTZCombine(SDNode *N,15176 DAGCombinerInfo &DCI) const {15177 SDValue Src0 = N->getOperand(0);15178 SDValue Src1 = N->getOperand(1);15179 if (Src0.isUndef() && Src1.isUndef())15180 return DCI.DAG.getUNDEF(N->getValueType(0));15181 return SDValue();15182}15183 15184// Check if EXTRACT_VECTOR_ELT/INSERT_VECTOR_ELT (<n x e>, var-idx) should be15185// expanded into a set of cmp/select instructions.15186bool SITargetLowering::shouldExpandVectorDynExt(unsigned EltSize,15187 unsigned NumElem,15188 bool IsDivergentIdx,15189 const GCNSubtarget *Subtarget) {15190 if (UseDivergentRegisterIndexing)15191 return false;15192 15193 unsigned VecSize = EltSize * NumElem;15194 15195 // Sub-dword vectors of size 2 dword or less have better implementation.15196 if (VecSize <= 64 && EltSize < 32)15197 return false;15198 15199 // Always expand the rest of sub-dword instructions, otherwise it will be15200 // lowered via memory.15201 if (EltSize < 32)15202 return true;15203 15204 // Always do this if var-idx is divergent, otherwise it will become a loop.15205 if (IsDivergentIdx)15206 return true;15207 15208 // Large vectors would yield too many compares and v_cndmask_b32 instructions.15209 unsigned NumInsts = NumElem /* Number of compares */ +15210 ((EltSize + 31) / 32) * NumElem /* Number of cndmasks */;15211 15212 // On some architectures (GFX9) movrel is not available and it's better15213 // to expand.15214 if (Subtarget->useVGPRIndexMode())15215 return NumInsts <= 16;15216 15217 // If movrel is available, use it instead of expanding for vector of 815218 // elements.15219 if (Subtarget->hasMovrel())15220 return NumInsts <= 15;15221 15222 return true;15223}15224 15225bool SITargetLowering::shouldExpandVectorDynExt(SDNode *N) const {15226 SDValue Idx = N->getOperand(N->getNumOperands() - 1);15227 if (isa<ConstantSDNode>(Idx))15228 return false;15229 15230 SDValue Vec = N->getOperand(0);15231 EVT VecVT = Vec.getValueType();15232 EVT EltVT = VecVT.getVectorElementType();15233 unsigned EltSize = EltVT.getSizeInBits();15234 unsigned NumElem = VecVT.getVectorNumElements();15235 15236 return SITargetLowering::shouldExpandVectorDynExt(15237 EltSize, NumElem, Idx->isDivergent(), getSubtarget());15238}15239 15240SDValue15241SITargetLowering::performExtractVectorEltCombine(SDNode *N,15242 DAGCombinerInfo &DCI) const {15243 SDValue Vec = N->getOperand(0);15244 SelectionDAG &DAG = DCI.DAG;15245 15246 EVT VecVT = Vec.getValueType();15247 EVT VecEltVT = VecVT.getVectorElementType();15248 EVT ResVT = N->getValueType(0);15249 15250 unsigned VecSize = VecVT.getSizeInBits();15251 unsigned VecEltSize = VecEltVT.getSizeInBits();15252 15253 if ((Vec.getOpcode() == ISD::FNEG || Vec.getOpcode() == ISD::FABS) &&15254 allUsesHaveSourceMods(N)) {15255 SDLoc SL(N);15256 SDValue Idx = N->getOperand(1);15257 SDValue Elt =15258 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, ResVT, Vec.getOperand(0), Idx);15259 return DAG.getNode(Vec.getOpcode(), SL, ResVT, Elt);15260 }15261 15262 // (extract_vector_element (and {y0, y1}, (build_vector 0x1f, 0x1f)), index)15263 // -> (and (extract_vector_element {y0, y1}, index), 0x1f)15264 // There are optimisations to transform 64-bit shifts into 32-bit shifts15265 // depending on the shift operand. See e.g. performSraCombine().15266 // This combine ensures that the optimisation is compatible with v2i3215267 // legalised AND.15268 if (VecVT == MVT::v2i32 && Vec->getOpcode() == ISD::AND &&15269 Vec->getOperand(1)->getOpcode() == ISD::BUILD_VECTOR) {15270 15271 const ConstantSDNode *C = isConstOrConstSplat(Vec.getOperand(1));15272 if (!C || C->getZExtValue() != 0x1f)15273 return SDValue();15274 15275 SDLoc SL(N);15276 SDValue AndMask = DAG.getConstant(0x1f, SL, MVT::i32);15277 SDValue EVE = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32,15278 Vec->getOperand(0), N->getOperand(1));15279 SDValue A = DAG.getNode(ISD::AND, SL, MVT::i32, EVE, AndMask);15280 DAG.ReplaceAllUsesWith(N, A.getNode());15281 }15282 15283 // ScalarRes = EXTRACT_VECTOR_ELT ((vector-BINOP Vec1, Vec2), Idx)15284 // =>15285 // Vec1Elt = EXTRACT_VECTOR_ELT(Vec1, Idx)15286 // Vec2Elt = EXTRACT_VECTOR_ELT(Vec2, Idx)15287 // ScalarRes = scalar-BINOP Vec1Elt, Vec2Elt15288 if (Vec.hasOneUse() && DCI.isBeforeLegalize() && VecEltVT == ResVT) {15289 SDLoc SL(N);15290 SDValue Idx = N->getOperand(1);15291 unsigned Opc = Vec.getOpcode();15292 15293 switch (Opc) {15294 default:15295 break;15296 // TODO: Support other binary operations.15297 case ISD::FADD:15298 case ISD::FSUB:15299 case ISD::FMUL:15300 case ISD::ADD:15301 case ISD::UMIN:15302 case ISD::UMAX:15303 case ISD::SMIN:15304 case ISD::SMAX:15305 case ISD::FMAXNUM:15306 case ISD::FMINNUM:15307 case ISD::FMAXNUM_IEEE:15308 case ISD::FMINNUM_IEEE:15309 case ISD::FMAXIMUM:15310 case ISD::FMINIMUM: {15311 SDValue Elt0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, ResVT,15312 Vec.getOperand(0), Idx);15313 SDValue Elt1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, ResVT,15314 Vec.getOperand(1), Idx);15315 15316 DCI.AddToWorklist(Elt0.getNode());15317 DCI.AddToWorklist(Elt1.getNode());15318 return DAG.getNode(Opc, SL, ResVT, Elt0, Elt1, Vec->getFlags());15319 }15320 }15321 }15322 15323 // EXTRACT_VECTOR_ELT (<n x e>, var-idx) => n x select (e, const-idx)15324 if (shouldExpandVectorDynExt(N)) {15325 SDLoc SL(N);15326 SDValue Idx = N->getOperand(1);15327 SDValue V;15328 for (unsigned I = 0, E = VecVT.getVectorNumElements(); I < E; ++I) {15329 SDValue IC = DAG.getVectorIdxConstant(I, SL);15330 SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, ResVT, Vec, IC);15331 if (I == 0)15332 V = Elt;15333 else15334 V = DAG.getSelectCC(SL, Idx, IC, Elt, V, ISD::SETEQ);15335 }15336 return V;15337 }15338 15339 if (!DCI.isBeforeLegalize())15340 return SDValue();15341 15342 // Try to turn sub-dword accesses of vectors into accesses of the same 32-bit15343 // elements. This exposes more load reduction opportunities by replacing15344 // multiple small extract_vector_elements with a single 32-bit extract.15345 auto *Idx = dyn_cast<ConstantSDNode>(N->getOperand(1));15346 if (isa<MemSDNode>(Vec) && VecEltSize <= 16 && VecEltVT.isByteSized() &&15347 VecSize > 32 && VecSize % 32 == 0 && Idx) {15348 EVT NewVT = getEquivalentMemType(*DAG.getContext(), VecVT);15349 15350 unsigned BitIndex = Idx->getZExtValue() * VecEltSize;15351 unsigned EltIdx = BitIndex / 32;15352 unsigned LeftoverBitIdx = BitIndex % 32;15353 SDLoc SL(N);15354 15355 SDValue Cast = DAG.getNode(ISD::BITCAST, SL, NewVT, Vec);15356 DCI.AddToWorklist(Cast.getNode());15357 15358 SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, MVT::i32, Cast,15359 DAG.getConstant(EltIdx, SL, MVT::i32));15360 DCI.AddToWorklist(Elt.getNode());15361 SDValue Srl = DAG.getNode(ISD::SRL, SL, MVT::i32, Elt,15362 DAG.getConstant(LeftoverBitIdx, SL, MVT::i32));15363 DCI.AddToWorklist(Srl.getNode());15364 15365 EVT VecEltAsIntVT = VecEltVT.changeTypeToInteger();15366 SDValue Trunc = DAG.getNode(ISD::TRUNCATE, SL, VecEltAsIntVT, Srl);15367 DCI.AddToWorklist(Trunc.getNode());15368 15369 if (VecEltVT == ResVT) {15370 return DAG.getNode(ISD::BITCAST, SL, VecEltVT, Trunc);15371 }15372 15373 assert(ResVT.isScalarInteger());15374 return DAG.getAnyExtOrTrunc(Trunc, SL, ResVT);15375 }15376 15377 return SDValue();15378}15379 15380SDValue15381SITargetLowering::performInsertVectorEltCombine(SDNode *N,15382 DAGCombinerInfo &DCI) const {15383 SDValue Vec = N->getOperand(0);15384 SDValue Idx = N->getOperand(2);15385 EVT VecVT = Vec.getValueType();15386 EVT EltVT = VecVT.getVectorElementType();15387 15388 // INSERT_VECTOR_ELT (<n x e>, var-idx)15389 // => BUILD_VECTOR n x select (e, const-idx)15390 if (!shouldExpandVectorDynExt(N))15391 return SDValue();15392 15393 SelectionDAG &DAG = DCI.DAG;15394 SDLoc SL(N);15395 SDValue Ins = N->getOperand(1);15396 EVT IdxVT = Idx.getValueType();15397 15398 SmallVector<SDValue, 16> Ops;15399 for (unsigned I = 0, E = VecVT.getVectorNumElements(); I < E; ++I) {15400 SDValue IC = DAG.getConstant(I, SL, IdxVT);15401 SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, EltVT, Vec, IC);15402 SDValue V = DAG.getSelectCC(SL, Idx, IC, Ins, Elt, ISD::SETEQ);15403 Ops.push_back(V);15404 }15405 15406 return DAG.getBuildVector(VecVT, SL, Ops);15407}15408 15409/// Return the source of an fp_extend from f16 to f32, or a converted FP15410/// constant.15411static SDValue strictFPExtFromF16(SelectionDAG &DAG, SDValue Src) {15412 if (Src.getOpcode() == ISD::FP_EXTEND &&15413 Src.getOperand(0).getValueType() == MVT::f16) {15414 return Src.getOperand(0);15415 }15416 15417 if (auto *CFP = dyn_cast<ConstantFPSDNode>(Src)) {15418 APFloat Val = CFP->getValueAPF();15419 bool LosesInfo = true;15420 Val.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven, &LosesInfo);15421 if (!LosesInfo)15422 return DAG.getConstantFP(Val, SDLoc(Src), MVT::f16);15423 }15424 15425 return SDValue();15426}15427 15428SDValue SITargetLowering::performFPRoundCombine(SDNode *N,15429 DAGCombinerInfo &DCI) const {15430 assert(Subtarget->has16BitInsts() && !Subtarget->hasMed3_16() &&15431 "combine only useful on gfx8");15432 15433 SDValue TruncSrc = N->getOperand(0);15434 EVT VT = N->getValueType(0);15435 if (VT != MVT::f16)15436 return SDValue();15437 15438 if (TruncSrc.getOpcode() != AMDGPUISD::FMED3 ||15439 TruncSrc.getValueType() != MVT::f32 || !TruncSrc.hasOneUse())15440 return SDValue();15441 15442 SelectionDAG &DAG = DCI.DAG;15443 SDLoc SL(N);15444 15445 // Optimize f16 fmed3 pattern performed on f32. On gfx8 there is no f16 fmed3,15446 // and expanding it with min/max saves 1 instruction vs. casting to f32 and15447 // casting back.15448 15449 // fptrunc (f32 (fmed3 (fpext f16:a, fpext f16:b, fpext f16:c))) =>15450 // fmin(fmax(a, b), fmax(fmin(a, b), c))15451 SDValue A = strictFPExtFromF16(DAG, TruncSrc.getOperand(0));15452 if (!A)15453 return SDValue();15454 15455 SDValue B = strictFPExtFromF16(DAG, TruncSrc.getOperand(1));15456 if (!B)15457 return SDValue();15458 15459 SDValue C = strictFPExtFromF16(DAG, TruncSrc.getOperand(2));15460 if (!C)15461 return SDValue();15462 15463 // This changes signaling nan behavior. If an input is a signaling nan, it15464 // would have been quieted by the fpext originally. We don't care because15465 // these are unconstrained ops. If we needed to insert quieting canonicalizes15466 // we would be worse off than just doing the promotion.15467 SDValue A1 = DAG.getNode(ISD::FMINNUM_IEEE, SL, VT, A, B);15468 SDValue B1 = DAG.getNode(ISD::FMAXNUM_IEEE, SL, VT, A, B);15469 SDValue C1 = DAG.getNode(ISD::FMAXNUM_IEEE, SL, VT, A1, C);15470 return DAG.getNode(ISD::FMINNUM_IEEE, SL, VT, B1, C1);15471}15472 15473unsigned SITargetLowering::getFusedOpcode(const SelectionDAG &DAG,15474 const SDNode *N0,15475 const SDNode *N1) const {15476 EVT VT = N0->getValueType(0);15477 15478 // Only do this if we are not trying to support denormals. v_mad_f32 does not15479 // support denormals ever.15480 if (((VT == MVT::f32 &&15481 denormalModeIsFlushAllF32(DAG.getMachineFunction())) ||15482 (VT == MVT::f16 && Subtarget->hasMadF16() &&15483 denormalModeIsFlushAllF64F16(DAG.getMachineFunction()))) &&15484 isOperationLegal(ISD::FMAD, VT))15485 return ISD::FMAD;15486 15487 const TargetOptions &Options = DAG.getTarget().Options;15488 if ((Options.AllowFPOpFusion == FPOpFusion::Fast ||15489 (N0->getFlags().hasAllowContract() &&15490 N1->getFlags().hasAllowContract())) &&15491 isFMAFasterThanFMulAndFAdd(DAG.getMachineFunction(), VT)) {15492 return ISD::FMA;15493 }15494 15495 return 0;15496}15497 15498// For a reassociatable opcode perform:15499// op x, (op y, z) -> op (op x, z), y, if x and z are uniform15500SDValue SITargetLowering::reassociateScalarOps(SDNode *N,15501 SelectionDAG &DAG) const {15502 EVT VT = N->getValueType(0);15503 if (VT != MVT::i32 && VT != MVT::i64)15504 return SDValue();15505 15506 if (DAG.isBaseWithConstantOffset(SDValue(N, 0)))15507 return SDValue();15508 15509 unsigned Opc = N->getOpcode();15510 SDValue Op0 = N->getOperand(0);15511 SDValue Op1 = N->getOperand(1);15512 15513 if (!(Op0->isDivergent() ^ Op1->isDivergent()))15514 return SDValue();15515 15516 if (Op0->isDivergent())15517 std::swap(Op0, Op1);15518 15519 if (Op1.getOpcode() != Opc || !Op1.hasOneUse())15520 return SDValue();15521 15522 SDValue Op2 = Op1.getOperand(1);15523 Op1 = Op1.getOperand(0);15524 if (!(Op1->isDivergent() ^ Op2->isDivergent()))15525 return SDValue();15526 15527 if (Op1->isDivergent())15528 std::swap(Op1, Op2);15529 15530 SDLoc SL(N);15531 SDValue Add1 = DAG.getNode(Opc, SL, VT, Op0, Op1);15532 return DAG.getNode(Opc, SL, VT, Add1, Op2);15533}15534 15535static SDValue getMad64_32(SelectionDAG &DAG, const SDLoc &SL, EVT VT,15536 SDValue N0, SDValue N1, SDValue N2, bool Signed) {15537 unsigned MadOpc = Signed ? AMDGPUISD::MAD_I64_I32 : AMDGPUISD::MAD_U64_U32;15538 SDVTList VTs = DAG.getVTList(MVT::i64, MVT::i1);15539 SDValue Mad = DAG.getNode(MadOpc, SL, VTs, N0, N1, N2);15540 return DAG.getNode(ISD::TRUNCATE, SL, VT, Mad);15541}15542 15543// Fold15544// y = lshr i64 x, 3215545// res = add (mul i64 y, Const), x where "Const" is a 64-bit constant15546// with Const.hi == -115547// To15548// res = mad_u64_u32 y.lo ,Const.lo, x.lo15549static SDValue tryFoldMADwithSRL(SelectionDAG &DAG, const SDLoc &SL,15550 SDValue MulLHS, SDValue MulRHS,15551 SDValue AddRHS) {15552 if (MulRHS.getOpcode() == ISD::SRL)15553 std::swap(MulLHS, MulRHS);15554 15555 if (MulLHS.getValueType() != MVT::i64 || MulLHS.getOpcode() != ISD::SRL)15556 return SDValue();15557 15558 ConstantSDNode *ShiftVal = dyn_cast<ConstantSDNode>(MulLHS.getOperand(1));15559 if (!ShiftVal || ShiftVal->getAsZExtVal() != 32 ||15560 MulLHS.getOperand(0) != AddRHS)15561 return SDValue();15562 15563 ConstantSDNode *Const = dyn_cast<ConstantSDNode>(MulRHS.getNode());15564 if (!Const || Hi_32(Const->getZExtValue()) != uint32_t(-1))15565 return SDValue();15566 15567 SDValue ConstMul =15568 DAG.getConstant(Lo_32(Const->getZExtValue()), SL, MVT::i32);15569 return getMad64_32(DAG, SL, MVT::i64,15570 DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, MulLHS), ConstMul,15571 DAG.getZeroExtendInReg(AddRHS, SL, MVT::i32), false);15572}15573 15574// Fold (add (mul x, y), z) --> (mad_[iu]64_[iu]32 x, y, z) plus high15575// multiplies, if any.15576//15577// Full 64-bit multiplies that feed into an addition are lowered here instead15578// of using the generic expansion. The generic expansion ends up with15579// a tree of ADD nodes that prevents us from using the "add" part of the15580// MAD instruction. The expansion produced here results in a chain of ADDs15581// instead of a tree.15582SDValue SITargetLowering::tryFoldToMad64_32(SDNode *N,15583 DAGCombinerInfo &DCI) const {15584 assert(N->isAnyAdd());15585 15586 SelectionDAG &DAG = DCI.DAG;15587 EVT VT = N->getValueType(0);15588 SDLoc SL(N);15589 SDValue LHS = N->getOperand(0);15590 SDValue RHS = N->getOperand(1);15591 15592 if (VT.isVector())15593 return SDValue();15594 15595 // S_MUL_HI_[IU]32 was added in gfx9, which allows us to keep the overall15596 // result in scalar registers for uniform values.15597 if (!N->isDivergent() && Subtarget->hasSMulHi())15598 return SDValue();15599 15600 unsigned NumBits = VT.getScalarSizeInBits();15601 if (NumBits <= 32 || NumBits > 64)15602 return SDValue();15603 15604 if (LHS.getOpcode() != ISD::MUL) {15605 assert(RHS.getOpcode() == ISD::MUL);15606 std::swap(LHS, RHS);15607 }15608 15609 // Avoid the fold if it would unduly increase the number of multiplies due to15610 // multiple uses, except on hardware with full-rate multiply-add (which is15611 // part of full-rate 64-bit ops).15612 if (!Subtarget->hasFullRate64Ops()) {15613 unsigned NumUsers = 0;15614 for (SDNode *User : LHS->users()) {15615 // There is a use that does not feed into addition, so the multiply can't15616 // be removed. We prefer MUL + ADD + ADDC over MAD + MUL.15617 if (!User->isAnyAdd())15618 return SDValue();15619 15620 // We prefer 2xMAD over MUL + 2xADD + 2xADDC (code density), and prefer15621 // MUL + 3xADD + 3xADDC over 3xMAD.15622 ++NumUsers;15623 if (NumUsers >= 3)15624 return SDValue();15625 }15626 }15627 15628 SDValue MulLHS = LHS.getOperand(0);15629 SDValue MulRHS = LHS.getOperand(1);15630 SDValue AddRHS = RHS;15631 15632 if (SDValue FoldedMAD = tryFoldMADwithSRL(DAG, SL, MulLHS, MulRHS, AddRHS))15633 return FoldedMAD;15634 15635 // Always check whether operands are small unsigned values, since that15636 // knowledge is useful in more cases. Check for small signed values only if15637 // doing so can unlock a shorter code sequence.15638 bool MulLHSUnsigned32 = numBitsUnsigned(MulLHS, DAG) <= 32;15639 bool MulRHSUnsigned32 = numBitsUnsigned(MulRHS, DAG) <= 32;15640 15641 bool MulSignedLo = false;15642 if (!MulLHSUnsigned32 || !MulRHSUnsigned32) {15643 MulSignedLo =15644 numBitsSigned(MulLHS, DAG) <= 32 && numBitsSigned(MulRHS, DAG) <= 32;15645 }15646 15647 // The operands and final result all have the same number of bits. If15648 // operands need to be extended, they can be extended with garbage. The15649 // resulting garbage in the high bits of the mad_[iu]64_[iu]32 result is15650 // truncated away in the end.15651 if (VT != MVT::i64) {15652 MulLHS = DAG.getNode(ISD::ANY_EXTEND, SL, MVT::i64, MulLHS);15653 MulRHS = DAG.getNode(ISD::ANY_EXTEND, SL, MVT::i64, MulRHS);15654 AddRHS = DAG.getNode(ISD::ANY_EXTEND, SL, MVT::i64, AddRHS);15655 }15656 15657 // The basic code generated is conceptually straightforward. Pseudo code:15658 //15659 // accum = mad_64_32 lhs.lo, rhs.lo, accum15660 // accum.hi = add (mul lhs.hi, rhs.lo), accum.hi15661 // accum.hi = add (mul lhs.lo, rhs.hi), accum.hi15662 //15663 // The second and third lines are optional, depending on whether the factors15664 // are {sign,zero}-extended or not.15665 //15666 // The actual DAG is noisier than the pseudo code, but only due to15667 // instructions that disassemble values into low and high parts, and15668 // assemble the final result.15669 SDValue One = DAG.getConstant(1, SL, MVT::i32);15670 15671 auto MulLHSLo = DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, MulLHS);15672 auto MulRHSLo = DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, MulRHS);15673 SDValue Accum =15674 getMad64_32(DAG, SL, MVT::i64, MulLHSLo, MulRHSLo, AddRHS, MulSignedLo);15675 15676 if (!MulSignedLo && (!MulLHSUnsigned32 || !MulRHSUnsigned32)) {15677 auto [AccumLo, AccumHi] = DAG.SplitScalar(Accum, SL, MVT::i32, MVT::i32);15678 15679 if (!MulLHSUnsigned32) {15680 auto MulLHSHi =15681 DAG.getNode(ISD::EXTRACT_ELEMENT, SL, MVT::i32, MulLHS, One);15682 SDValue MulHi = DAG.getNode(ISD::MUL, SL, MVT::i32, MulLHSHi, MulRHSLo);15683 AccumHi = DAG.getNode(ISD::ADD, SL, MVT::i32, MulHi, AccumHi);15684 }15685 15686 if (!MulRHSUnsigned32) {15687 auto MulRHSHi =15688 DAG.getNode(ISD::EXTRACT_ELEMENT, SL, MVT::i32, MulRHS, One);15689 SDValue MulHi = DAG.getNode(ISD::MUL, SL, MVT::i32, MulLHSLo, MulRHSHi);15690 AccumHi = DAG.getNode(ISD::ADD, SL, MVT::i32, MulHi, AccumHi);15691 }15692 15693 Accum = DAG.getBuildVector(MVT::v2i32, SL, {AccumLo, AccumHi});15694 Accum = DAG.getBitcast(MVT::i64, Accum);15695 }15696 15697 if (VT != MVT::i64)15698 Accum = DAG.getNode(ISD::TRUNCATE, SL, VT, Accum);15699 return Accum;15700}15701 15702SDValue15703SITargetLowering::foldAddSub64WithZeroLowBitsTo32(SDNode *N,15704 DAGCombinerInfo &DCI) const {15705 SDValue RHS = N->getOperand(1);15706 auto *CRHS = dyn_cast<ConstantSDNode>(RHS);15707 if (!CRHS)15708 return SDValue();15709 15710 // TODO: Worth using computeKnownBits? Maybe expensive since it's so15711 // common.15712 uint64_t Val = CRHS->getZExtValue();15713 if (countr_zero(Val) >= 32) {15714 SelectionDAG &DAG = DCI.DAG;15715 SDLoc SL(N);15716 SDValue LHS = N->getOperand(0);15717 15718 // Avoid carry machinery if we know the low half of the add does not15719 // contribute to the final result.15720 //15721 // add i64:x, K if computeTrailingZeros(K) >= 3215722 // => build_pair (add x.hi, K.hi), x.lo15723 15724 // Breaking the 64-bit add here with this strange constant is unlikely15725 // to interfere with addressing mode patterns.15726 15727 SDValue Hi = getHiHalf64(LHS, DAG);15728 SDValue ConstHi32 = DAG.getConstant(Hi_32(Val), SL, MVT::i32);15729 unsigned Opcode = N->getOpcode();15730 if (Opcode == ISD::PTRADD)15731 Opcode = ISD::ADD;15732 SDValue AddHi =15733 DAG.getNode(Opcode, SL, MVT::i32, Hi, ConstHi32, N->getFlags());15734 15735 SDValue Lo = DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, LHS);15736 return DAG.getNode(ISD::BUILD_PAIR, SL, MVT::i64, Lo, AddHi);15737 }15738 15739 return SDValue();15740}15741 15742// Collect the ultimate src of each of the mul node's operands, and confirm15743// each operand is 8 bytes.15744static std::optional<ByteProvider<SDValue>>15745handleMulOperand(const SDValue &MulOperand) {15746 auto Byte0 = calculateByteProvider(MulOperand, 0, 0);15747 if (!Byte0 || Byte0->isConstantZero()) {15748 return std::nullopt;15749 }15750 auto Byte1 = calculateByteProvider(MulOperand, 1, 0);15751 if (Byte1 && !Byte1->isConstantZero()) {15752 return std::nullopt;15753 }15754 return Byte0;15755}15756 15757static unsigned addPermMasks(unsigned First, unsigned Second) {15758 unsigned FirstCs = First & 0x0c0c0c0c;15759 unsigned SecondCs = Second & 0x0c0c0c0c;15760 unsigned FirstNoCs = First & ~0x0c0c0c0c;15761 unsigned SecondNoCs = Second & ~0x0c0c0c0c;15762 15763 assert((FirstCs & 0xFF) | (SecondCs & 0xFF));15764 assert((FirstCs & 0xFF00) | (SecondCs & 0xFF00));15765 assert((FirstCs & 0xFF0000) | (SecondCs & 0xFF0000));15766 assert((FirstCs & 0xFF000000) | (SecondCs & 0xFF000000));15767 15768 return (FirstNoCs | SecondNoCs) | (FirstCs & SecondCs);15769}15770 15771struct DotSrc {15772 SDValue SrcOp;15773 int64_t PermMask;15774 int64_t DWordOffset;15775};15776 15777static void placeSources(ByteProvider<SDValue> &Src0,15778 ByteProvider<SDValue> &Src1,15779 SmallVectorImpl<DotSrc> &Src0s,15780 SmallVectorImpl<DotSrc> &Src1s, int Step) {15781 15782 assert(Src0.Src.has_value() && Src1.Src.has_value());15783 // Src0s and Src1s are empty, just place arbitrarily.15784 if (Step == 0) {15785 Src0s.push_back({*Src0.Src, ((Src0.SrcOffset % 4) << 24) + 0x0c0c0c,15786 Src0.SrcOffset / 4});15787 Src1s.push_back({*Src1.Src, ((Src1.SrcOffset % 4) << 24) + 0x0c0c0c,15788 Src1.SrcOffset / 4});15789 return;15790 }15791 15792 for (int BPI = 0; BPI < 2; BPI++) {15793 std::pair<ByteProvider<SDValue>, ByteProvider<SDValue>> BPP = {Src0, Src1};15794 if (BPI == 1) {15795 BPP = {Src1, Src0};15796 }15797 unsigned ZeroMask = 0x0c0c0c0c;15798 unsigned FMask = 0xFF << (8 * (3 - Step));15799 15800 unsigned FirstMask =15801 (BPP.first.SrcOffset % 4) << (8 * (3 - Step)) | (ZeroMask & ~FMask);15802 unsigned SecondMask =15803 (BPP.second.SrcOffset % 4) << (8 * (3 - Step)) | (ZeroMask & ~FMask);15804 // Attempt to find Src vector which contains our SDValue, if so, add our15805 // perm mask to the existing one. If we are unable to find a match for the15806 // first SDValue, attempt to find match for the second.15807 int FirstGroup = -1;15808 for (int I = 0; I < 2; I++) {15809 SmallVectorImpl<DotSrc> &Srcs = I == 0 ? Src0s : Src1s;15810 auto MatchesFirst = [&BPP](DotSrc &IterElt) {15811 return IterElt.SrcOp == *BPP.first.Src &&15812 (IterElt.DWordOffset == (BPP.first.SrcOffset / 4));15813 };15814 15815 auto *Match = llvm::find_if(Srcs, MatchesFirst);15816 if (Match != Srcs.end()) {15817 Match->PermMask = addPermMasks(FirstMask, Match->PermMask);15818 FirstGroup = I;15819 break;15820 }15821 }15822 if (FirstGroup != -1) {15823 SmallVectorImpl<DotSrc> &Srcs = FirstGroup == 1 ? Src0s : Src1s;15824 auto MatchesSecond = [&BPP](DotSrc &IterElt) {15825 return IterElt.SrcOp == *BPP.second.Src &&15826 (IterElt.DWordOffset == (BPP.second.SrcOffset / 4));15827 };15828 auto *Match = llvm::find_if(Srcs, MatchesSecond);15829 if (Match != Srcs.end()) {15830 Match->PermMask = addPermMasks(SecondMask, Match->PermMask);15831 } else15832 Srcs.push_back({*BPP.second.Src, SecondMask, BPP.second.SrcOffset / 4});15833 return;15834 }15835 }15836 15837 // If we have made it here, then we could not find a match in Src0s or Src1s15838 // for either Src0 or Src1, so just place them arbitrarily.15839 15840 unsigned ZeroMask = 0x0c0c0c0c;15841 unsigned FMask = 0xFF << (8 * (3 - Step));15842 15843 Src0s.push_back(15844 {*Src0.Src,15845 ((Src0.SrcOffset % 4) << (8 * (3 - Step)) | (ZeroMask & ~FMask)),15846 Src0.SrcOffset / 4});15847 Src1s.push_back(15848 {*Src1.Src,15849 ((Src1.SrcOffset % 4) << (8 * (3 - Step)) | (ZeroMask & ~FMask)),15850 Src1.SrcOffset / 4});15851}15852 15853static SDValue resolveSources(SelectionDAG &DAG, SDLoc SL,15854 SmallVectorImpl<DotSrc> &Srcs, bool IsSigned,15855 bool IsAny) {15856 15857 // If we just have one source, just permute it accordingly.15858 if (Srcs.size() == 1) {15859 auto *Elt = Srcs.begin();15860 auto EltOp = getDWordFromOffset(DAG, SL, Elt->SrcOp, Elt->DWordOffset);15861 15862 // v_perm will produce the original value15863 if (Elt->PermMask == 0x3020100)15864 return EltOp;15865 15866 return DAG.getNode(AMDGPUISD::PERM, SL, MVT::i32, EltOp, EltOp,15867 DAG.getConstant(Elt->PermMask, SL, MVT::i32));15868 }15869 15870 auto *FirstElt = Srcs.begin();15871 auto *SecondElt = std::next(FirstElt);15872 15873 SmallVector<SDValue, 2> Perms;15874 15875 // If we have multiple sources in the chain, combine them via perms (using15876 // calculated perm mask) and Ors.15877 while (true) {15878 auto FirstMask = FirstElt->PermMask;15879 auto SecondMask = SecondElt->PermMask;15880 15881 unsigned FirstCs = FirstMask & 0x0c0c0c0c;15882 unsigned FirstPlusFour = FirstMask | 0x04040404;15883 // 0x0c + 0x04 = 0x10, so anding with 0x0F will produced 0x00 for any15884 // original 0x0C.15885 FirstMask = (FirstPlusFour & 0x0F0F0F0F) | FirstCs;15886 15887 auto PermMask = addPermMasks(FirstMask, SecondMask);15888 auto FirstVal =15889 getDWordFromOffset(DAG, SL, FirstElt->SrcOp, FirstElt->DWordOffset);15890 auto SecondVal =15891 getDWordFromOffset(DAG, SL, SecondElt->SrcOp, SecondElt->DWordOffset);15892 15893 Perms.push_back(DAG.getNode(AMDGPUISD::PERM, SL, MVT::i32, FirstVal,15894 SecondVal,15895 DAG.getConstant(PermMask, SL, MVT::i32)));15896 15897 FirstElt = std::next(SecondElt);15898 if (FirstElt == Srcs.end())15899 break;15900 15901 SecondElt = std::next(FirstElt);15902 // If we only have a FirstElt, then just combine that into the cumulative15903 // source node.15904 if (SecondElt == Srcs.end()) {15905 auto EltOp =15906 getDWordFromOffset(DAG, SL, FirstElt->SrcOp, FirstElt->DWordOffset);15907 15908 Perms.push_back(15909 DAG.getNode(AMDGPUISD::PERM, SL, MVT::i32, EltOp, EltOp,15910 DAG.getConstant(FirstElt->PermMask, SL, MVT::i32)));15911 break;15912 }15913 }15914 15915 assert(Perms.size() == 1 || Perms.size() == 2);15916 return Perms.size() == 215917 ? DAG.getNode(ISD::OR, SL, MVT::i32, Perms[0], Perms[1])15918 : Perms[0];15919}15920 15921static void fixMasks(SmallVectorImpl<DotSrc> &Srcs, unsigned ChainLength) {15922 for (auto &[EntryVal, EntryMask, EntryOffset] : Srcs) {15923 EntryMask = EntryMask >> ((4 - ChainLength) * 8);15924 auto ZeroMask = ChainLength == 2 ? 0x0c0c0000 : 0x0c000000;15925 EntryMask += ZeroMask;15926 }15927}15928 15929static bool isMul(const SDValue Op) {15930 auto Opcode = Op.getOpcode();15931 15932 return (Opcode == ISD::MUL || Opcode == AMDGPUISD::MUL_U24 ||15933 Opcode == AMDGPUISD::MUL_I24);15934}15935 15936static std::optional<bool>15937checkDot4MulSignedness(const SDValue &N, ByteProvider<SDValue> &Src0,15938 ByteProvider<SDValue> &Src1, const SDValue &S0Op,15939 const SDValue &S1Op, const SelectionDAG &DAG) {15940 // If we both ops are i8s (pre legalize-dag), then the signedness semantics15941 // of the dot4 is irrelevant.15942 if (S0Op.getValueSizeInBits() == 8 && S1Op.getValueSizeInBits() == 8)15943 return false;15944 15945 auto Known0 = DAG.computeKnownBits(S0Op, 0);15946 bool S0IsUnsigned = Known0.countMinLeadingZeros() > 0;15947 bool S0IsSigned = Known0.countMinLeadingOnes() > 0;15948 auto Known1 = DAG.computeKnownBits(S1Op, 0);15949 bool S1IsUnsigned = Known1.countMinLeadingZeros() > 0;15950 bool S1IsSigned = Known1.countMinLeadingOnes() > 0;15951 15952 assert(!(S0IsUnsigned && S0IsSigned));15953 assert(!(S1IsUnsigned && S1IsSigned));15954 15955 // There are 9 possible permutations of15956 // {S0IsUnsigned, S0IsSigned, S1IsUnsigned, S1IsSigned}15957 15958 // In two permutations, the sign bits are known to be the same for both Ops,15959 // so simply return Signed / Unsigned corresponding to the MSB15960 15961 if ((S0IsUnsigned && S1IsUnsigned) || (S0IsSigned && S1IsSigned))15962 return S0IsSigned;15963 15964 // In another two permutations, the sign bits are known to be opposite. In15965 // this case return std::nullopt to indicate a bad match.15966 15967 if ((S0IsUnsigned && S1IsSigned) || (S0IsSigned && S1IsUnsigned))15968 return std::nullopt;15969 15970 // In the remaining five permutations, we don't know the value of the sign15971 // bit for at least one Op. Since we have a valid ByteProvider, we know that15972 // the upper bits must be extension bits. Thus, the only ways for the sign15973 // bit to be unknown is if it was sign extended from unknown value, or if it15974 // was any extended. In either case, it is correct to use the signed15975 // version of the signedness semantics of dot415976 15977 // In two of such permutations, we known the sign bit is set for15978 // one op, and the other is unknown. It is okay to used signed version of15979 // dot4.15980 if ((S0IsSigned && !(S1IsSigned || S1IsUnsigned)) ||15981 ((S1IsSigned && !(S0IsSigned || S0IsUnsigned))))15982 return true;15983 15984 // In one such permutation, we don't know either of the sign bits. It is okay15985 // to used the signed version of dot4.15986 if ((!(S1IsSigned || S1IsUnsigned) && !(S0IsSigned || S0IsUnsigned)))15987 return true;15988 15989 // In two of such permutations, we known the sign bit is unset for15990 // one op, and the other is unknown. Return std::nullopt to indicate a15991 // bad match.15992 if ((S0IsUnsigned && !(S1IsSigned || S1IsUnsigned)) ||15993 ((S1IsUnsigned && !(S0IsSigned || S0IsUnsigned))))15994 return std::nullopt;15995 15996 llvm_unreachable("Fully covered condition");15997}15998 15999SDValue SITargetLowering::performAddCombine(SDNode *N,16000 DAGCombinerInfo &DCI) const {16001 SelectionDAG &DAG = DCI.DAG;16002 EVT VT = N->getValueType(0);16003 SDLoc SL(N);16004 SDValue LHS = N->getOperand(0);16005 SDValue RHS = N->getOperand(1);16006 16007 if (LHS.getOpcode() == ISD::MUL || RHS.getOpcode() == ISD::MUL) {16008 if (Subtarget->hasMad64_32()) {16009 if (SDValue Folded = tryFoldToMad64_32(N, DCI))16010 return Folded;16011 }16012 }16013 16014 if (SDValue V = reassociateScalarOps(N, DAG)) {16015 return V;16016 }16017 16018 if (VT == MVT::i64) {16019 if (SDValue Folded = foldAddSub64WithZeroLowBitsTo32(N, DCI))16020 return Folded;16021 }16022 16023 if ((isMul(LHS) || isMul(RHS)) && Subtarget->hasDot7Insts() &&16024 (Subtarget->hasDot1Insts() || Subtarget->hasDot8Insts())) {16025 SDValue TempNode(N, 0);16026 std::optional<bool> IsSigned;16027 SmallVector<DotSrc, 4> Src0s;16028 SmallVector<DotSrc, 4> Src1s;16029 SmallVector<SDValue, 4> Src2s;16030 16031 // Match the v_dot4 tree, while collecting src nodes.16032 int ChainLength = 0;16033 for (int I = 0; I < 4; I++) {16034 auto MulIdx = isMul(LHS) ? 0 : isMul(RHS) ? 1 : -1;16035 if (MulIdx == -1)16036 break;16037 auto Src0 = handleMulOperand(TempNode->getOperand(MulIdx)->getOperand(0));16038 if (!Src0)16039 break;16040 auto Src1 = handleMulOperand(TempNode->getOperand(MulIdx)->getOperand(1));16041 if (!Src1)16042 break;16043 16044 auto IterIsSigned = checkDot4MulSignedness(16045 TempNode->getOperand(MulIdx), *Src0, *Src1,16046 TempNode->getOperand(MulIdx)->getOperand(0),16047 TempNode->getOperand(MulIdx)->getOperand(1), DAG);16048 if (!IterIsSigned)16049 break;16050 if (!IsSigned)16051 IsSigned = *IterIsSigned;16052 if (*IterIsSigned != *IsSigned)16053 break;16054 placeSources(*Src0, *Src1, Src0s, Src1s, I);16055 auto AddIdx = 1 - MulIdx;16056 // Allow the special case where add (add (mul24, 0), mul24) became ->16057 // add (mul24, mul24).16058 if (I == 2 && isMul(TempNode->getOperand(AddIdx))) {16059 Src2s.push_back(TempNode->getOperand(AddIdx));16060 auto Src0 =16061 handleMulOperand(TempNode->getOperand(AddIdx)->getOperand(0));16062 if (!Src0)16063 break;16064 auto Src1 =16065 handleMulOperand(TempNode->getOperand(AddIdx)->getOperand(1));16066 if (!Src1)16067 break;16068 auto IterIsSigned = checkDot4MulSignedness(16069 TempNode->getOperand(AddIdx), *Src0, *Src1,16070 TempNode->getOperand(AddIdx)->getOperand(0),16071 TempNode->getOperand(AddIdx)->getOperand(1), DAG);16072 if (!IterIsSigned)16073 break;16074 assert(IsSigned);16075 if (*IterIsSigned != *IsSigned)16076 break;16077 placeSources(*Src0, *Src1, Src0s, Src1s, I + 1);16078 Src2s.push_back(DAG.getConstant(0, SL, MVT::i32));16079 ChainLength = I + 2;16080 break;16081 }16082 16083 TempNode = TempNode->getOperand(AddIdx);16084 Src2s.push_back(TempNode);16085 ChainLength = I + 1;16086 if (TempNode->getNumOperands() < 2)16087 break;16088 LHS = TempNode->getOperand(0);16089 RHS = TempNode->getOperand(1);16090 }16091 16092 if (ChainLength < 2)16093 return SDValue();16094 16095 // Masks were constructed with assumption that we would find a chain of16096 // length 4. If not, then we need to 0 out the MSB bits (via perm mask of16097 // 0x0c) so they do not affect dot calculation.16098 if (ChainLength < 4) {16099 fixMasks(Src0s, ChainLength);16100 fixMasks(Src1s, ChainLength);16101 }16102 16103 SDValue Src0, Src1;16104 16105 // If we are just using a single source for both, and have permuted the16106 // bytes consistently, we can just use the sources without permuting16107 // (commutation).16108 bool UseOriginalSrc = false;16109 if (ChainLength == 4 && Src0s.size() == 1 && Src1s.size() == 1 &&16110 Src0s.begin()->PermMask == Src1s.begin()->PermMask &&16111 Src0s.begin()->SrcOp.getValueSizeInBits() >= 32 &&16112 Src1s.begin()->SrcOp.getValueSizeInBits() >= 32) {16113 SmallVector<unsigned, 4> SrcBytes;16114 auto Src0Mask = Src0s.begin()->PermMask;16115 SrcBytes.push_back(Src0Mask & 0xFF000000);16116 bool UniqueEntries = true;16117 for (auto I = 1; I < 4; I++) {16118 auto NextByte = Src0Mask & (0xFF << ((3 - I) * 8));16119 16120 if (is_contained(SrcBytes, NextByte)) {16121 UniqueEntries = false;16122 break;16123 }16124 SrcBytes.push_back(NextByte);16125 }16126 16127 if (UniqueEntries) {16128 UseOriginalSrc = true;16129 16130 auto *FirstElt = Src0s.begin();16131 auto FirstEltOp =16132 getDWordFromOffset(DAG, SL, FirstElt->SrcOp, FirstElt->DWordOffset);16133 16134 auto *SecondElt = Src1s.begin();16135 auto SecondEltOp = getDWordFromOffset(DAG, SL, SecondElt->SrcOp,16136 SecondElt->DWordOffset);16137 16138 Src0 = DAG.getBitcastedAnyExtOrTrunc(FirstEltOp, SL,16139 MVT::getIntegerVT(32));16140 Src1 = DAG.getBitcastedAnyExtOrTrunc(SecondEltOp, SL,16141 MVT::getIntegerVT(32));16142 }16143 }16144 16145 if (!UseOriginalSrc) {16146 Src0 = resolveSources(DAG, SL, Src0s, false, true);16147 Src1 = resolveSources(DAG, SL, Src1s, false, true);16148 }16149 16150 assert(IsSigned);16151 SDValue Src2 =16152 DAG.getExtOrTrunc(*IsSigned, Src2s[ChainLength - 1], SL, MVT::i32);16153 16154 SDValue IID = DAG.getTargetConstant(*IsSigned ? Intrinsic::amdgcn_sdot416155 : Intrinsic::amdgcn_udot4,16156 SL, MVT::i64);16157 16158 assert(!VT.isVector());16159 auto Dot = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, SL, MVT::i32, IID, Src0,16160 Src1, Src2, DAG.getTargetConstant(0, SL, MVT::i1));16161 16162 return DAG.getExtOrTrunc(*IsSigned, Dot, SL, VT);16163 }16164 16165 if (VT != MVT::i32 || !DCI.isAfterLegalizeDAG())16166 return SDValue();16167 16168 // add x, zext (setcc) => uaddo_carry x, 0, setcc16169 // add x, sext (setcc) => usubo_carry x, 0, setcc16170 unsigned Opc = LHS.getOpcode();16171 if (Opc == ISD::ZERO_EXTEND || Opc == ISD::SIGN_EXTEND ||16172 Opc == ISD::ANY_EXTEND || Opc == ISD::UADDO_CARRY)16173 std::swap(RHS, LHS);16174 16175 Opc = RHS.getOpcode();16176 switch (Opc) {16177 default:16178 break;16179 case ISD::ZERO_EXTEND:16180 case ISD::SIGN_EXTEND:16181 case ISD::ANY_EXTEND: {16182 auto Cond = RHS.getOperand(0);16183 // If this won't be a real VOPC output, we would still need to insert an16184 // extra instruction anyway.16185 if (!isBoolSGPR(Cond))16186 break;16187 SDVTList VTList = DAG.getVTList(MVT::i32, MVT::i1);16188 SDValue Args[] = {LHS, DAG.getConstant(0, SL, MVT::i32), Cond};16189 Opc = (Opc == ISD::SIGN_EXTEND) ? ISD::USUBO_CARRY : ISD::UADDO_CARRY;16190 return DAG.getNode(Opc, SL, VTList, Args);16191 }16192 case ISD::UADDO_CARRY: {16193 // add x, (uaddo_carry y, 0, cc) => uaddo_carry x, y, cc16194 if (!isNullConstant(RHS.getOperand(1)))16195 break;16196 SDValue Args[] = {LHS, RHS.getOperand(0), RHS.getOperand(2)};16197 return DAG.getNode(ISD::UADDO_CARRY, SDLoc(N), RHS->getVTList(), Args);16198 }16199 }16200 return SDValue();16201}16202 16203SDValue SITargetLowering::performPtrAddCombine(SDNode *N,16204 DAGCombinerInfo &DCI) const {16205 SelectionDAG &DAG = DCI.DAG;16206 SDLoc DL(N);16207 EVT VT = N->getValueType(0);16208 SDValue N0 = N->getOperand(0);16209 SDValue N1 = N->getOperand(1);16210 16211 // The following folds transform PTRADDs into regular arithmetic in cases16212 // where the PTRADD wouldn't be folded as an immediate offset into memory16213 // instructions anyway. They are target-specific in that other targets might16214 // prefer to not lose information about the pointer arithmetic.16215 16216 // Fold (ptradd x, shl(0 - v, k)) -> sub(x, shl(v, k)).16217 // Adapted from DAGCombiner::visitADDLikeCommutative.16218 SDValue V, K;16219 if (sd_match(N1, m_Shl(m_Neg(m_Value(V)), m_Value(K)))) {16220 SDNodeFlags ShlFlags = N1->getFlags();16221 // If the original shl is NUW and NSW, the first k+1 bits of 0-v are all 0,16222 // so v is either 0 or the first k+1 bits of v are all 1 -> NSW can be16223 // preserved.16224 SDNodeFlags NewShlFlags =16225 ShlFlags.hasNoUnsignedWrap() && ShlFlags.hasNoSignedWrap()16226 ? SDNodeFlags::NoSignedWrap16227 : SDNodeFlags();16228 SDValue Inner = DAG.getNode(ISD::SHL, DL, VT, V, K, NewShlFlags);16229 DCI.AddToWorklist(Inner.getNode());16230 return DAG.getNode(ISD::SUB, DL, VT, N0, Inner);16231 }16232 16233 // Fold into Mad64 if the right-hand side is a MUL. Analogous to a fold in16234 // performAddCombine.16235 if (N1.getOpcode() == ISD::MUL) {16236 if (Subtarget->hasMad64_32()) {16237 if (SDValue Folded = tryFoldToMad64_32(N, DCI))16238 return Folded;16239 }16240 }16241 16242 // If the 32 low bits of the constant are all zero, there is nothing to fold16243 // into an immediate offset, so it's better to eliminate the unnecessary16244 // addition for the lower 32 bits than to preserve the PTRADD.16245 // Analogous to a fold in performAddCombine.16246 if (VT == MVT::i64) {16247 if (SDValue Folded = foldAddSub64WithZeroLowBitsTo32(N, DCI))16248 return Folded;16249 }16250 16251 if (N1.getOpcode() != ISD::ADD || !N1.hasOneUse())16252 return SDValue();16253 16254 SDValue X = N0;16255 SDValue Y = N1.getOperand(0);16256 SDValue Z = N1.getOperand(1);16257 bool YIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Y);16258 bool ZIsConstant = DAG.isConstantIntBuildVectorOrConstantInt(Z);16259 16260 if (!YIsConstant && !ZIsConstant && !X->isDivergent() &&16261 Y->isDivergent() != Z->isDivergent()) {16262 // Reassociate (ptradd x, (add y, z)) -> (ptradd (ptradd x, y), z) if x and16263 // y are uniform and z isn't.16264 // Reassociate (ptradd x, (add y, z)) -> (ptradd (ptradd x, z), y) if x and16265 // z are uniform and y isn't.16266 // The goal is to push uniform operands up in the computation, so that they16267 // can be handled with scalar operations. We can't use reassociateScalarOps16268 // for this since it requires two identical commutative operations to16269 // reassociate.16270 if (Y->isDivergent())16271 std::swap(Y, Z);16272 // If both additions in the original were NUW, reassociation preserves that.16273 SDNodeFlags ReassocFlags =16274 (N->getFlags() & N1->getFlags()) & SDNodeFlags::NoUnsignedWrap;16275 SDValue UniformInner = DAG.getMemBasePlusOffset(X, Y, DL, ReassocFlags);16276 DCI.AddToWorklist(UniformInner.getNode());16277 return DAG.getMemBasePlusOffset(UniformInner, Z, DL, ReassocFlags);16278 }16279 16280 return SDValue();16281}16282 16283SDValue SITargetLowering::performSubCombine(SDNode *N,16284 DAGCombinerInfo &DCI) const {16285 SelectionDAG &DAG = DCI.DAG;16286 EVT VT = N->getValueType(0);16287 16288 if (VT == MVT::i64) {16289 if (SDValue Folded = foldAddSub64WithZeroLowBitsTo32(N, DCI))16290 return Folded;16291 }16292 16293 if (VT != MVT::i32)16294 return SDValue();16295 16296 SDLoc SL(N);16297 SDValue LHS = N->getOperand(0);16298 SDValue RHS = N->getOperand(1);16299 16300 // sub x, zext (setcc) => usubo_carry x, 0, setcc16301 // sub x, sext (setcc) => uaddo_carry x, 0, setcc16302 unsigned Opc = RHS.getOpcode();16303 switch (Opc) {16304 default:16305 break;16306 case ISD::ZERO_EXTEND:16307 case ISD::SIGN_EXTEND:16308 case ISD::ANY_EXTEND: {16309 auto Cond = RHS.getOperand(0);16310 // If this won't be a real VOPC output, we would still need to insert an16311 // extra instruction anyway.16312 if (!isBoolSGPR(Cond))16313 break;16314 SDVTList VTList = DAG.getVTList(MVT::i32, MVT::i1);16315 SDValue Args[] = {LHS, DAG.getConstant(0, SL, MVT::i32), Cond};16316 Opc = (Opc == ISD::SIGN_EXTEND) ? ISD::UADDO_CARRY : ISD::USUBO_CARRY;16317 return DAG.getNode(Opc, SL, VTList, Args);16318 }16319 }16320 16321 if (LHS.getOpcode() == ISD::USUBO_CARRY) {16322 // sub (usubo_carry x, 0, cc), y => usubo_carry x, y, cc16323 if (!isNullConstant(LHS.getOperand(1)))16324 return SDValue();16325 SDValue Args[] = {LHS.getOperand(0), RHS, LHS.getOperand(2)};16326 return DAG.getNode(ISD::USUBO_CARRY, SDLoc(N), LHS->getVTList(), Args);16327 }16328 return SDValue();16329}16330 16331SDValue16332SITargetLowering::performAddCarrySubCarryCombine(SDNode *N,16333 DAGCombinerInfo &DCI) const {16334 16335 if (N->getValueType(0) != MVT::i32)16336 return SDValue();16337 16338 if (!isNullConstant(N->getOperand(1)))16339 return SDValue();16340 16341 SelectionDAG &DAG = DCI.DAG;16342 SDValue LHS = N->getOperand(0);16343 16344 // uaddo_carry (add x, y), 0, cc => uaddo_carry x, y, cc16345 // usubo_carry (sub x, y), 0, cc => usubo_carry x, y, cc16346 unsigned LHSOpc = LHS.getOpcode();16347 unsigned Opc = N->getOpcode();16348 if ((LHSOpc == ISD::ADD && Opc == ISD::UADDO_CARRY) ||16349 (LHSOpc == ISD::SUB && Opc == ISD::USUBO_CARRY)) {16350 SDValue Args[] = {LHS.getOperand(0), LHS.getOperand(1), N->getOperand(2)};16351 return DAG.getNode(Opc, SDLoc(N), N->getVTList(), Args);16352 }16353 return SDValue();16354}16355 16356SDValue SITargetLowering::performFAddCombine(SDNode *N,16357 DAGCombinerInfo &DCI) const {16358 if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)16359 return SDValue();16360 16361 SelectionDAG &DAG = DCI.DAG;16362 EVT VT = N->getValueType(0);16363 16364 SDLoc SL(N);16365 SDValue LHS = N->getOperand(0);16366 SDValue RHS = N->getOperand(1);16367 16368 // These should really be instruction patterns, but writing patterns with16369 // source modifiers is a pain.16370 16371 // fadd (fadd (a, a), b) -> mad 2.0, a, b16372 if (LHS.getOpcode() == ISD::FADD) {16373 SDValue A = LHS.getOperand(0);16374 if (A == LHS.getOperand(1)) {16375 unsigned FusedOp = getFusedOpcode(DAG, N, LHS.getNode());16376 if (FusedOp != 0) {16377 const SDValue Two = DAG.getConstantFP(2.0, SL, VT);16378 return DAG.getNode(FusedOp, SL, VT, A, Two, RHS);16379 }16380 }16381 }16382 16383 // fadd (b, fadd (a, a)) -> mad 2.0, a, b16384 if (RHS.getOpcode() == ISD::FADD) {16385 SDValue A = RHS.getOperand(0);16386 if (A == RHS.getOperand(1)) {16387 unsigned FusedOp = getFusedOpcode(DAG, N, RHS.getNode());16388 if (FusedOp != 0) {16389 const SDValue Two = DAG.getConstantFP(2.0, SL, VT);16390 return DAG.getNode(FusedOp, SL, VT, A, Two, LHS);16391 }16392 }16393 }16394 16395 return SDValue();16396}16397 16398SDValue SITargetLowering::performFSubCombine(SDNode *N,16399 DAGCombinerInfo &DCI) const {16400 if (DCI.getDAGCombineLevel() < AfterLegalizeDAG)16401 return SDValue();16402 16403 SelectionDAG &DAG = DCI.DAG;16404 SDLoc SL(N);16405 EVT VT = N->getValueType(0);16406 assert(!VT.isVector());16407 16408 // Try to get the fneg to fold into the source modifier. This undoes generic16409 // DAG combines and folds them into the mad.16410 //16411 // Only do this if we are not trying to support denormals. v_mad_f32 does16412 // not support denormals ever.16413 SDValue LHS = N->getOperand(0);16414 SDValue RHS = N->getOperand(1);16415 if (LHS.getOpcode() == ISD::FADD) {16416 // (fsub (fadd a, a), c) -> mad 2.0, a, (fneg c)16417 SDValue A = LHS.getOperand(0);16418 if (A == LHS.getOperand(1)) {16419 unsigned FusedOp = getFusedOpcode(DAG, N, LHS.getNode());16420 if (FusedOp != 0) {16421 const SDValue Two = DAG.getConstantFP(2.0, SL, VT);16422 SDValue NegRHS = DAG.getNode(ISD::FNEG, SL, VT, RHS);16423 16424 return DAG.getNode(FusedOp, SL, VT, A, Two, NegRHS);16425 }16426 }16427 }16428 16429 if (RHS.getOpcode() == ISD::FADD) {16430 // (fsub c, (fadd a, a)) -> mad -2.0, a, c16431 16432 SDValue A = RHS.getOperand(0);16433 if (A == RHS.getOperand(1)) {16434 unsigned FusedOp = getFusedOpcode(DAG, N, RHS.getNode());16435 if (FusedOp != 0) {16436 const SDValue NegTwo = DAG.getConstantFP(-2.0, SL, VT);16437 return DAG.getNode(FusedOp, SL, VT, A, NegTwo, LHS);16438 }16439 }16440 }16441 16442 return SDValue();16443}16444 16445SDValue SITargetLowering::performFDivCombine(SDNode *N,16446 DAGCombinerInfo &DCI) const {16447 SelectionDAG &DAG = DCI.DAG;16448 SDLoc SL(N);16449 EVT VT = N->getValueType(0);16450 if ((VT != MVT::f16 && VT != MVT::bf16) || !Subtarget->has16BitInsts())16451 return SDValue();16452 16453 SDValue LHS = N->getOperand(0);16454 SDValue RHS = N->getOperand(1);16455 16456 SDNodeFlags Flags = N->getFlags();16457 SDNodeFlags RHSFlags = RHS->getFlags();16458 if (!Flags.hasAllowContract() || !RHSFlags.hasAllowContract() ||16459 !RHS->hasOneUse())16460 return SDValue();16461 16462 if (const ConstantFPSDNode *CLHS = dyn_cast<ConstantFPSDNode>(LHS)) {16463 bool IsNegative = false;16464 if (CLHS->isExactlyValue(1.0) ||16465 (IsNegative = CLHS->isExactlyValue(-1.0))) {16466 // fdiv contract 1.0, (sqrt contract x) -> rsq for f1616467 // fdiv contract -1.0, (sqrt contract x) -> fneg(rsq) for f1616468 if (RHS.getOpcode() == ISD::FSQRT) {16469 // TODO: Or in RHS flags, somehow missing from SDNodeFlags16470 SDValue Rsq =16471 DAG.getNode(AMDGPUISD::RSQ, SL, VT, RHS.getOperand(0), Flags);16472 return IsNegative ? DAG.getNode(ISD::FNEG, SL, VT, Rsq, Flags) : Rsq;16473 }16474 }16475 }16476 16477 return SDValue();16478}16479 16480SDValue SITargetLowering::performFMulCombine(SDNode *N,16481 DAGCombinerInfo &DCI) const {16482 SelectionDAG &DAG = DCI.DAG;16483 EVT VT = N->getValueType(0);16484 EVT ScalarVT = VT.getScalarType();16485 EVT IntVT = VT.changeElementType(MVT::i32);16486 16487 if (!N->isDivergent() && getSubtarget()->hasSALUFloatInsts() &&16488 (ScalarVT == MVT::f32 || ScalarVT == MVT::f16)) {16489 // Prefer to use s_mul_f16/f32 instead of v_ldexp_f16/f32.16490 return SDValue();16491 }16492 16493 SDValue LHS = N->getOperand(0);16494 SDValue RHS = N->getOperand(1);16495 16496 // It is cheaper to realize i32 inline constants as compared against16497 // materializing f16 or f64 (or even non-inline f32) values,16498 // possible via ldexp usage, as shown below :16499 //16500 // Given : A = 2^a & B = 2^b ; where a and b are integers.16501 // fmul x, (select y, A, B) -> ldexp( x, (select i32 y, a, b) )16502 // fmul x, (select y, -A, -B) -> ldexp( (fneg x), (select i32 y, a, b) )16503 if ((ScalarVT == MVT::f64 || ScalarVT == MVT::f32 || ScalarVT == MVT::f16) &&16504 (RHS.hasOneUse() && RHS.getOpcode() == ISD::SELECT)) {16505 const ConstantFPSDNode *TrueNode = isConstOrConstSplatFP(RHS.getOperand(1));16506 if (!TrueNode)16507 return SDValue();16508 const ConstantFPSDNode *FalseNode =16509 isConstOrConstSplatFP(RHS.getOperand(2));16510 if (!FalseNode)16511 return SDValue();16512 16513 if (TrueNode->isNegative() != FalseNode->isNegative())16514 return SDValue();16515 16516 // For f32, only non-inline constants should be transformed.16517 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();16518 if (ScalarVT == MVT::f32 &&16519 TII->isInlineConstant(TrueNode->getValueAPF()) &&16520 TII->isInlineConstant(FalseNode->getValueAPF()))16521 return SDValue();16522 16523 int TrueNodeExpVal = TrueNode->getValueAPF().getExactLog2Abs();16524 if (TrueNodeExpVal == INT_MIN)16525 return SDValue();16526 int FalseNodeExpVal = FalseNode->getValueAPF().getExactLog2Abs();16527 if (FalseNodeExpVal == INT_MIN)16528 return SDValue();16529 16530 SDLoc SL(N);16531 SDValue SelectNode =16532 DAG.getNode(ISD::SELECT, SL, IntVT, RHS.getOperand(0),16533 DAG.getSignedConstant(TrueNodeExpVal, SL, IntVT),16534 DAG.getSignedConstant(FalseNodeExpVal, SL, IntVT));16535 16536 LHS = TrueNode->isNegative()16537 ? DAG.getNode(ISD::FNEG, SL, VT, LHS, LHS->getFlags())16538 : LHS;16539 16540 return DAG.getNode(ISD::FLDEXP, SL, VT, LHS, SelectNode, N->getFlags());16541 }16542 16543 return SDValue();16544}16545 16546SDValue SITargetLowering::performFMACombine(SDNode *N,16547 DAGCombinerInfo &DCI) const {16548 SelectionDAG &DAG = DCI.DAG;16549 EVT VT = N->getValueType(0);16550 SDLoc SL(N);16551 16552 if (!Subtarget->hasDot10Insts() || VT != MVT::f32)16553 return SDValue();16554 16555 // FMA((F32)S0.x, (F32)S1. x, FMA((F32)S0.y, (F32)S1.y, (F32)z)) ->16556 // FDOT2((V2F16)S0, (V2F16)S1, (F32)z))16557 SDValue Op1 = N->getOperand(0);16558 SDValue Op2 = N->getOperand(1);16559 SDValue FMA = N->getOperand(2);16560 16561 if (FMA.getOpcode() != ISD::FMA || Op1.getOpcode() != ISD::FP_EXTEND ||16562 Op2.getOpcode() != ISD::FP_EXTEND)16563 return SDValue();16564 16565 // fdot2_f32_f16 always flushes fp32 denormal operand and output to zero,16566 // regardless of the denorm mode setting. Therefore,16567 // fp-contract is sufficient to allow generating fdot2.16568 const TargetOptions &Options = DAG.getTarget().Options;16569 if (Options.AllowFPOpFusion == FPOpFusion::Fast ||16570 (N->getFlags().hasAllowContract() &&16571 FMA->getFlags().hasAllowContract())) {16572 Op1 = Op1.getOperand(0);16573 Op2 = Op2.getOperand(0);16574 if (Op1.getOpcode() != ISD::EXTRACT_VECTOR_ELT ||16575 Op2.getOpcode() != ISD::EXTRACT_VECTOR_ELT)16576 return SDValue();16577 16578 SDValue Vec1 = Op1.getOperand(0);16579 SDValue Idx1 = Op1.getOperand(1);16580 SDValue Vec2 = Op2.getOperand(0);16581 16582 SDValue FMAOp1 = FMA.getOperand(0);16583 SDValue FMAOp2 = FMA.getOperand(1);16584 SDValue FMAAcc = FMA.getOperand(2);16585 16586 if (FMAOp1.getOpcode() != ISD::FP_EXTEND ||16587 FMAOp2.getOpcode() != ISD::FP_EXTEND)16588 return SDValue();16589 16590 FMAOp1 = FMAOp1.getOperand(0);16591 FMAOp2 = FMAOp2.getOperand(0);16592 if (FMAOp1.getOpcode() != ISD::EXTRACT_VECTOR_ELT ||16593 FMAOp2.getOpcode() != ISD::EXTRACT_VECTOR_ELT)16594 return SDValue();16595 16596 SDValue Vec3 = FMAOp1.getOperand(0);16597 SDValue Vec4 = FMAOp2.getOperand(0);16598 SDValue Idx2 = FMAOp1.getOperand(1);16599 16600 if (Idx1 != Op2.getOperand(1) || Idx2 != FMAOp2.getOperand(1) ||16601 // Idx1 and Idx2 cannot be the same.16602 Idx1 == Idx2)16603 return SDValue();16604 16605 if (Vec1 == Vec2 || Vec3 == Vec4)16606 return SDValue();16607 16608 if (Vec1.getValueType() != MVT::v2f16 || Vec2.getValueType() != MVT::v2f16)16609 return SDValue();16610 16611 if ((Vec1 == Vec3 && Vec2 == Vec4) || (Vec1 == Vec4 && Vec2 == Vec3)) {16612 return DAG.getNode(AMDGPUISD::FDOT2, SL, MVT::f32, Vec1, Vec2, FMAAcc,16613 DAG.getTargetConstant(0, SL, MVT::i1));16614 }16615 }16616 return SDValue();16617}16618 16619SDValue SITargetLowering::performSetCCCombine(SDNode *N,16620 DAGCombinerInfo &DCI) const {16621 SelectionDAG &DAG = DCI.DAG;16622 SDLoc SL(N);16623 16624 SDValue LHS = N->getOperand(0);16625 SDValue RHS = N->getOperand(1);16626 EVT VT = LHS.getValueType();16627 ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();16628 16629 auto *CRHS = dyn_cast<ConstantSDNode>(RHS);16630 if (!CRHS) {16631 CRHS = dyn_cast<ConstantSDNode>(LHS);16632 if (CRHS) {16633 std::swap(LHS, RHS);16634 CC = getSetCCSwappedOperands(CC);16635 }16636 }16637 16638 if (CRHS) {16639 if (VT == MVT::i32 && LHS.getOpcode() == ISD::SIGN_EXTEND &&16640 isBoolSGPR(LHS.getOperand(0))) {16641 // setcc (sext from i1 cc), -1, ne|sgt|ult) => not cc => xor cc, -116642 // setcc (sext from i1 cc), -1, eq|sle|uge) => cc16643 // setcc (sext from i1 cc), 0, eq|sge|ule) => not cc => xor cc, -116644 // setcc (sext from i1 cc), 0, ne|ugt|slt) => cc16645 if ((CRHS->isAllOnes() &&16646 (CC == ISD::SETNE || CC == ISD::SETGT || CC == ISD::SETULT)) ||16647 (CRHS->isZero() &&16648 (CC == ISD::SETEQ || CC == ISD::SETGE || CC == ISD::SETULE)))16649 return DAG.getNode(ISD::XOR, SL, MVT::i1, LHS.getOperand(0),16650 DAG.getAllOnesConstant(SL, MVT::i1));16651 if ((CRHS->isAllOnes() &&16652 (CC == ISD::SETEQ || CC == ISD::SETLE || CC == ISD::SETUGE)) ||16653 (CRHS->isZero() &&16654 (CC == ISD::SETNE || CC == ISD::SETUGT || CC == ISD::SETLT)))16655 return LHS.getOperand(0);16656 }16657 16658 const APInt &CRHSVal = CRHS->getAPIntValue();16659 if ((CC == ISD::SETEQ || CC == ISD::SETNE) &&16660 LHS.getOpcode() == ISD::SELECT &&16661 isa<ConstantSDNode>(LHS.getOperand(1)) &&16662 isa<ConstantSDNode>(LHS.getOperand(2)) &&16663 LHS.getConstantOperandVal(1) != LHS.getConstantOperandVal(2) &&16664 isBoolSGPR(LHS.getOperand(0))) {16665 // Given CT != FT:16666 // setcc (select cc, CT, CF), CF, eq => xor cc, -116667 // setcc (select cc, CT, CF), CF, ne => cc16668 // setcc (select cc, CT, CF), CT, ne => xor cc, -116669 // setcc (select cc, CT, CF), CT, eq => cc16670 const APInt &CT = LHS.getConstantOperandAPInt(1);16671 const APInt &CF = LHS.getConstantOperandAPInt(2);16672 16673 if ((CF == CRHSVal && CC == ISD::SETEQ) ||16674 (CT == CRHSVal && CC == ISD::SETNE))16675 return DAG.getNode(ISD::XOR, SL, MVT::i1, LHS.getOperand(0),16676 DAG.getAllOnesConstant(SL, MVT::i1));16677 if ((CF == CRHSVal && CC == ISD::SETNE) ||16678 (CT == CRHSVal && CC == ISD::SETEQ))16679 return LHS.getOperand(0);16680 }16681 }16682 16683 // Eliminate setcc by using carryout from add/sub instruction16684 16685 // LHS = ADD i64 RHS, Z LHSlo = UADDO i32 RHSlo, Zlo16686 // setcc LHS ult RHS -> LHSHi = UADDO_CARRY i32 RHShi, Zhi16687 // similarly for subtraction16688 16689 // LHS = ADD i64 Y, 1 LHSlo = UADDO i32 Ylo, 116690 // setcc LHS eq 0 -> LHSHi = UADDO_CARRY i32 Yhi, 016691 16692 if (VT == MVT::i64 && ((CC == ISD::SETULT &&16693 sd_match(LHS, m_Add(m_Specific(RHS), m_Value()))) ||16694 (CC == ISD::SETUGT &&16695 sd_match(LHS, m_Sub(m_Specific(RHS), m_Value()))) ||16696 (CC == ISD::SETEQ && CRHS && CRHS->isZero() &&16697 sd_match(LHS, m_Add(m_Value(), m_One()))))) {16698 bool IsAdd = LHS.getOpcode() == ISD::ADD;16699 16700 SDValue Op0 = LHS.getOperand(0);16701 SDValue Op1 = LHS.getOperand(1);16702 16703 SDValue Op0Lo = DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, Op0);16704 SDValue Op1Lo = DAG.getNode(ISD::TRUNCATE, SL, MVT::i32, Op1);16705 16706 SDValue Op0Hi = getHiHalf64(Op0, DAG);16707 SDValue Op1Hi = getHiHalf64(Op1, DAG);16708 16709 SDValue NodeLo =16710 DAG.getNode(IsAdd ? ISD::UADDO : ISD::USUBO, SL,16711 DAG.getVTList(MVT::i32, MVT::i1), {Op0Lo, Op1Lo});16712 16713 SDValue CarryInHi = NodeLo.getValue(1);16714 SDValue NodeHi = DAG.getNode(IsAdd ? ISD::UADDO_CARRY : ISD::USUBO_CARRY,16715 SL, DAG.getVTList(MVT::i32, MVT::i1),16716 {Op0Hi, Op1Hi, CarryInHi});16717 16718 SDValue ResultLo = NodeLo.getValue(0);16719 SDValue ResultHi = NodeHi.getValue(0);16720 16721 SDValue JoinedResult =16722 DAG.getBuildVector(MVT::v2i32, SL, {ResultLo, ResultHi});16723 16724 SDValue Result = DAG.getNode(ISD::BITCAST, SL, VT, JoinedResult);16725 SDValue Overflow = NodeHi.getValue(1);16726 DCI.CombineTo(LHS.getNode(), Result);16727 return Overflow;16728 }16729 16730 if (VT != MVT::f32 && VT != MVT::f64 &&16731 (!Subtarget->has16BitInsts() || VT != MVT::f16))16732 return SDValue();16733 16734 // Match isinf/isfinite pattern16735 // (fcmp oeq (fabs x), inf) -> (fp_class x, (p_infinity | n_infinity))16736 // (fcmp one (fabs x), inf) -> (fp_class x,16737 // (p_normal | n_normal | p_subnormal | n_subnormal | p_zero | n_zero)16738 if ((CC == ISD::SETOEQ || CC == ISD::SETONE) &&16739 LHS.getOpcode() == ISD::FABS) {16740 const ConstantFPSDNode *CRHS = dyn_cast<ConstantFPSDNode>(RHS);16741 if (!CRHS)16742 return SDValue();16743 16744 const APFloat &APF = CRHS->getValueAPF();16745 if (APF.isInfinity() && !APF.isNegative()) {16746 const unsigned IsInfMask =16747 SIInstrFlags::P_INFINITY | SIInstrFlags::N_INFINITY;16748 const unsigned IsFiniteMask =16749 SIInstrFlags::N_ZERO | SIInstrFlags::P_ZERO | SIInstrFlags::N_NORMAL |16750 SIInstrFlags::P_NORMAL | SIInstrFlags::N_SUBNORMAL |16751 SIInstrFlags::P_SUBNORMAL;16752 unsigned Mask = CC == ISD::SETOEQ ? IsInfMask : IsFiniteMask;16753 return DAG.getNode(AMDGPUISD::FP_CLASS, SL, MVT::i1, LHS.getOperand(0),16754 DAG.getConstant(Mask, SL, MVT::i32));16755 }16756 }16757 16758 return SDValue();16759}16760 16761SDValue16762SITargetLowering::performCvtF32UByteNCombine(SDNode *N,16763 DAGCombinerInfo &DCI) const {16764 SelectionDAG &DAG = DCI.DAG;16765 SDLoc SL(N);16766 unsigned Offset = N->getOpcode() - AMDGPUISD::CVT_F32_UBYTE0;16767 16768 SDValue Src = N->getOperand(0);16769 SDValue Shift = N->getOperand(0);16770 16771 // TODO: Extend type shouldn't matter (assuming legal types).16772 if (Shift.getOpcode() == ISD::ZERO_EXTEND)16773 Shift = Shift.getOperand(0);16774 16775 if (Shift.getOpcode() == ISD::SRL || Shift.getOpcode() == ISD::SHL) {16776 // cvt_f32_ubyte1 (shl x, 8) -> cvt_f32_ubyte0 x16777 // cvt_f32_ubyte3 (shl x, 16) -> cvt_f32_ubyte1 x16778 // cvt_f32_ubyte0 (srl x, 16) -> cvt_f32_ubyte2 x16779 // cvt_f32_ubyte1 (srl x, 16) -> cvt_f32_ubyte3 x16780 // cvt_f32_ubyte0 (srl x, 8) -> cvt_f32_ubyte1 x16781 if (auto *C = dyn_cast<ConstantSDNode>(Shift.getOperand(1))) {16782 SDValue Shifted = DAG.getZExtOrTrunc(16783 Shift.getOperand(0), SDLoc(Shift.getOperand(0)), MVT::i32);16784 16785 unsigned ShiftOffset = 8 * Offset;16786 if (Shift.getOpcode() == ISD::SHL)16787 ShiftOffset -= C->getZExtValue();16788 else16789 ShiftOffset += C->getZExtValue();16790 16791 if (ShiftOffset < 32 && (ShiftOffset % 8) == 0) {16792 return DAG.getNode(AMDGPUISD::CVT_F32_UBYTE0 + ShiftOffset / 8, SL,16793 MVT::f32, Shifted);16794 }16795 }16796 }16797 16798 const TargetLowering &TLI = DAG.getTargetLoweringInfo();16799 APInt DemandedBits = APInt::getBitsSet(32, 8 * Offset, 8 * Offset + 8);16800 if (TLI.SimplifyDemandedBits(Src, DemandedBits, DCI)) {16801 // We simplified Src. If this node is not dead, visit it again so it is16802 // folded properly.16803 if (N->getOpcode() != ISD::DELETED_NODE)16804 DCI.AddToWorklist(N);16805 return SDValue(N, 0);16806 }16807 16808 // Handle (or x, (srl y, 8)) pattern when known bits are zero.16809 if (SDValue DemandedSrc =16810 TLI.SimplifyMultipleUseDemandedBits(Src, DemandedBits, DAG))16811 return DAG.getNode(N->getOpcode(), SL, MVT::f32, DemandedSrc);16812 16813 return SDValue();16814}16815 16816SDValue SITargetLowering::performClampCombine(SDNode *N,16817 DAGCombinerInfo &DCI) const {16818 ConstantFPSDNode *CSrc = dyn_cast<ConstantFPSDNode>(N->getOperand(0));16819 if (!CSrc)16820 return SDValue();16821 16822 const MachineFunction &MF = DCI.DAG.getMachineFunction();16823 const APFloat &F = CSrc->getValueAPF();16824 APFloat Zero = APFloat::getZero(F.getSemantics());16825 if (F < Zero ||16826 (F.isNaN() && MF.getInfo<SIMachineFunctionInfo>()->getMode().DX10Clamp)) {16827 return DCI.DAG.getConstantFP(Zero, SDLoc(N), N->getValueType(0));16828 }16829 16830 APFloat One(F.getSemantics(), "1.0");16831 if (F > One)16832 return DCI.DAG.getConstantFP(One, SDLoc(N), N->getValueType(0));16833 16834 return SDValue(CSrc, 0);16835}16836 16837SDValue SITargetLowering::performSelectCombine(SDNode *N,16838 DAGCombinerInfo &DCI) const {16839 16840 // Try to fold CMP + SELECT patterns with shared constants (both FP and16841 // integer).16842 // Detect when CMP and SELECT use the same constant and fold them to avoid16843 // loading the constant twice. Specifically handles patterns like:16844 // %cmp = icmp eq i32 %val, 424216845 // %sel = select i1 %cmp, i32 4242, i32 %other16846 // It can be optimized to reuse %val instead of 4242 in select.16847 SDValue Cond = N->getOperand(0);16848 SDValue TrueVal = N->getOperand(1);16849 SDValue FalseVal = N->getOperand(2);16850 16851 // Check if condition is a comparison.16852 if (Cond.getOpcode() != ISD::SETCC)16853 return SDValue();16854 16855 SDValue LHS = Cond.getOperand(0);16856 SDValue RHS = Cond.getOperand(1);16857 ISD::CondCode CC = cast<CondCodeSDNode>(Cond.getOperand(2))->get();16858 16859 bool isFloatingPoint = LHS.getValueType().isFloatingPoint();16860 bool isInteger = LHS.getValueType().isInteger();16861 16862 // Handle simple floating-point and integer types only.16863 if (!isFloatingPoint && !isInteger)16864 return SDValue();16865 16866 bool isEquality = CC == (isFloatingPoint ? ISD::SETOEQ : ISD::SETEQ);16867 bool isNonEquality = CC == (isFloatingPoint ? ISD::SETONE : ISD::SETNE);16868 if (!isEquality && !isNonEquality)16869 return SDValue();16870 16871 SDValue ArgVal, ConstVal;16872 if ((isFloatingPoint && isa<ConstantFPSDNode>(RHS)) ||16873 (isInteger && isa<ConstantSDNode>(RHS))) {16874 ConstVal = RHS;16875 ArgVal = LHS;16876 } else if ((isFloatingPoint && isa<ConstantFPSDNode>(LHS)) ||16877 (isInteger && isa<ConstantSDNode>(LHS))) {16878 ConstVal = LHS;16879 ArgVal = RHS;16880 } else {16881 return SDValue();16882 }16883 16884 // Skip optimization for inlinable immediates.16885 if (isFloatingPoint) {16886 const APFloat &Val = cast<ConstantFPSDNode>(ConstVal)->getValueAPF();16887 if (!Val.isNormal() || Subtarget->getInstrInfo()->isInlineConstant(Val))16888 return SDValue();16889 } else {16890 if (AMDGPU::isInlinableIntLiteral(16891 cast<ConstantSDNode>(ConstVal)->getSExtValue()))16892 return SDValue();16893 }16894 16895 // For equality and non-equality comparisons, patterns:16896 // select (setcc x, const), const, y -> select (setcc x, const), x, y16897 // select (setccinv x, const), y, const -> select (setccinv x, const), y, x16898 if (!(isEquality && TrueVal == ConstVal) &&16899 !(isNonEquality && FalseVal == ConstVal))16900 return SDValue();16901 16902 SDValue SelectLHS = (isEquality && TrueVal == ConstVal) ? ArgVal : TrueVal;16903 SDValue SelectRHS =16904 (isNonEquality && FalseVal == ConstVal) ? ArgVal : FalseVal;16905 return DCI.DAG.getNode(ISD::SELECT, SDLoc(N), N->getValueType(0), Cond,16906 SelectLHS, SelectRHS);16907}16908 16909SDValue SITargetLowering::PerformDAGCombine(SDNode *N,16910 DAGCombinerInfo &DCI) const {16911 switch (N->getOpcode()) {16912 case ISD::ADD:16913 case ISD::SUB:16914 case ISD::SHL:16915 case ISD::SRL:16916 case ISD::SRA:16917 case ISD::AND:16918 case ISD::OR:16919 case ISD::XOR:16920 case ISD::MUL:16921 case ISD::SETCC:16922 case ISD::SELECT:16923 case ISD::SMIN:16924 case ISD::SMAX:16925 case ISD::UMIN:16926 case ISD::UMAX:16927 if (auto Res = promoteUniformOpToI32(SDValue(N, 0), DCI))16928 return Res;16929 break;16930 default:16931 break;16932 }16933 16934 if (getTargetMachine().getOptLevel() == CodeGenOptLevel::None)16935 return SDValue();16936 16937 switch (N->getOpcode()) {16938 case ISD::ADD:16939 return performAddCombine(N, DCI);16940 case ISD::PTRADD:16941 return performPtrAddCombine(N, DCI);16942 case ISD::SUB:16943 return performSubCombine(N, DCI);16944 case ISD::UADDO_CARRY:16945 case ISD::USUBO_CARRY:16946 return performAddCarrySubCarryCombine(N, DCI);16947 case ISD::FADD:16948 return performFAddCombine(N, DCI);16949 case ISD::FSUB:16950 return performFSubCombine(N, DCI);16951 case ISD::FDIV:16952 return performFDivCombine(N, DCI);16953 case ISD::FMUL:16954 return performFMulCombine(N, DCI);16955 case ISD::SETCC:16956 return performSetCCCombine(N, DCI);16957 case ISD::SELECT:16958 if (auto Res = performSelectCombine(N, DCI))16959 return Res;16960 break;16961 case ISD::FMAXNUM:16962 case ISD::FMINNUM:16963 case ISD::FMAXNUM_IEEE:16964 case ISD::FMINNUM_IEEE:16965 case ISD::FMAXIMUM:16966 case ISD::FMINIMUM:16967 case ISD::FMAXIMUMNUM:16968 case ISD::FMINIMUMNUM:16969 case ISD::SMAX:16970 case ISD::SMIN:16971 case ISD::UMAX:16972 case ISD::UMIN:16973 case AMDGPUISD::FMIN_LEGACY:16974 case AMDGPUISD::FMAX_LEGACY:16975 return performMinMaxCombine(N, DCI);16976 case ISD::FMA:16977 return performFMACombine(N, DCI);16978 case ISD::AND:16979 return performAndCombine(N, DCI);16980 case ISD::OR:16981 return performOrCombine(N, DCI);16982 case ISD::FSHR: {16983 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();16984 if (N->getValueType(0) == MVT::i32 && N->isDivergent() &&16985 TII->pseudoToMCOpcode(AMDGPU::V_PERM_B32_e64) != -1) {16986 return matchPERM(N, DCI);16987 }16988 break;16989 }16990 case ISD::XOR:16991 return performXorCombine(N, DCI);16992 case ISD::ZERO_EXTEND:16993 return performZeroExtendCombine(N, DCI);16994 case ISD::SIGN_EXTEND_INREG:16995 return performSignExtendInRegCombine(N, DCI);16996 case AMDGPUISD::FP_CLASS:16997 return performClassCombine(N, DCI);16998 case ISD::FCANONICALIZE:16999 return performFCanonicalizeCombine(N, DCI);17000 case AMDGPUISD::RCP:17001 return performRcpCombine(N, DCI);17002 case ISD::FLDEXP:17003 case AMDGPUISD::FRACT:17004 case AMDGPUISD::RSQ:17005 case AMDGPUISD::RCP_LEGACY:17006 case AMDGPUISD::RCP_IFLAG:17007 case AMDGPUISD::RSQ_CLAMP: {17008 // FIXME: This is probably wrong. If src is an sNaN, it won't be quieted17009 SDValue Src = N->getOperand(0);17010 if (Src.isUndef())17011 return Src;17012 break;17013 }17014 case ISD::SINT_TO_FP:17015 case ISD::UINT_TO_FP:17016 return performUCharToFloatCombine(N, DCI);17017 case ISD::FCOPYSIGN:17018 return performFCopySignCombine(N, DCI);17019 case AMDGPUISD::CVT_F32_UBYTE0:17020 case AMDGPUISD::CVT_F32_UBYTE1:17021 case AMDGPUISD::CVT_F32_UBYTE2:17022 case AMDGPUISD::CVT_F32_UBYTE3:17023 return performCvtF32UByteNCombine(N, DCI);17024 case AMDGPUISD::FMED3:17025 return performFMed3Combine(N, DCI);17026 case AMDGPUISD::CVT_PKRTZ_F16_F32:17027 return performCvtPkRTZCombine(N, DCI);17028 case AMDGPUISD::CLAMP:17029 return performClampCombine(N, DCI);17030 case ISD::SCALAR_TO_VECTOR: {17031 SelectionDAG &DAG = DCI.DAG;17032 EVT VT = N->getValueType(0);17033 17034 // v2i16 (scalar_to_vector i16:x) -> v2i16 (bitcast (any_extend i16:x))17035 if (VT == MVT::v2i16 || VT == MVT::v2f16 || VT == MVT::v2bf16) {17036 SDLoc SL(N);17037 SDValue Src = N->getOperand(0);17038 EVT EltVT = Src.getValueType();17039 if (EltVT != MVT::i16)17040 Src = DAG.getNode(ISD::BITCAST, SL, MVT::i16, Src);17041 17042 SDValue Ext = DAG.getNode(ISD::ANY_EXTEND, SL, MVT::i32, Src);17043 return DAG.getNode(ISD::BITCAST, SL, VT, Ext);17044 }17045 17046 break;17047 }17048 case ISD::EXTRACT_VECTOR_ELT:17049 return performExtractVectorEltCombine(N, DCI);17050 case ISD::INSERT_VECTOR_ELT:17051 return performInsertVectorEltCombine(N, DCI);17052 case ISD::FP_ROUND:17053 return performFPRoundCombine(N, DCI);17054 case ISD::LOAD: {17055 if (SDValue Widened = widenLoad(cast<LoadSDNode>(N), DCI))17056 return Widened;17057 [[fallthrough]];17058 }17059 default: {17060 if (!DCI.isBeforeLegalize()) {17061 if (MemSDNode *MemNode = dyn_cast<MemSDNode>(N))17062 return performMemSDNodeCombine(MemNode, DCI);17063 }17064 17065 break;17066 }17067 }17068 17069 return AMDGPUTargetLowering::PerformDAGCombine(N, DCI);17070}17071 17072/// Helper function for adjustWritemask17073static unsigned SubIdx2Lane(unsigned Idx) {17074 switch (Idx) {17075 default:17076 return ~0u;17077 case AMDGPU::sub0:17078 return 0;17079 case AMDGPU::sub1:17080 return 1;17081 case AMDGPU::sub2:17082 return 2;17083 case AMDGPU::sub3:17084 return 3;17085 case AMDGPU::sub4:17086 return 4; // Possible with TFE/LWE17087 }17088}17089 17090/// Adjust the writemask of MIMG, VIMAGE or VSAMPLE instructions17091SDNode *SITargetLowering::adjustWritemask(MachineSDNode *&Node,17092 SelectionDAG &DAG) const {17093 unsigned Opcode = Node->getMachineOpcode();17094 17095 // Subtract 1 because the vdata output is not a MachineSDNode operand.17096 int D16Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::d16) - 1;17097 if (D16Idx >= 0 && Node->getConstantOperandVal(D16Idx))17098 return Node; // not implemented for D1617099 17100 SDNode *Users[5] = {nullptr};17101 unsigned Lane = 0;17102 unsigned DmaskIdx =17103 AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::dmask) - 1;17104 unsigned OldDmask = Node->getConstantOperandVal(DmaskIdx);17105 unsigned NewDmask = 0;17106 unsigned TFEIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::tfe) - 1;17107 unsigned LWEIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::lwe) - 1;17108 bool UsesTFC = (int(TFEIdx) >= 0 && Node->getConstantOperandVal(TFEIdx)) ||17109 (int(LWEIdx) >= 0 && Node->getConstantOperandVal(LWEIdx));17110 unsigned TFCLane = 0;17111 bool HasChain = Node->getNumValues() > 1;17112 17113 if (OldDmask == 0) {17114 // These are folded out, but on the chance it happens don't assert.17115 return Node;17116 }17117 17118 unsigned OldBitsSet = llvm::popcount(OldDmask);17119 // Work out which is the TFE/LWE lane if that is enabled.17120 if (UsesTFC) {17121 TFCLane = OldBitsSet;17122 }17123 17124 // Try to figure out the used register components17125 for (SDUse &Use : Node->uses()) {17126 17127 // Don't look at users of the chain.17128 if (Use.getResNo() != 0)17129 continue;17130 17131 SDNode *User = Use.getUser();17132 17133 // Abort if we can't understand the usage17134 if (!User->isMachineOpcode() ||17135 User->getMachineOpcode() != TargetOpcode::EXTRACT_SUBREG)17136 return Node;17137 17138 // Lane means which subreg of %vgpra_vgprb_vgprc_vgprd is used.17139 // Note that subregs are packed, i.e. Lane==0 is the first bit set17140 // in OldDmask, so it can be any of X,Y,Z,W; Lane==1 is the second bit17141 // set, etc.17142 Lane = SubIdx2Lane(User->getConstantOperandVal(1));17143 if (Lane == ~0u)17144 return Node;17145 17146 // Check if the use is for the TFE/LWE generated result at VGPRn+1.17147 if (UsesTFC && Lane == TFCLane) {17148 Users[Lane] = User;17149 } else {17150 // Set which texture component corresponds to the lane.17151 unsigned Comp;17152 for (unsigned i = 0, Dmask = OldDmask; (i <= Lane) && (Dmask != 0); i++) {17153 Comp = llvm::countr_zero(Dmask);17154 Dmask &= ~(1 << Comp);17155 }17156 17157 // Abort if we have more than one user per component.17158 if (Users[Lane])17159 return Node;17160 17161 Users[Lane] = User;17162 NewDmask |= 1 << Comp;17163 }17164 }17165 17166 // Don't allow 0 dmask, as hardware assumes one channel enabled.17167 bool NoChannels = !NewDmask;17168 if (NoChannels) {17169 if (!UsesTFC) {17170 // No uses of the result and not using TFC. Then do nothing.17171 return Node;17172 }17173 // If the original dmask has one channel - then nothing to do17174 if (OldBitsSet == 1)17175 return Node;17176 // Use an arbitrary dmask - required for the instruction to work17177 NewDmask = 1;17178 }17179 // Abort if there's no change17180 if (NewDmask == OldDmask)17181 return Node;17182 17183 unsigned BitsSet = llvm::popcount(NewDmask);17184 17185 // Check for TFE or LWE - increase the number of channels by one to account17186 // for the extra return value17187 // This will need adjustment for D16 if this is also included in17188 // adjustWriteMask (this function) but at present D16 are excluded.17189 unsigned NewChannels = BitsSet + UsesTFC;17190 17191 int NewOpcode =17192 AMDGPU::getMaskedMIMGOp(Node->getMachineOpcode(), NewChannels);17193 assert(NewOpcode != -1 &&17194 NewOpcode != static_cast<int>(Node->getMachineOpcode()) &&17195 "failed to find equivalent MIMG op");17196 17197 // Adjust the writemask in the node17198 SmallVector<SDValue, 12> Ops;17199 llvm::append_range(Ops, Node->ops().take_front(DmaskIdx));17200 Ops.push_back(DAG.getTargetConstant(NewDmask, SDLoc(Node), MVT::i32));17201 llvm::append_range(Ops, Node->ops().drop_front(DmaskIdx + 1));17202 17203 MVT SVT = Node->getValueType(0).getVectorElementType().getSimpleVT();17204 17205 MVT ResultVT = NewChannels == 117206 ? SVT17207 : MVT::getVectorVT(SVT, NewChannels == 3 ? 417208 : NewChannels == 5 ? 817209 : NewChannels);17210 SDVTList NewVTList =17211 HasChain ? DAG.getVTList(ResultVT, MVT::Other) : DAG.getVTList(ResultVT);17212 17213 MachineSDNode *NewNode =17214 DAG.getMachineNode(NewOpcode, SDLoc(Node), NewVTList, Ops);17215 17216 if (HasChain) {17217 // Update chain.17218 DAG.setNodeMemRefs(NewNode, Node->memoperands());17219 DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 1), SDValue(NewNode, 1));17220 }17221 17222 if (NewChannels == 1) {17223 assert(Node->hasNUsesOfValue(1, 0));17224 SDNode *Copy =17225 DAG.getMachineNode(TargetOpcode::COPY, SDLoc(Node),17226 Users[Lane]->getValueType(0), SDValue(NewNode, 0));17227 DAG.ReplaceAllUsesWith(Users[Lane], Copy);17228 return nullptr;17229 }17230 17231 // Update the users of the node with the new indices17232 for (unsigned i = 0, Idx = AMDGPU::sub0; i < 5; ++i) {17233 SDNode *User = Users[i];17234 if (!User) {17235 // Handle the special case of NoChannels. We set NewDmask to 1 above, but17236 // Users[0] is still nullptr because channel 0 doesn't really have a use.17237 if (i || !NoChannels)17238 continue;17239 } else {17240 SDValue Op = DAG.getTargetConstant(Idx, SDLoc(User), MVT::i32);17241 SDNode *NewUser = DAG.UpdateNodeOperands(User, SDValue(NewNode, 0), Op);17242 if (NewUser != User) {17243 DAG.ReplaceAllUsesWith(SDValue(User, 0), SDValue(NewUser, 0));17244 DAG.RemoveDeadNode(User);17245 }17246 }17247 17248 switch (Idx) {17249 default:17250 break;17251 case AMDGPU::sub0:17252 Idx = AMDGPU::sub1;17253 break;17254 case AMDGPU::sub1:17255 Idx = AMDGPU::sub2;17256 break;17257 case AMDGPU::sub2:17258 Idx = AMDGPU::sub3;17259 break;17260 case AMDGPU::sub3:17261 Idx = AMDGPU::sub4;17262 break;17263 }17264 }17265 17266 DAG.RemoveDeadNode(Node);17267 return nullptr;17268}17269 17270static bool isFrameIndexOp(SDValue Op) {17271 if (Op.getOpcode() == ISD::AssertZext)17272 Op = Op.getOperand(0);17273 17274 return isa<FrameIndexSDNode>(Op);17275}17276 17277/// Legalize target independent instructions (e.g. INSERT_SUBREG)17278/// with frame index operands.17279/// LLVM assumes that inputs are to these instructions are registers.17280SDNode *17281SITargetLowering::legalizeTargetIndependentNode(SDNode *Node,17282 SelectionDAG &DAG) const {17283 if (Node->getOpcode() == ISD::CopyToReg) {17284 RegisterSDNode *DestReg = cast<RegisterSDNode>(Node->getOperand(1));17285 SDValue SrcVal = Node->getOperand(2);17286 17287 // Insert a copy to a VReg_1 virtual register so LowerI1Copies doesn't have17288 // to try understanding copies to physical registers.17289 if (SrcVal.getValueType() == MVT::i1 && DestReg->getReg().isPhysical()) {17290 SDLoc SL(Node);17291 MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();17292 SDValue VReg = DAG.getRegister(17293 MRI.createVirtualRegister(&AMDGPU::VReg_1RegClass), MVT::i1);17294 17295 SDNode *Glued = Node->getGluedNode();17296 SDValue ToVReg = DAG.getCopyToReg(17297 Node->getOperand(0), SL, VReg, SrcVal,17298 SDValue(Glued, Glued ? Glued->getNumValues() - 1 : 0));17299 SDValue ToResultReg = DAG.getCopyToReg(ToVReg, SL, SDValue(DestReg, 0),17300 VReg, ToVReg.getValue(1));17301 DAG.ReplaceAllUsesWith(Node, ToResultReg.getNode());17302 DAG.RemoveDeadNode(Node);17303 return ToResultReg.getNode();17304 }17305 }17306 17307 SmallVector<SDValue, 8> Ops;17308 for (unsigned i = 0; i < Node->getNumOperands(); ++i) {17309 if (!isFrameIndexOp(Node->getOperand(i))) {17310 Ops.push_back(Node->getOperand(i));17311 continue;17312 }17313 17314 SDLoc DL(Node);17315 Ops.push_back(SDValue(DAG.getMachineNode(AMDGPU::S_MOV_B32, DL,17316 Node->getOperand(i).getValueType(),17317 Node->getOperand(i)),17318 0));17319 }17320 17321 return DAG.UpdateNodeOperands(Node, Ops);17322}17323 17324/// Fold the instructions after selecting them.17325/// Returns null if users were already updated.17326SDNode *SITargetLowering::PostISelFolding(MachineSDNode *Node,17327 SelectionDAG &DAG) const {17328 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();17329 unsigned Opcode = Node->getMachineOpcode();17330 17331 if (TII->isImage(Opcode) && !TII->get(Opcode).mayStore() &&17332 !TII->isGather4(Opcode) &&17333 AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::dmask)) {17334 return adjustWritemask(Node, DAG);17335 }17336 17337 if (Opcode == AMDGPU::INSERT_SUBREG || Opcode == AMDGPU::REG_SEQUENCE) {17338 legalizeTargetIndependentNode(Node, DAG);17339 return Node;17340 }17341 17342 switch (Opcode) {17343 case AMDGPU::V_DIV_SCALE_F32_e64:17344 case AMDGPU::V_DIV_SCALE_F64_e64: {17345 // Satisfy the operand register constraint when one of the inputs is17346 // undefined. Ordinarily each undef value will have its own implicit_def of17347 // a vreg, so force these to use a single register.17348 SDValue Src0 = Node->getOperand(1);17349 SDValue Src1 = Node->getOperand(3);17350 SDValue Src2 = Node->getOperand(5);17351 17352 if ((Src0.isMachineOpcode() &&17353 Src0.getMachineOpcode() != AMDGPU::IMPLICIT_DEF) &&17354 (Src0 == Src1 || Src0 == Src2))17355 break;17356 17357 MVT VT = Src0.getValueType().getSimpleVT();17358 const TargetRegisterClass *RC =17359 getRegClassFor(VT, Src0.getNode()->isDivergent());17360 17361 MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();17362 SDValue UndefReg = DAG.getRegister(MRI.createVirtualRegister(RC), VT);17363 17364 SDValue ImpDef = DAG.getCopyToReg(DAG.getEntryNode(), SDLoc(Node), UndefReg,17365 Src0, SDValue());17366 17367 // src0 must be the same register as src1 or src2, even if the value is17368 // undefined, so make sure we don't violate this constraint.17369 if (Src0.isMachineOpcode() &&17370 Src0.getMachineOpcode() == AMDGPU::IMPLICIT_DEF) {17371 if (Src1.isMachineOpcode() &&17372 Src1.getMachineOpcode() != AMDGPU::IMPLICIT_DEF)17373 Src0 = Src1;17374 else if (Src2.isMachineOpcode() &&17375 Src2.getMachineOpcode() != AMDGPU::IMPLICIT_DEF)17376 Src0 = Src2;17377 else {17378 assert(Src1.getMachineOpcode() == AMDGPU::IMPLICIT_DEF);17379 Src0 = UndefReg;17380 Src1 = UndefReg;17381 }17382 } else17383 break;17384 17385 SmallVector<SDValue, 9> Ops(Node->ops());17386 Ops[1] = Src0;17387 Ops[3] = Src1;17388 Ops[5] = Src2;17389 Ops.push_back(ImpDef.getValue(1));17390 return DAG.getMachineNode(Opcode, SDLoc(Node), Node->getVTList(), Ops);17391 }17392 default:17393 break;17394 }17395 17396 return Node;17397}17398 17399// Any MIMG instructions that use tfe or lwe require an initialization of the17400// result register that will be written in the case of a memory access failure.17401// The required code is also added to tie this init code to the result of the17402// img instruction.17403void SITargetLowering::AddMemOpInit(MachineInstr &MI) const {17404 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();17405 const SIRegisterInfo &TRI = TII->getRegisterInfo();17406 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();17407 MachineBasicBlock &MBB = *MI.getParent();17408 17409 int DstIdx =17410 AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::vdata);17411 unsigned InitIdx = 0;17412 17413 if (TII->isImage(MI)) {17414 MachineOperand *TFE = TII->getNamedOperand(MI, AMDGPU::OpName::tfe);17415 MachineOperand *LWE = TII->getNamedOperand(MI, AMDGPU::OpName::lwe);17416 MachineOperand *D16 = TII->getNamedOperand(MI, AMDGPU::OpName::d16);17417 17418 if (!TFE && !LWE) // intersect_ray17419 return;17420 17421 unsigned TFEVal = TFE ? TFE->getImm() : 0;17422 unsigned LWEVal = LWE ? LWE->getImm() : 0;17423 unsigned D16Val = D16 ? D16->getImm() : 0;17424 17425 if (!TFEVal && !LWEVal)17426 return;17427 17428 // At least one of TFE or LWE are non-zero17429 // We have to insert a suitable initialization of the result value and17430 // tie this to the dest of the image instruction.17431 17432 // Calculate which dword we have to initialize to 0.17433 MachineOperand *MO_Dmask = TII->getNamedOperand(MI, AMDGPU::OpName::dmask);17434 17435 // check that dmask operand is found.17436 assert(MO_Dmask && "Expected dmask operand in instruction");17437 17438 unsigned dmask = MO_Dmask->getImm();17439 // Determine the number of active lanes taking into account the17440 // Gather4 special case17441 unsigned ActiveLanes = TII->isGather4(MI) ? 4 : llvm::popcount(dmask);17442 17443 bool Packed = !Subtarget->hasUnpackedD16VMem();17444 17445 InitIdx = D16Val && Packed ? ((ActiveLanes + 1) >> 1) + 1 : ActiveLanes + 1;17446 17447 // Abandon attempt if the dst size isn't large enough17448 // - this is in fact an error but this is picked up elsewhere and17449 // reported correctly.17450 const TargetRegisterClass *DstRC = TII->getRegClass(MI.getDesc(), DstIdx);17451 17452 uint32_t DstSize = TRI.getRegSizeInBits(*DstRC) / 32;17453 if (DstSize < InitIdx)17454 return;17455 } else if (TII->isMUBUF(MI) && AMDGPU::getMUBUFTfe(MI.getOpcode())) {17456 const TargetRegisterClass *DstRC = TII->getRegClass(MI.getDesc(), DstIdx);17457 InitIdx = TRI.getRegSizeInBits(*DstRC) / 32;17458 } else {17459 return;17460 }17461 17462 const DebugLoc &DL = MI.getDebugLoc();17463 17464 // Create a register for the initialization value.17465 Register PrevDst = MRI.cloneVirtualRegister(MI.getOperand(DstIdx).getReg());17466 unsigned NewDst = 0; // Final initialized value will be in here17467 17468 // If PRTStrictNull feature is enabled (the default) then initialize17469 // all the result registers to 0, otherwise just the error indication17470 // register (VGPRn+1)17471 unsigned SizeLeft = Subtarget->usePRTStrictNull() ? InitIdx : 1;17472 unsigned CurrIdx = Subtarget->usePRTStrictNull() ? 0 : (InitIdx - 1);17473 17474 BuildMI(MBB, MI, DL, TII->get(AMDGPU::IMPLICIT_DEF), PrevDst);17475 for (; SizeLeft; SizeLeft--, CurrIdx++) {17476 NewDst = MRI.createVirtualRegister(TII->getOpRegClass(MI, DstIdx));17477 // Initialize dword17478 Register SubReg = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass);17479 // clang-format off17480 BuildMI(MBB, MI, DL, TII->get(AMDGPU::V_MOV_B32_e32), SubReg)17481 .addImm(0);17482 // clang-format on17483 // Insert into the super-reg17484 BuildMI(MBB, MI, DL, TII->get(TargetOpcode::INSERT_SUBREG), NewDst)17485 .addReg(PrevDst)17486 .addReg(SubReg)17487 .addImm(SIRegisterInfo::getSubRegFromChannel(CurrIdx));17488 17489 PrevDst = NewDst;17490 }17491 17492 // Add as an implicit operand17493 MI.addOperand(MachineOperand::CreateReg(NewDst, false, true));17494 17495 // Tie the just added implicit operand to the dst17496 MI.tieOperands(DstIdx, MI.getNumOperands() - 1);17497}17498 17499/// Assign the register class depending on the number of17500/// bits set in the writemask17501void SITargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI,17502 SDNode *Node) const {17503 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();17504 17505 MachineFunction *MF = MI.getMF();17506 MachineRegisterInfo &MRI = MF->getRegInfo();17507 17508 if (TII->isVOP3(MI.getOpcode())) {17509 // Make sure constant bus requirements are respected.17510 TII->legalizeOperandsVOP3(MRI, MI);17511 17512 if (TII->isMAI(MI)) {17513 // The ordinary src0, src1, src2 were legalized above.17514 //17515 // We have to also legalize the appended v_mfma_ld_scale_b32 operands,17516 // as a separate instruction.17517 int Src0Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),17518 AMDGPU::OpName::scale_src0);17519 if (Src0Idx != -1) {17520 int Src1Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),17521 AMDGPU::OpName::scale_src1);17522 if (TII->usesConstantBus(MRI, MI, Src0Idx) &&17523 TII->usesConstantBus(MRI, MI, Src1Idx))17524 TII->legalizeOpWithMove(MI, Src1Idx);17525 }17526 }17527 17528 return;17529 }17530 17531 if (TII->isImage(MI))17532 TII->enforceOperandRCAlignment(MI, AMDGPU::OpName::vaddr);17533}17534 17535static SDValue buildSMovImm32(SelectionDAG &DAG, const SDLoc &DL,17536 uint64_t Val) {17537 SDValue K = DAG.getTargetConstant(Val, DL, MVT::i32);17538 return SDValue(DAG.getMachineNode(AMDGPU::S_MOV_B32, DL, MVT::i32, K), 0);17539}17540 17541MachineSDNode *SITargetLowering::wrapAddr64Rsrc(SelectionDAG &DAG,17542 const SDLoc &DL,17543 SDValue Ptr) const {17544 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();17545 17546 // Build the half of the subregister with the constants before building the17547 // full 128-bit register. If we are building multiple resource descriptors,17548 // this will allow CSEing of the 2-component register.17549 const SDValue Ops0[] = {17550 DAG.getTargetConstant(AMDGPU::SGPR_64RegClassID, DL, MVT::i32),17551 buildSMovImm32(DAG, DL, 0),17552 DAG.getTargetConstant(AMDGPU::sub0, DL, MVT::i32),17553 buildSMovImm32(DAG, DL, TII->getDefaultRsrcDataFormat() >> 32),17554 DAG.getTargetConstant(AMDGPU::sub1, DL, MVT::i32)};17555 17556 SDValue SubRegHi = SDValue(17557 DAG.getMachineNode(AMDGPU::REG_SEQUENCE, DL, MVT::v2i32, Ops0), 0);17558 17559 // Combine the constants and the pointer.17560 const SDValue Ops1[] = {17561 DAG.getTargetConstant(AMDGPU::SGPR_128RegClassID, DL, MVT::i32), Ptr,17562 DAG.getTargetConstant(AMDGPU::sub0_sub1, DL, MVT::i32), SubRegHi,17563 DAG.getTargetConstant(AMDGPU::sub2_sub3, DL, MVT::i32)};17564 17565 return DAG.getMachineNode(AMDGPU::REG_SEQUENCE, DL, MVT::v4i32, Ops1);17566}17567 17568/// Return a resource descriptor with the 'Add TID' bit enabled17569/// The TID (Thread ID) is multiplied by the stride value (bits [61:48]17570/// of the resource descriptor) to create an offset, which is added to17571/// the resource pointer.17572MachineSDNode *SITargetLowering::buildRSRC(SelectionDAG &DAG, const SDLoc &DL,17573 SDValue Ptr, uint32_t RsrcDword1,17574 uint64_t RsrcDword2And3) const {17575 SDValue PtrLo = DAG.getTargetExtractSubreg(AMDGPU::sub0, DL, MVT::i32, Ptr);17576 SDValue PtrHi = DAG.getTargetExtractSubreg(AMDGPU::sub1, DL, MVT::i32, Ptr);17577 if (RsrcDword1) {17578 PtrHi =17579 SDValue(DAG.getMachineNode(AMDGPU::S_OR_B32, DL, MVT::i32, PtrHi,17580 DAG.getConstant(RsrcDword1, DL, MVT::i32)),17581 0);17582 }17583 17584 SDValue DataLo =17585 buildSMovImm32(DAG, DL, RsrcDword2And3 & UINT64_C(0xFFFFFFFF));17586 SDValue DataHi = buildSMovImm32(DAG, DL, RsrcDword2And3 >> 32);17587 17588 const SDValue Ops[] = {17589 DAG.getTargetConstant(AMDGPU::SGPR_128RegClassID, DL, MVT::i32),17590 PtrLo,17591 DAG.getTargetConstant(AMDGPU::sub0, DL, MVT::i32),17592 PtrHi,17593 DAG.getTargetConstant(AMDGPU::sub1, DL, MVT::i32),17594 DataLo,17595 DAG.getTargetConstant(AMDGPU::sub2, DL, MVT::i32),17596 DataHi,17597 DAG.getTargetConstant(AMDGPU::sub3, DL, MVT::i32)};17598 17599 return DAG.getMachineNode(AMDGPU::REG_SEQUENCE, DL, MVT::v4i32, Ops);17600}17601 17602//===----------------------------------------------------------------------===//17603// SI Inline Assembly Support17604//===----------------------------------------------------------------------===//17605 17606std::pair<unsigned, const TargetRegisterClass *>17607SITargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI_,17608 StringRef Constraint,17609 MVT VT) const {17610 const SIRegisterInfo *TRI = static_cast<const SIRegisterInfo *>(TRI_);17611 17612 const TargetRegisterClass *RC = nullptr;17613 if (Constraint.size() == 1) {17614 // Check if we cannot determine the bit size of the given value type. This17615 // can happen, for example, in this situation where we have an empty struct17616 // (size 0): `call void asm "", "v"({} poison)`-17617 if (VT == MVT::Other)17618 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);17619 const unsigned BitWidth = VT.getSizeInBits();17620 switch (Constraint[0]) {17621 default:17622 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);17623 case 's':17624 case 'r':17625 switch (BitWidth) {17626 case 16:17627 RC = &AMDGPU::SReg_32RegClass;17628 break;17629 case 64:17630 RC = &AMDGPU::SGPR_64RegClass;17631 break;17632 default:17633 RC = SIRegisterInfo::getSGPRClassForBitWidth(BitWidth);17634 if (!RC)17635 return std::pair(0U, nullptr);17636 break;17637 }17638 break;17639 case 'v':17640 switch (BitWidth) {17641 case 16:17642 RC = Subtarget->useRealTrue16Insts() ? &AMDGPU::VGPR_16RegClass17643 : &AMDGPU::VGPR_32_Lo256RegClass;17644 break;17645 default:17646 RC = Subtarget->has1024AddressableVGPRs()17647 ? TRI->getAlignedLo256VGPRClassForBitWidth(BitWidth)17648 : TRI->getVGPRClassForBitWidth(BitWidth);17649 if (!RC)17650 return std::pair(0U, nullptr);17651 break;17652 }17653 break;17654 case 'a':17655 if (!Subtarget->hasMAIInsts())17656 break;17657 switch (BitWidth) {17658 case 16:17659 RC = &AMDGPU::AGPR_32RegClass;17660 break;17661 default:17662 RC = TRI->getAGPRClassForBitWidth(BitWidth);17663 if (!RC)17664 return std::pair(0U, nullptr);17665 break;17666 }17667 break;17668 }17669 } else if (Constraint == "VA" && Subtarget->hasGFX90AInsts()) {17670 const unsigned BitWidth = VT.getSizeInBits();17671 switch (BitWidth) {17672 case 16:17673 RC = &AMDGPU::AV_32RegClass;17674 break;17675 default:17676 RC = TRI->getVectorSuperClassForBitWidth(BitWidth);17677 if (!RC)17678 return std::pair(0U, nullptr);17679 break;17680 }17681 }17682 17683 // We actually support i128, i16 and f16 as inline parameters17684 // even if they are not reported as legal17685 if (RC && (isTypeLegal(VT) || VT.SimpleTy == MVT::i128 ||17686 VT.SimpleTy == MVT::i16 || VT.SimpleTy == MVT::f16))17687 return std::pair(0U, RC);17688 17689 auto [Kind, Idx, NumRegs] = AMDGPU::parseAsmConstraintPhysReg(Constraint);17690 if (Kind != '\0') {17691 if (Kind == 'v') {17692 RC = &AMDGPU::VGPR_32_Lo256RegClass;17693 } else if (Kind == 's') {17694 RC = &AMDGPU::SGPR_32RegClass;17695 } else if (Kind == 'a') {17696 RC = &AMDGPU::AGPR_32RegClass;17697 }17698 17699 if (RC) {17700 if (NumRegs > 1) {17701 if (Idx >= RC->getNumRegs() || Idx + NumRegs - 1 >= RC->getNumRegs())17702 return std::pair(0U, nullptr);17703 17704 uint32_t Width = NumRegs * 32;17705 // Prohibit constraints for register ranges with a width that does not17706 // match the required type.17707 if (VT.SimpleTy != MVT::Other && Width != VT.getSizeInBits())17708 return std::pair(0U, nullptr);17709 17710 MCRegister Reg = RC->getRegister(Idx);17711 if (SIRegisterInfo::isVGPRClass(RC))17712 RC = TRI->getVGPRClassForBitWidth(Width);17713 else if (SIRegisterInfo::isSGPRClass(RC))17714 RC = TRI->getSGPRClassForBitWidth(Width);17715 else if (SIRegisterInfo::isAGPRClass(RC))17716 RC = TRI->getAGPRClassForBitWidth(Width);17717 if (RC) {17718 Reg = TRI->getMatchingSuperReg(Reg, AMDGPU::sub0, RC);17719 if (!Reg) {17720 // The register class does not contain the requested register,17721 // e.g., because it is an SGPR pair that would violate alignment17722 // requirements.17723 return std::pair(0U, nullptr);17724 }17725 return std::pair(Reg, RC);17726 }17727 }17728 17729 // Check for lossy scalar/vector conversions.17730 if (VT.isVector() && VT.getSizeInBits() != 32)17731 return std::pair(0U, nullptr);17732 if (Idx < RC->getNumRegs())17733 return std::pair(RC->getRegister(Idx), RC);17734 return std::pair(0U, nullptr);17735 }17736 }17737 17738 auto Ret = TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);17739 if (Ret.first)17740 Ret.second = TRI->getPhysRegBaseClass(Ret.first);17741 17742 return Ret;17743}17744 17745static bool isImmConstraint(StringRef Constraint) {17746 if (Constraint.size() == 1) {17747 switch (Constraint[0]) {17748 default:17749 break;17750 case 'I':17751 case 'J':17752 case 'A':17753 case 'B':17754 case 'C':17755 return true;17756 }17757 } else if (Constraint == "DA" || Constraint == "DB") {17758 return true;17759 }17760 return false;17761}17762 17763SITargetLowering::ConstraintType17764SITargetLowering::getConstraintType(StringRef Constraint) const {17765 if (Constraint.size() == 1) {17766 switch (Constraint[0]) {17767 default:17768 break;17769 case 's':17770 case 'v':17771 case 'a':17772 return C_RegisterClass;17773 }17774 } else if (Constraint.size() == 2) {17775 if (Constraint == "VA")17776 return C_RegisterClass;17777 }17778 if (isImmConstraint(Constraint)) {17779 return C_Other;17780 }17781 return TargetLowering::getConstraintType(Constraint);17782}17783 17784static uint64_t clearUnusedBits(uint64_t Val, unsigned Size) {17785 if (!AMDGPU::isInlinableIntLiteral(Val)) {17786 Val = Val & maskTrailingOnes<uint64_t>(Size);17787 }17788 return Val;17789}17790 17791void SITargetLowering::LowerAsmOperandForConstraint(SDValue Op,17792 StringRef Constraint,17793 std::vector<SDValue> &Ops,17794 SelectionDAG &DAG) const {17795 if (isImmConstraint(Constraint)) {17796 uint64_t Val;17797 if (getAsmOperandConstVal(Op, Val) &&17798 checkAsmConstraintVal(Op, Constraint, Val)) {17799 Val = clearUnusedBits(Val, Op.getScalarValueSizeInBits());17800 Ops.push_back(DAG.getTargetConstant(Val, SDLoc(Op), MVT::i64));17801 }17802 } else {17803 TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);17804 }17805}17806 17807bool SITargetLowering::getAsmOperandConstVal(SDValue Op, uint64_t &Val) const {17808 unsigned Size = Op.getScalarValueSizeInBits();17809 if (Size > 64)17810 return false;17811 17812 if (Size == 16 && !Subtarget->has16BitInsts())17813 return false;17814 17815 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {17816 Val = C->getSExtValue();17817 return true;17818 }17819 if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Op)) {17820 Val = C->getValueAPF().bitcastToAPInt().getSExtValue();17821 return true;17822 }17823 if (BuildVectorSDNode *V = dyn_cast<BuildVectorSDNode>(Op)) {17824 if (Size != 16 || Op.getNumOperands() != 2)17825 return false;17826 if (Op.getOperand(0).isUndef() || Op.getOperand(1).isUndef())17827 return false;17828 if (ConstantSDNode *C = V->getConstantSplatNode()) {17829 Val = C->getSExtValue();17830 return true;17831 }17832 if (ConstantFPSDNode *C = V->getConstantFPSplatNode()) {17833 Val = C->getValueAPF().bitcastToAPInt().getSExtValue();17834 return true;17835 }17836 }17837 17838 return false;17839}17840 17841bool SITargetLowering::checkAsmConstraintVal(SDValue Op, StringRef Constraint,17842 uint64_t Val) const {17843 if (Constraint.size() == 1) {17844 switch (Constraint[0]) {17845 case 'I':17846 return AMDGPU::isInlinableIntLiteral(Val);17847 case 'J':17848 return isInt<16>(Val);17849 case 'A':17850 return checkAsmConstraintValA(Op, Val);17851 case 'B':17852 return isInt<32>(Val);17853 case 'C':17854 return isUInt<32>(clearUnusedBits(Val, Op.getScalarValueSizeInBits())) ||17855 AMDGPU::isInlinableIntLiteral(Val);17856 default:17857 break;17858 }17859 } else if (Constraint.size() == 2) {17860 if (Constraint == "DA") {17861 int64_t HiBits = static_cast<int32_t>(Val >> 32);17862 int64_t LoBits = static_cast<int32_t>(Val);17863 return checkAsmConstraintValA(Op, HiBits, 32) &&17864 checkAsmConstraintValA(Op, LoBits, 32);17865 }17866 if (Constraint == "DB") {17867 return true;17868 }17869 }17870 llvm_unreachable("Invalid asm constraint");17871}17872 17873bool SITargetLowering::checkAsmConstraintValA(SDValue Op, uint64_t Val,17874 unsigned MaxSize) const {17875 unsigned Size = std::min<unsigned>(Op.getScalarValueSizeInBits(), MaxSize);17876 bool HasInv2Pi = Subtarget->hasInv2PiInlineImm();17877 if (Size == 16) {17878 MVT VT = Op.getSimpleValueType();17879 switch (VT.SimpleTy) {17880 default:17881 return false;17882 case MVT::i16:17883 return AMDGPU::isInlinableLiteralI16(Val, HasInv2Pi);17884 case MVT::f16:17885 return AMDGPU::isInlinableLiteralFP16(Val, HasInv2Pi);17886 case MVT::bf16:17887 return AMDGPU::isInlinableLiteralBF16(Val, HasInv2Pi);17888 case MVT::v2i16:17889 return AMDGPU::getInlineEncodingV2I16(Val).has_value();17890 case MVT::v2f16:17891 return AMDGPU::getInlineEncodingV2F16(Val).has_value();17892 case MVT::v2bf16:17893 return AMDGPU::getInlineEncodingV2BF16(Val).has_value();17894 }17895 }17896 if ((Size == 32 && AMDGPU::isInlinableLiteral32(Val, HasInv2Pi)) ||17897 (Size == 64 && AMDGPU::isInlinableLiteral64(Val, HasInv2Pi)))17898 return true;17899 return false;17900}17901 17902static int getAlignedAGPRClassID(unsigned UnalignedClassID) {17903 switch (UnalignedClassID) {17904 case AMDGPU::VReg_64RegClassID:17905 return AMDGPU::VReg_64_Align2RegClassID;17906 case AMDGPU::VReg_96RegClassID:17907 return AMDGPU::VReg_96_Align2RegClassID;17908 case AMDGPU::VReg_128RegClassID:17909 return AMDGPU::VReg_128_Align2RegClassID;17910 case AMDGPU::VReg_160RegClassID:17911 return AMDGPU::VReg_160_Align2RegClassID;17912 case AMDGPU::VReg_192RegClassID:17913 return AMDGPU::VReg_192_Align2RegClassID;17914 case AMDGPU::VReg_224RegClassID:17915 return AMDGPU::VReg_224_Align2RegClassID;17916 case AMDGPU::VReg_256RegClassID:17917 return AMDGPU::VReg_256_Align2RegClassID;17918 case AMDGPU::VReg_288RegClassID:17919 return AMDGPU::VReg_288_Align2RegClassID;17920 case AMDGPU::VReg_320RegClassID:17921 return AMDGPU::VReg_320_Align2RegClassID;17922 case AMDGPU::VReg_352RegClassID:17923 return AMDGPU::VReg_352_Align2RegClassID;17924 case AMDGPU::VReg_384RegClassID:17925 return AMDGPU::VReg_384_Align2RegClassID;17926 case AMDGPU::VReg_512RegClassID:17927 return AMDGPU::VReg_512_Align2RegClassID;17928 case AMDGPU::VReg_1024RegClassID:17929 return AMDGPU::VReg_1024_Align2RegClassID;17930 case AMDGPU::AReg_64RegClassID:17931 return AMDGPU::AReg_64_Align2RegClassID;17932 case AMDGPU::AReg_96RegClassID:17933 return AMDGPU::AReg_96_Align2RegClassID;17934 case AMDGPU::AReg_128RegClassID:17935 return AMDGPU::AReg_128_Align2RegClassID;17936 case AMDGPU::AReg_160RegClassID:17937 return AMDGPU::AReg_160_Align2RegClassID;17938 case AMDGPU::AReg_192RegClassID:17939 return AMDGPU::AReg_192_Align2RegClassID;17940 case AMDGPU::AReg_256RegClassID:17941 return AMDGPU::AReg_256_Align2RegClassID;17942 case AMDGPU::AReg_512RegClassID:17943 return AMDGPU::AReg_512_Align2RegClassID;17944 case AMDGPU::AReg_1024RegClassID:17945 return AMDGPU::AReg_1024_Align2RegClassID;17946 default:17947 return -1;17948 }17949}17950 17951// Figure out which registers should be reserved for stack access. Only after17952// the function is legalized do we know all of the non-spill stack objects or if17953// calls are present.17954void SITargetLowering::finalizeLowering(MachineFunction &MF) const {17955 MachineRegisterInfo &MRI = MF.getRegInfo();17956 SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();17957 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();17958 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();17959 const SIInstrInfo *TII = ST.getInstrInfo();17960 17961 if (Info->isEntryFunction()) {17962 // Callable functions have fixed registers used for stack access.17963 reservePrivateMemoryRegs(getTargetMachine(), MF, *TRI, *Info);17964 }17965 17966 // TODO: Move this logic to getReservedRegs()17967 // Reserve the SGPR(s) to save/restore EXEC for WWM spill/copy handling.17968 unsigned MaxNumSGPRs = ST.getMaxNumSGPRs(MF);17969 Register SReg = ST.isWave32()17970 ? AMDGPU::SGPR_32RegClass.getRegister(MaxNumSGPRs - 1)17971 : TRI->getAlignedHighSGPRForRC(MF, /*Align=*/2,17972 &AMDGPU::SGPR_64RegClass);17973 Info->setSGPRForEXECCopy(SReg);17974 17975 assert(!TRI->isSubRegister(Info->getScratchRSrcReg(),17976 Info->getStackPtrOffsetReg()));17977 if (Info->getStackPtrOffsetReg() != AMDGPU::SP_REG)17978 MRI.replaceRegWith(AMDGPU::SP_REG, Info->getStackPtrOffsetReg());17979 17980 // We need to worry about replacing the default register with itself in case17981 // of MIR testcases missing the MFI.17982 if (Info->getScratchRSrcReg() != AMDGPU::PRIVATE_RSRC_REG)17983 MRI.replaceRegWith(AMDGPU::PRIVATE_RSRC_REG, Info->getScratchRSrcReg());17984 17985 if (Info->getFrameOffsetReg() != AMDGPU::FP_REG)17986 MRI.replaceRegWith(AMDGPU::FP_REG, Info->getFrameOffsetReg());17987 17988 Info->limitOccupancy(MF);17989 17990 if (ST.isWave32() && !MF.empty()) {17991 for (auto &MBB : MF) {17992 for (auto &MI : MBB) {17993 TII->fixImplicitOperands(MI);17994 }17995 }17996 }17997 17998 // FIXME: This is a hack to fixup AGPR classes to use the properly aligned17999 // classes if required. Ideally the register class constraints would differ18000 // per-subtarget, but there's no easy way to achieve that right now. This is18001 // not a problem for VGPRs because the correctly aligned VGPR class is implied18002 // from using them as the register class for legal types.18003 if (ST.needsAlignedVGPRs()) {18004 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {18005 const Register Reg = Register::index2VirtReg(I);18006 const TargetRegisterClass *RC = MRI.getRegClassOrNull(Reg);18007 if (!RC)18008 continue;18009 int NewClassID = getAlignedAGPRClassID(RC->getID());18010 if (NewClassID != -1)18011 MRI.setRegClass(Reg, TRI->getRegClass(NewClassID));18012 }18013 }18014 18015 TargetLoweringBase::finalizeLowering(MF);18016}18017 18018void SITargetLowering::computeKnownBitsForTargetNode(const SDValue Op,18019 KnownBits &Known,18020 const APInt &DemandedElts,18021 const SelectionDAG &DAG,18022 unsigned Depth) const {18023 Known.resetAll();18024 unsigned Opc = Op.getOpcode();18025 switch (Opc) {18026 case ISD::INTRINSIC_WO_CHAIN: {18027 unsigned IID = Op.getConstantOperandVal(0);18028 switch (IID) {18029 case Intrinsic::amdgcn_mbcnt_lo:18030 case Intrinsic::amdgcn_mbcnt_hi: {18031 const GCNSubtarget &ST =18032 DAG.getMachineFunction().getSubtarget<GCNSubtarget>();18033 // Wave64 mbcnt_lo returns at most 32 + src1. Otherwise these return at18034 // most 31 + src1.18035 Known.Zero.setBitsFrom(18036 IID == Intrinsic::amdgcn_mbcnt_lo ? ST.getWavefrontSizeLog2() : 5);18037 KnownBits Known2 = DAG.computeKnownBits(Op.getOperand(2), Depth + 1);18038 Known = KnownBits::add(Known, Known2);18039 return;18040 }18041 }18042 break;18043 }18044 }18045 return AMDGPUTargetLowering::computeKnownBitsForTargetNode(18046 Op, Known, DemandedElts, DAG, Depth);18047}18048 18049void SITargetLowering::computeKnownBitsForFrameIndex(18050 const int FI, KnownBits &Known, const MachineFunction &MF) const {18051 TargetLowering::computeKnownBitsForFrameIndex(FI, Known, MF);18052 18053 // Set the high bits to zero based on the maximum allowed scratch size per18054 // wave. We can't use vaddr in MUBUF instructions if we don't know the address18055 // calculation won't overflow, so assume the sign bit is never set.18056 Known.Zero.setHighBits(getSubtarget()->getKnownHighZeroBitsForFrameIndex());18057}18058 18059static void knownBitsForWorkitemID(const GCNSubtarget &ST,18060 GISelValueTracking &VT, KnownBits &Known,18061 unsigned Dim) {18062 unsigned MaxValue =18063 ST.getMaxWorkitemID(VT.getMachineFunction().getFunction(), Dim);18064 Known.Zero.setHighBits(llvm::countl_zero(MaxValue));18065}18066 18067static void knownBitsForSBFE(const MachineInstr &MI, GISelValueTracking &VT,18068 KnownBits &Known, const APInt &DemandedElts,18069 unsigned BFEWidth, bool SExt, unsigned Depth) {18070 const MachineRegisterInfo &MRI = VT.getMachineFunction().getRegInfo();18071 const MachineOperand &Src1 = MI.getOperand(2);18072 18073 unsigned Src1Cst = 0;18074 if (Src1.isImm()) {18075 Src1Cst = Src1.getImm();18076 } else if (Src1.isReg()) {18077 auto Cst = getIConstantVRegValWithLookThrough(Src1.getReg(), MRI);18078 if (!Cst)18079 return;18080 Src1Cst = Cst->Value.getZExtValue();18081 } else {18082 return;18083 }18084 18085 // Offset is at bits [4:0] for 32 bit, [5:0] for 64 bit.18086 // Width is always [22:16].18087 const unsigned Offset =18088 Src1Cst & maskTrailingOnes<unsigned>((BFEWidth == 32) ? 5 : 6);18089 const unsigned Width = (Src1Cst >> 16) & maskTrailingOnes<unsigned>(6);18090 18091 if (Width >= BFEWidth) // Ill-formed.18092 return;18093 18094 VT.computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, DemandedElts,18095 Depth + 1);18096 18097 Known = Known.extractBits(Width, Offset);18098 18099 if (SExt)18100 Known = Known.sext(BFEWidth);18101 else18102 Known = Known.zext(BFEWidth);18103}18104 18105void SITargetLowering::computeKnownBitsForTargetInstr(18106 GISelValueTracking &VT, Register R, KnownBits &Known,18107 const APInt &DemandedElts, const MachineRegisterInfo &MRI,18108 unsigned Depth) const {18109 Known.resetAll();18110 const MachineInstr *MI = MRI.getVRegDef(R);18111 switch (MI->getOpcode()) {18112 case AMDGPU::S_BFE_I32:18113 return knownBitsForSBFE(*MI, VT, Known, DemandedElts, /*Width=*/32,18114 /*SExt=*/true, Depth);18115 case AMDGPU::S_BFE_U32:18116 return knownBitsForSBFE(*MI, VT, Known, DemandedElts, /*Width=*/32,18117 /*SExt=*/false, Depth);18118 case AMDGPU::S_BFE_I64:18119 return knownBitsForSBFE(*MI, VT, Known, DemandedElts, /*Width=*/64,18120 /*SExt=*/true, Depth);18121 case AMDGPU::S_BFE_U64:18122 return knownBitsForSBFE(*MI, VT, Known, DemandedElts, /*Width=*/64,18123 /*SExt=*/false, Depth);18124 case AMDGPU::G_INTRINSIC:18125 case AMDGPU::G_INTRINSIC_CONVERGENT: {18126 Intrinsic::ID IID = cast<GIntrinsic>(MI)->getIntrinsicID();18127 switch (IID) {18128 case Intrinsic::amdgcn_workitem_id_x:18129 knownBitsForWorkitemID(*getSubtarget(), VT, Known, 0);18130 break;18131 case Intrinsic::amdgcn_workitem_id_y:18132 knownBitsForWorkitemID(*getSubtarget(), VT, Known, 1);18133 break;18134 case Intrinsic::amdgcn_workitem_id_z:18135 knownBitsForWorkitemID(*getSubtarget(), VT, Known, 2);18136 break;18137 case Intrinsic::amdgcn_mbcnt_lo:18138 case Intrinsic::amdgcn_mbcnt_hi: {18139 // Wave64 mbcnt_lo returns at most 32 + src1. Otherwise these return at18140 // most 31 + src1.18141 Known.Zero.setBitsFrom(IID == Intrinsic::amdgcn_mbcnt_lo18142 ? getSubtarget()->getWavefrontSizeLog2()18143 : 5);18144 KnownBits Known2;18145 VT.computeKnownBitsImpl(MI->getOperand(3).getReg(), Known2, DemandedElts,18146 Depth + 1);18147 Known = KnownBits::add(Known, Known2);18148 break;18149 }18150 case Intrinsic::amdgcn_groupstaticsize: {18151 // We can report everything over the maximum size as 0. We can't report18152 // based on the actual size because we don't know if it's accurate or not18153 // at any given point.18154 Known.Zero.setHighBits(18155 llvm::countl_zero(getSubtarget()->getAddressableLocalMemorySize()));18156 break;18157 }18158 }18159 break;18160 }18161 case AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE:18162 Known.Zero.setHighBits(24);18163 break;18164 case AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT:18165 Known.Zero.setHighBits(16);18166 break;18167 case AMDGPU::G_AMDGPU_SMED3:18168 case AMDGPU::G_AMDGPU_UMED3: {18169 auto [Dst, Src0, Src1, Src2] = MI->getFirst4Regs();18170 18171 KnownBits Known2;18172 VT.computeKnownBitsImpl(Src2, Known2, DemandedElts, Depth + 1);18173 if (Known2.isUnknown())18174 break;18175 18176 KnownBits Known1;18177 VT.computeKnownBitsImpl(Src1, Known1, DemandedElts, Depth + 1);18178 if (Known1.isUnknown())18179 break;18180 18181 KnownBits Known0;18182 VT.computeKnownBitsImpl(Src0, Known0, DemandedElts, Depth + 1);18183 if (Known0.isUnknown())18184 break;18185 18186 // TODO: Handle LeadZero/LeadOne from UMIN/UMAX handling.18187 Known.Zero = Known0.Zero & Known1.Zero & Known2.Zero;18188 Known.One = Known0.One & Known1.One & Known2.One;18189 break;18190 }18191 }18192}18193 18194Align SITargetLowering::computeKnownAlignForTargetInstr(18195 GISelValueTracking &VT, Register R, const MachineRegisterInfo &MRI,18196 unsigned Depth) const {18197 const MachineInstr *MI = MRI.getVRegDef(R);18198 if (auto *GI = dyn_cast<GIntrinsic>(MI)) {18199 // FIXME: Can this move to generic code? What about the case where the call18200 // site specifies a lower alignment?18201 Intrinsic::ID IID = GI->getIntrinsicID();18202 LLVMContext &Ctx = VT.getMachineFunction().getFunction().getContext();18203 AttributeList Attrs =18204 Intrinsic::getAttributes(Ctx, IID, Intrinsic::getType(Ctx, IID));18205 if (MaybeAlign RetAlign = Attrs.getRetAlignment())18206 return *RetAlign;18207 }18208 return Align(1);18209}18210 18211Align SITargetLowering::getPrefLoopAlignment(MachineLoop *ML) const {18212 const Align PrefAlign = TargetLowering::getPrefLoopAlignment(ML);18213 const Align CacheLineAlign = Align(64);18214 18215 // Pre-GFX10 target did not benefit from loop alignment18216 if (!ML || DisableLoopAlignment || !getSubtarget()->hasInstPrefetch() ||18217 getSubtarget()->hasInstFwdPrefetchBug())18218 return PrefAlign;18219 18220 // On GFX10 I$ is 4 x 64 bytes cache lines.18221 // By default prefetcher keeps one cache line behind and reads two ahead.18222 // We can modify it with S_INST_PREFETCH for larger loops to have two lines18223 // behind and one ahead.18224 // Therefor we can benefit from aligning loop headers if loop fits 192 bytes.18225 // If loop fits 64 bytes it always spans no more than two cache lines and18226 // does not need an alignment.18227 // Else if loop is less or equal 128 bytes we do not need to modify prefetch,18228 // Else if loop is less or equal 192 bytes we need two lines behind.18229 18230 const SIInstrInfo *TII = getSubtarget()->getInstrInfo();18231 const MachineBasicBlock *Header = ML->getHeader();18232 if (Header->getAlignment() != PrefAlign)18233 return Header->getAlignment(); // Already processed.18234 18235 unsigned LoopSize = 0;18236 for (const MachineBasicBlock *MBB : ML->blocks()) {18237 // If inner loop block is aligned assume in average half of the alignment18238 // size to be added as nops.18239 if (MBB != Header)18240 LoopSize += MBB->getAlignment().value() / 2;18241 18242 for (const MachineInstr &MI : *MBB) {18243 LoopSize += TII->getInstSizeInBytes(MI);18244 if (LoopSize > 192)18245 return PrefAlign;18246 }18247 }18248 18249 if (LoopSize <= 64)18250 return PrefAlign;18251 18252 if (LoopSize <= 128)18253 return CacheLineAlign;18254 18255 // If any of parent loops is surrounded by prefetch instructions do not18256 // insert new for inner loop, which would reset parent's settings.18257 for (MachineLoop *P = ML->getParentLoop(); P; P = P->getParentLoop()) {18258 if (MachineBasicBlock *Exit = P->getExitBlock()) {18259 auto I = Exit->getFirstNonDebugInstr();18260 if (I != Exit->end() && I->getOpcode() == AMDGPU::S_INST_PREFETCH)18261 return CacheLineAlign;18262 }18263 }18264 18265 MachineBasicBlock *Pre = ML->getLoopPreheader();18266 MachineBasicBlock *Exit = ML->getExitBlock();18267 18268 if (Pre && Exit) {18269 auto PreTerm = Pre->getFirstTerminator();18270 if (PreTerm == Pre->begin() ||18271 std::prev(PreTerm)->getOpcode() != AMDGPU::S_INST_PREFETCH)18272 BuildMI(*Pre, PreTerm, DebugLoc(), TII->get(AMDGPU::S_INST_PREFETCH))18273 .addImm(1); // prefetch 2 lines behind PC18274 18275 auto ExitHead = Exit->getFirstNonDebugInstr();18276 if (ExitHead == Exit->end() ||18277 ExitHead->getOpcode() != AMDGPU::S_INST_PREFETCH)18278 BuildMI(*Exit, ExitHead, DebugLoc(), TII->get(AMDGPU::S_INST_PREFETCH))18279 .addImm(2); // prefetch 1 line behind PC18280 }18281 18282 return CacheLineAlign;18283}18284 18285[[maybe_unused]]18286static bool isCopyFromRegOfInlineAsm(const SDNode *N) {18287 assert(N->getOpcode() == ISD::CopyFromReg);18288 do {18289 // Follow the chain until we find an INLINEASM node.18290 N = N->getOperand(0).getNode();18291 if (N->getOpcode() == ISD::INLINEASM || N->getOpcode() == ISD::INLINEASM_BR)18292 return true;18293 } while (N->getOpcode() == ISD::CopyFromReg);18294 return false;18295}18296 18297bool SITargetLowering::isSDNodeSourceOfDivergence(const SDNode *N,18298 FunctionLoweringInfo *FLI,18299 UniformityInfo *UA) const {18300 switch (N->getOpcode()) {18301 case ISD::CopyFromReg: {18302 const RegisterSDNode *R = cast<RegisterSDNode>(N->getOperand(1));18303 const MachineRegisterInfo &MRI = FLI->MF->getRegInfo();18304 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();18305 Register Reg = R->getReg();18306 18307 // FIXME: Why does this need to consider isLiveIn?18308 if (Reg.isPhysical() || MRI.isLiveIn(Reg))18309 return !TRI->isSGPRReg(MRI, Reg);18310 18311 if (const Value *V = FLI->getValueFromVirtualReg(R->getReg()))18312 return UA->isDivergent(V);18313 18314 assert(Reg == FLI->DemoteRegister || isCopyFromRegOfInlineAsm(N));18315 return !TRI->isSGPRReg(MRI, Reg);18316 }18317 case ISD::LOAD: {18318 const LoadSDNode *L = cast<LoadSDNode>(N);18319 unsigned AS = L->getAddressSpace();18320 // A flat load may access private memory.18321 return AS == AMDGPUAS::PRIVATE_ADDRESS || AS == AMDGPUAS::FLAT_ADDRESS;18322 }18323 case ISD::CALLSEQ_END:18324 return true;18325 case ISD::INTRINSIC_WO_CHAIN:18326 return AMDGPU::isIntrinsicSourceOfDivergence(N->getConstantOperandVal(0));18327 case ISD::INTRINSIC_W_CHAIN:18328 return AMDGPU::isIntrinsicSourceOfDivergence(N->getConstantOperandVal(1));18329 case AMDGPUISD::ATOMIC_CMP_SWAP:18330 case AMDGPUISD::BUFFER_ATOMIC_SWAP:18331 case AMDGPUISD::BUFFER_ATOMIC_ADD:18332 case AMDGPUISD::BUFFER_ATOMIC_SUB:18333 case AMDGPUISD::BUFFER_ATOMIC_SMIN:18334 case AMDGPUISD::BUFFER_ATOMIC_UMIN:18335 case AMDGPUISD::BUFFER_ATOMIC_SMAX:18336 case AMDGPUISD::BUFFER_ATOMIC_UMAX:18337 case AMDGPUISD::BUFFER_ATOMIC_AND:18338 case AMDGPUISD::BUFFER_ATOMIC_OR:18339 case AMDGPUISD::BUFFER_ATOMIC_XOR:18340 case AMDGPUISD::BUFFER_ATOMIC_INC:18341 case AMDGPUISD::BUFFER_ATOMIC_DEC:18342 case AMDGPUISD::BUFFER_ATOMIC_CMPSWAP:18343 case AMDGPUISD::BUFFER_ATOMIC_CSUB:18344 case AMDGPUISD::BUFFER_ATOMIC_FADD:18345 case AMDGPUISD::BUFFER_ATOMIC_FMIN:18346 case AMDGPUISD::BUFFER_ATOMIC_FMAX:18347 // Target-specific read-modify-write atomics are sources of divergence.18348 return true;18349 default:18350 if (auto *A = dyn_cast<AtomicSDNode>(N)) {18351 // Generic read-modify-write atomics are sources of divergence.18352 return A->readMem() && A->writeMem();18353 }18354 return false;18355 }18356}18357 18358bool SITargetLowering::denormalsEnabledForType(const SelectionDAG &DAG,18359 EVT VT) const {18360 switch (VT.getScalarType().getSimpleVT().SimpleTy) {18361 case MVT::f32:18362 return !denormalModeIsFlushAllF32(DAG.getMachineFunction());18363 case MVT::f64:18364 case MVT::f16:18365 return !denormalModeIsFlushAllF64F16(DAG.getMachineFunction());18366 default:18367 return false;18368 }18369}18370 18371bool SITargetLowering::denormalsEnabledForType(18372 LLT Ty, const MachineFunction &MF) const {18373 switch (Ty.getScalarSizeInBits()) {18374 case 32:18375 return !denormalModeIsFlushAllF32(MF);18376 case 64:18377 case 16:18378 return !denormalModeIsFlushAllF64F16(MF);18379 default:18380 return false;18381 }18382}18383 18384bool SITargetLowering::isKnownNeverNaNForTargetNode(SDValue Op,18385 const APInt &DemandedElts,18386 const SelectionDAG &DAG,18387 bool SNaN,18388 unsigned Depth) const {18389 if (Op.getOpcode() == AMDGPUISD::CLAMP) {18390 const MachineFunction &MF = DAG.getMachineFunction();18391 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();18392 18393 if (Info->getMode().DX10Clamp)18394 return true; // Clamped to 0.18395 return DAG.isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1);18396 }18397 18398 return AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(Op, DemandedElts,18399 DAG, SNaN, Depth);18400}18401 18402// On older subtargets, global FP atomic instructions have a hardcoded FP mode18403// and do not support FP32 denormals, and only support v2f16/f64 denormals.18404static bool atomicIgnoresDenormalModeOrFPModeIsFTZ(const AtomicRMWInst *RMW) {18405 if (RMW->hasMetadata("amdgpu.ignore.denormal.mode"))18406 return true;18407 18408 const fltSemantics &Flt = RMW->getType()->getScalarType()->getFltSemantics();18409 auto DenormMode = RMW->getFunction()->getDenormalMode(Flt);18410 if (DenormMode == DenormalMode::getPreserveSign())18411 return true;18412 18413 // TODO: Remove this.18414 return RMW->getFunction()18415 ->getFnAttribute("amdgpu-unsafe-fp-atomics")18416 .getValueAsBool();18417}18418 18419static OptimizationRemark emitAtomicRMWLegalRemark(const AtomicRMWInst *RMW) {18420 LLVMContext &Ctx = RMW->getContext();18421 StringRef MemScope =18422 Ctx.getSyncScopeName(RMW->getSyncScopeID()).value_or("system");18423 18424 return OptimizationRemark(DEBUG_TYPE, "Passed", RMW)18425 << "Hardware instruction generated for atomic "18426 << RMW->getOperationName(RMW->getOperation())18427 << " operation at memory scope " << MemScope;18428}18429 18430static bool isV2F16OrV2BF16(Type *Ty) {18431 if (auto *VT = dyn_cast<FixedVectorType>(Ty)) {18432 Type *EltTy = VT->getElementType();18433 return VT->getNumElements() == 2 &&18434 (EltTy->isHalfTy() || EltTy->isBFloatTy());18435 }18436 18437 return false;18438}18439 18440static bool isV2F16(Type *Ty) {18441 FixedVectorType *VT = dyn_cast<FixedVectorType>(Ty);18442 return VT && VT->getNumElements() == 2 && VT->getElementType()->isHalfTy();18443}18444 18445static bool isV2BF16(Type *Ty) {18446 FixedVectorType *VT = dyn_cast<FixedVectorType>(Ty);18447 return VT && VT->getNumElements() == 2 && VT->getElementType()->isBFloatTy();18448}18449 18450/// \return true if atomicrmw integer ops work for the type.18451static bool isAtomicRMWLegalIntTy(Type *Ty) {18452 if (auto *IT = dyn_cast<IntegerType>(Ty)) {18453 unsigned BW = IT->getBitWidth();18454 return BW == 32 || BW == 64;18455 }18456 18457 return false;18458}18459 18460/// \return true if this atomicrmw xchg type can be selected.18461static bool isAtomicRMWLegalXChgTy(const AtomicRMWInst *RMW) {18462 Type *Ty = RMW->getType();18463 if (isAtomicRMWLegalIntTy(Ty))18464 return true;18465 18466 if (PointerType *PT = dyn_cast<PointerType>(Ty)) {18467 const DataLayout &DL = RMW->getFunction()->getParent()->getDataLayout();18468 unsigned BW = DL.getPointerSizeInBits(PT->getAddressSpace());18469 return BW == 32 || BW == 64;18470 }18471 18472 if (Ty->isFloatTy() || Ty->isDoubleTy())18473 return true;18474 18475 if (FixedVectorType *VT = dyn_cast<FixedVectorType>(Ty)) {18476 return VT->getNumElements() == 2 &&18477 VT->getElementType()->getPrimitiveSizeInBits() == 16;18478 }18479 18480 return false;18481}18482 18483/// \returns true if it's valid to emit a native instruction for \p RMW, based18484/// on the properties of the target memory.18485static bool globalMemoryFPAtomicIsLegal(const GCNSubtarget &Subtarget,18486 const AtomicRMWInst *RMW,18487 bool HasSystemScope) {18488 // The remote/fine-grained access logic is different from the integer18489 // atomics. Without AgentScopeFineGrainedRemoteMemoryAtomics support,18490 // fine-grained access does not work, even for a device local allocation.18491 //18492 // With AgentScopeFineGrainedRemoteMemoryAtomics, system scoped device local18493 // allocations work.18494 if (HasSystemScope) {18495 if (Subtarget.supportsAgentScopeFineGrainedRemoteMemoryAtomics() &&18496 RMW->hasMetadata("amdgpu.no.remote.memory"))18497 return true;18498 if (Subtarget.hasEmulatedSystemScopeAtomics())18499 return true;18500 } else if (Subtarget.supportsAgentScopeFineGrainedRemoteMemoryAtomics())18501 return true;18502 18503 return RMW->hasMetadata("amdgpu.no.fine.grained.memory");18504}18505 18506/// \return Action to perform on AtomicRMWInsts for integer operations.18507static TargetLowering::AtomicExpansionKind18508atomicSupportedIfLegalIntType(const AtomicRMWInst *RMW) {18509 return isAtomicRMWLegalIntTy(RMW->getType())18510 ? TargetLowering::AtomicExpansionKind::None18511 : TargetLowering::AtomicExpansionKind::CmpXChg;18512}18513 18514/// Return if a flat address space atomicrmw can access private memory.18515static bool flatInstrMayAccessPrivate(const Instruction *I) {18516 const MDNode *MD = I->getMetadata(LLVMContext::MD_noalias_addrspace);18517 return !MD ||18518 !AMDGPU::hasValueInRangeLikeMetadata(*MD, AMDGPUAS::PRIVATE_ADDRESS);18519}18520 18521static TargetLowering::AtomicExpansionKind18522getPrivateAtomicExpansionKind(const GCNSubtarget &STI) {18523 // For GAS, lower to flat atomic.18524 return STI.hasGloballyAddressableScratch()18525 ? TargetLowering::AtomicExpansionKind::CustomExpand18526 : TargetLowering::AtomicExpansionKind::NotAtomic;18527}18528 18529TargetLowering::AtomicExpansionKind18530SITargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const {18531 unsigned AS = RMW->getPointerAddressSpace();18532 if (AS == AMDGPUAS::PRIVATE_ADDRESS)18533 return getPrivateAtomicExpansionKind(*getSubtarget());18534 18535 // 64-bit flat atomics that dynamically reside in private memory will silently18536 // be dropped.18537 //18538 // Note that we will emit a new copy of the original atomic in the expansion,18539 // which will be incrementally relegalized.18540 const DataLayout &DL = RMW->getFunction()->getDataLayout();18541 if (AS == AMDGPUAS::FLAT_ADDRESS &&18542 DL.getTypeSizeInBits(RMW->getType()) == 64 &&18543 flatInstrMayAccessPrivate(RMW))18544 return AtomicExpansionKind::CustomExpand;18545 18546 auto ReportUnsafeHWInst = [=](TargetLowering::AtomicExpansionKind Kind) {18547 OptimizationRemarkEmitter ORE(RMW->getFunction());18548 ORE.emit([=]() {18549 return emitAtomicRMWLegalRemark(RMW) << " due to an unsafe request.";18550 });18551 return Kind;18552 };18553 18554 auto SSID = RMW->getSyncScopeID();18555 bool HasSystemScope =18556 SSID == SyncScope::System ||18557 SSID == RMW->getContext().getOrInsertSyncScopeID("one-as");18558 18559 auto Op = RMW->getOperation();18560 switch (Op) {18561 case AtomicRMWInst::Xchg:18562 // PCIe supports add and xchg for system atomics.18563 return isAtomicRMWLegalXChgTy(RMW)18564 ? TargetLowering::AtomicExpansionKind::None18565 : TargetLowering::AtomicExpansionKind::CmpXChg;18566 case AtomicRMWInst::Add:18567 // PCIe supports add and xchg for system atomics.18568 return atomicSupportedIfLegalIntType(RMW);18569 case AtomicRMWInst::Sub:18570 case AtomicRMWInst::And:18571 case AtomicRMWInst::Or:18572 case AtomicRMWInst::Xor:18573 case AtomicRMWInst::Max:18574 case AtomicRMWInst::Min:18575 case AtomicRMWInst::UMax:18576 case AtomicRMWInst::UMin:18577 case AtomicRMWInst::UIncWrap:18578 case AtomicRMWInst::UDecWrap: {18579 if (AMDGPU::isFlatGlobalAddrSpace(AS) ||18580 AS == AMDGPUAS::BUFFER_FAT_POINTER) {18581 if (Subtarget->hasEmulatedSystemScopeAtomics())18582 return atomicSupportedIfLegalIntType(RMW);18583 18584 // On most subtargets, for atomicrmw operations other than add/xchg,18585 // whether or not the instructions will behave correctly depends on where18586 // the address physically resides and what interconnect is used in the18587 // system configuration. On some some targets the instruction will nop,18588 // and in others synchronization will only occur at degraded device scope.18589 //18590 // If the allocation is known local to the device, the instructions should18591 // work correctly.18592 if (RMW->hasMetadata("amdgpu.no.remote.memory"))18593 return atomicSupportedIfLegalIntType(RMW);18594 18595 // If fine-grained remote memory works at device scope, we don't need to18596 // do anything.18597 if (!HasSystemScope &&18598 Subtarget->supportsAgentScopeFineGrainedRemoteMemoryAtomics())18599 return atomicSupportedIfLegalIntType(RMW);18600 18601 // If we are targeting a remote allocated address, it depends what kind of18602 // allocation the address belongs to.18603 //18604 // If the allocation is fine-grained (in host memory, or in PCIe peer18605 // device memory), the operation will fail depending on the target.18606 //18607 // Note fine-grained host memory access does work on APUs or if XGMI is18608 // used, but we do not know if we are targeting an APU or the system18609 // configuration from the ISA version/target-cpu.18610 if (RMW->hasMetadata("amdgpu.no.fine.grained.memory"))18611 return atomicSupportedIfLegalIntType(RMW);18612 18613 if (Op == AtomicRMWInst::Sub || Op == AtomicRMWInst::Or ||18614 Op == AtomicRMWInst::Xor) {18615 // Atomic sub/or/xor do not work over PCI express, but atomic add18616 // does. InstCombine transforms these with 0 to or, so undo that.18617 if (Constant *ConstVal = dyn_cast<Constant>(RMW->getValOperand());18618 ConstVal && ConstVal->isNullValue())18619 return AtomicExpansionKind::CustomExpand;18620 }18621 18622 // If the allocation could be in remote, fine-grained memory, the rmw18623 // instructions may fail. cmpxchg should work, so emit that. On some18624 // system configurations, PCIe atomics aren't supported so cmpxchg won't18625 // even work, so you're out of luck anyway.18626 18627 // In summary:18628 //18629 // Cases that may fail:18630 // - fine-grained pinned host memory18631 // - fine-grained migratable host memory18632 // - fine-grained PCIe peer device18633 //18634 // Cases that should work, but may be treated overly conservatively.18635 // - fine-grained host memory on an APU18636 // - fine-grained XGMI peer device18637 return AtomicExpansionKind::CmpXChg;18638 }18639 18640 return atomicSupportedIfLegalIntType(RMW);18641 }18642 case AtomicRMWInst::FAdd: {18643 Type *Ty = RMW->getType();18644 18645 // TODO: Handle REGION_ADDRESS18646 if (AS == AMDGPUAS::LOCAL_ADDRESS) {18647 // DS F32 FP atomics do respect the denormal mode, but the rounding mode18648 // is fixed to round-to-nearest-even.18649 //18650 // F64 / PK_F16 / PK_BF16 never flush and are also fixed to18651 // round-to-nearest-even.18652 //18653 // We ignore the rounding mode problem, even in strictfp. The C++ standard18654 // suggests it is OK if the floating-point mode may not match the calling18655 // thread.18656 if (Ty->isFloatTy()) {18657 return Subtarget->hasLDSFPAtomicAddF32() ? AtomicExpansionKind::None18658 : AtomicExpansionKind::CmpXChg;18659 }18660 18661 if (Ty->isDoubleTy()) {18662 // Ignores denormal mode, but we don't consider flushing mandatory.18663 return Subtarget->hasLDSFPAtomicAddF64() ? AtomicExpansionKind::None18664 : AtomicExpansionKind::CmpXChg;18665 }18666 18667 if (Subtarget->hasAtomicDsPkAdd16Insts() && isV2F16OrV2BF16(Ty))18668 return AtomicExpansionKind::None;18669 18670 return AtomicExpansionKind::CmpXChg;18671 }18672 18673 // LDS atomics respect the denormal mode from the mode register.18674 //18675 // Traditionally f32 global/buffer memory atomics would unconditionally18676 // flush denormals, but newer targets do not flush. f64/f16/bf16 cases never18677 // flush.18678 //18679 // On targets with flat atomic fadd, denormals would flush depending on18680 // whether the target address resides in LDS or global memory. We consider18681 // this flat-maybe-flush as will-flush.18682 if (Ty->isFloatTy() &&18683 !Subtarget->hasMemoryAtomicFaddF32DenormalSupport() &&18684 !atomicIgnoresDenormalModeOrFPModeIsFTZ(RMW))18685 return AtomicExpansionKind::CmpXChg;18686 18687 // FIXME: These ReportUnsafeHWInsts are imprecise. Some of these cases are18688 // safe. The message phrasing also should be better.18689 if (globalMemoryFPAtomicIsLegal(*Subtarget, RMW, HasSystemScope)) {18690 if (AS == AMDGPUAS::FLAT_ADDRESS) {18691 // gfx942, gfx1218692 if (Subtarget->hasAtomicFlatPkAdd16Insts() && isV2F16OrV2BF16(Ty))18693 return ReportUnsafeHWInst(AtomicExpansionKind::None);18694 } else if (AMDGPU::isExtendedGlobalAddrSpace(AS)) {18695 // gfx90a, gfx942, gfx1218696 if (Subtarget->hasAtomicBufferGlobalPkAddF16Insts() && isV2F16(Ty))18697 return ReportUnsafeHWInst(AtomicExpansionKind::None);18698 18699 // gfx942, gfx1218700 if (Subtarget->hasAtomicGlobalPkAddBF16Inst() && isV2BF16(Ty))18701 return ReportUnsafeHWInst(AtomicExpansionKind::None);18702 } else if (AS == AMDGPUAS::BUFFER_FAT_POINTER) {18703 // gfx90a, gfx942, gfx1218704 if (Subtarget->hasAtomicBufferGlobalPkAddF16Insts() && isV2F16(Ty))18705 return ReportUnsafeHWInst(AtomicExpansionKind::None);18706 18707 // While gfx90a/gfx942 supports v2bf16 for global/flat, it does not for18708 // buffer. gfx12 does have the buffer version.18709 if (Subtarget->hasAtomicBufferPkAddBF16Inst() && isV2BF16(Ty))18710 return ReportUnsafeHWInst(AtomicExpansionKind::None);18711 }18712 18713 // global and flat atomic fadd f64: gfx90a, gfx942.18714 if (Subtarget->hasFlatBufferGlobalAtomicFaddF64Inst() && Ty->isDoubleTy())18715 return ReportUnsafeHWInst(AtomicExpansionKind::None);18716 18717 if (AS != AMDGPUAS::FLAT_ADDRESS) {18718 if (Ty->isFloatTy()) {18719 // global/buffer atomic fadd f32 no-rtn: gfx908, gfx90a, gfx942,18720 // gfx11+.18721 if (RMW->use_empty() && Subtarget->hasAtomicFaddNoRtnInsts())18722 return ReportUnsafeHWInst(AtomicExpansionKind::None);18723 // global/buffer atomic fadd f32 rtn: gfx90a, gfx942, gfx11+.18724 if (!RMW->use_empty() && Subtarget->hasAtomicFaddRtnInsts())18725 return ReportUnsafeHWInst(AtomicExpansionKind::None);18726 } else {18727 // gfx90818728 if (RMW->use_empty() &&18729 Subtarget->hasAtomicBufferGlobalPkAddF16NoRtnInsts() &&18730 isV2F16(Ty))18731 return ReportUnsafeHWInst(AtomicExpansionKind::None);18732 }18733 }18734 18735 // flat atomic fadd f32: gfx942, gfx11+.18736 if (AS == AMDGPUAS::FLAT_ADDRESS && Ty->isFloatTy()) {18737 if (Subtarget->hasFlatAtomicFaddF32Inst())18738 return ReportUnsafeHWInst(AtomicExpansionKind::None);18739 18740 // If it is in flat address space, and the type is float, we will try to18741 // expand it, if the target supports global and lds atomic fadd. The18742 // reason we need that is, in the expansion, we emit the check of18743 // address space. If it is in global address space, we emit the global18744 // atomic fadd; if it is in shared address space, we emit the LDS atomic18745 // fadd.18746 if (Subtarget->hasLDSFPAtomicAddF32()) {18747 if (RMW->use_empty() && Subtarget->hasAtomicFaddNoRtnInsts())18748 return AtomicExpansionKind::CustomExpand;18749 if (!RMW->use_empty() && Subtarget->hasAtomicFaddRtnInsts())18750 return AtomicExpansionKind::CustomExpand;18751 }18752 }18753 }18754 18755 return AtomicExpansionKind::CmpXChg;18756 }18757 case AtomicRMWInst::FMin:18758 case AtomicRMWInst::FMax: {18759 Type *Ty = RMW->getType();18760 18761 // LDS float and double fmin/fmax were always supported.18762 if (AS == AMDGPUAS::LOCAL_ADDRESS) {18763 return Ty->isFloatTy() || Ty->isDoubleTy() ? AtomicExpansionKind::None18764 : AtomicExpansionKind::CmpXChg;18765 }18766 18767 if (globalMemoryFPAtomicIsLegal(*Subtarget, RMW, HasSystemScope)) {18768 // For flat and global cases:18769 // float, double in gfx7. Manual claims denormal support.18770 // Removed in gfx8.18771 // float, double restored in gfx10.18772 // double removed again in gfx11, so only f32 for gfx11/gfx12.18773 //18774 // For gfx9, gfx90a and gfx942 support f64 for global (same as fadd), but18775 // no f32.18776 if (AS == AMDGPUAS::FLAT_ADDRESS) {18777 if (Subtarget->hasAtomicFMinFMaxF32FlatInsts() && Ty->isFloatTy())18778 return ReportUnsafeHWInst(AtomicExpansionKind::None);18779 if (Subtarget->hasAtomicFMinFMaxF64FlatInsts() && Ty->isDoubleTy())18780 return ReportUnsafeHWInst(AtomicExpansionKind::None);18781 } else if (AMDGPU::isExtendedGlobalAddrSpace(AS) ||18782 AS == AMDGPUAS::BUFFER_FAT_POINTER) {18783 if (Subtarget->hasAtomicFMinFMaxF32GlobalInsts() && Ty->isFloatTy())18784 return ReportUnsafeHWInst(AtomicExpansionKind::None);18785 if (Subtarget->hasAtomicFMinFMaxF64GlobalInsts() && Ty->isDoubleTy())18786 return ReportUnsafeHWInst(AtomicExpansionKind::None);18787 }18788 }18789 18790 return AtomicExpansionKind::CmpXChg;18791 }18792 case AtomicRMWInst::Nand:18793 case AtomicRMWInst::FSub:18794 default:18795 return AtomicExpansionKind::CmpXChg;18796 }18797 18798 llvm_unreachable("covered atomicrmw op switch");18799}18800 18801TargetLowering::AtomicExpansionKind18802SITargetLowering::shouldExpandAtomicLoadInIR(LoadInst *LI) const {18803 return LI->getPointerAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS18804 ? getPrivateAtomicExpansionKind(*getSubtarget())18805 : AtomicExpansionKind::None;18806}18807 18808TargetLowering::AtomicExpansionKind18809SITargetLowering::shouldExpandAtomicStoreInIR(StoreInst *SI) const {18810 return SI->getPointerAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS18811 ? getPrivateAtomicExpansionKind(*getSubtarget())18812 : AtomicExpansionKind::None;18813}18814 18815TargetLowering::AtomicExpansionKind18816SITargetLowering::shouldExpandAtomicCmpXchgInIR(AtomicCmpXchgInst *CmpX) const {18817 unsigned AddrSpace = CmpX->getPointerAddressSpace();18818 if (AddrSpace == AMDGPUAS::PRIVATE_ADDRESS)18819 return getPrivateAtomicExpansionKind(*getSubtarget());18820 18821 if (AddrSpace != AMDGPUAS::FLAT_ADDRESS || !flatInstrMayAccessPrivate(CmpX))18822 return AtomicExpansionKind::None;18823 18824 const DataLayout &DL = CmpX->getDataLayout();18825 18826 Type *ValTy = CmpX->getNewValOperand()->getType();18827 18828 // If a 64-bit flat atomic may alias private, we need to avoid using the18829 // atomic in the private case.18830 return DL.getTypeSizeInBits(ValTy) == 64 ? AtomicExpansionKind::CustomExpand18831 : AtomicExpansionKind::None;18832}18833 18834const TargetRegisterClass *18835SITargetLowering::getRegClassFor(MVT VT, bool isDivergent) const {18836 const TargetRegisterClass *RC = TargetLoweringBase::getRegClassFor(VT, false);18837 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();18838 if (RC == &AMDGPU::VReg_1RegClass && !isDivergent)18839 return Subtarget->isWave64() ? &AMDGPU::SReg_64RegClass18840 : &AMDGPU::SReg_32RegClass;18841 if (!TRI->isSGPRClass(RC) && !isDivergent)18842 return TRI->getEquivalentSGPRClass(RC);18843 if (TRI->isSGPRClass(RC) && isDivergent) {18844 if (Subtarget->hasGFX90AInsts())18845 return TRI->getEquivalentAVClass(RC);18846 return TRI->getEquivalentVGPRClass(RC);18847 }18848 18849 return RC;18850}18851 18852// FIXME: This is a workaround for DivergenceAnalysis not understanding always18853// uniform values (as produced by the mask results of control flow intrinsics)18854// used outside of divergent blocks. The phi users need to also be treated as18855// always uniform.18856//18857// FIXME: DA is no longer in-use. Does this still apply to UniformityAnalysis?18858static bool hasCFUser(const Value *V, SmallPtrSet<const Value *, 16> &Visited,18859 unsigned WaveSize) {18860 // FIXME: We assume we never cast the mask results of a control flow18861 // intrinsic.18862 // Early exit if the type won't be consistent as a compile time hack.18863 IntegerType *IT = dyn_cast<IntegerType>(V->getType());18864 if (!IT || IT->getBitWidth() != WaveSize)18865 return false;18866 18867 if (!isa<Instruction>(V))18868 return false;18869 if (!Visited.insert(V).second)18870 return false;18871 bool Result = false;18872 for (const auto *U : V->users()) {18873 if (const IntrinsicInst *Intrinsic = dyn_cast<IntrinsicInst>(U)) {18874 if (V == U->getOperand(1)) {18875 switch (Intrinsic->getIntrinsicID()) {18876 default:18877 Result = false;18878 break;18879 case Intrinsic::amdgcn_if_break:18880 case Intrinsic::amdgcn_if:18881 case Intrinsic::amdgcn_else:18882 Result = true;18883 break;18884 }18885 }18886 if (V == U->getOperand(0)) {18887 switch (Intrinsic->getIntrinsicID()) {18888 default:18889 Result = false;18890 break;18891 case Intrinsic::amdgcn_end_cf:18892 case Intrinsic::amdgcn_loop:18893 Result = true;18894 break;18895 }18896 }18897 } else {18898 Result = hasCFUser(U, Visited, WaveSize);18899 }18900 if (Result)18901 break;18902 }18903 return Result;18904}18905 18906bool SITargetLowering::requiresUniformRegister(MachineFunction &MF,18907 const Value *V) const {18908 if (const CallInst *CI = dyn_cast<CallInst>(V)) {18909 if (CI->isInlineAsm()) {18910 // FIXME: This cannot give a correct answer. This should only trigger in18911 // the case where inline asm returns mixed SGPR and VGPR results, used18912 // outside the defining block. We don't have a specific result to18913 // consider, so this assumes if any value is SGPR, the overall register18914 // also needs to be SGPR.18915 const SIRegisterInfo *SIRI = Subtarget->getRegisterInfo();18916 TargetLowering::AsmOperandInfoVector TargetConstraints = ParseConstraints(18917 MF.getDataLayout(), Subtarget->getRegisterInfo(), *CI);18918 for (auto &TC : TargetConstraints) {18919 if (TC.Type == InlineAsm::isOutput) {18920 ComputeConstraintToUse(TC, SDValue());18921 const TargetRegisterClass *RC =18922 getRegForInlineAsmConstraint(SIRI, TC.ConstraintCode,18923 TC.ConstraintVT)18924 .second;18925 if (RC && SIRI->isSGPRClass(RC))18926 return true;18927 }18928 }18929 }18930 }18931 SmallPtrSet<const Value *, 16> Visited;18932 return hasCFUser(V, Visited, Subtarget->getWavefrontSize());18933}18934 18935bool SITargetLowering::hasMemSDNodeUser(SDNode *N) const {18936 for (SDUse &Use : N->uses()) {18937 if (MemSDNode *M = dyn_cast<MemSDNode>(Use.getUser())) {18938 if (getBasePtrIndex(M) == Use.getOperandNo())18939 return true;18940 }18941 }18942 return false;18943}18944 18945bool SITargetLowering::isReassocProfitable(SelectionDAG &DAG, SDValue N0,18946 SDValue N1) const {18947 if (!N0.hasOneUse())18948 return false;18949 // Take care of the opportunity to keep N0 uniform18950 if (N0->isDivergent() || !N1->isDivergent())18951 return true;18952 // Check if we have a good chance to form the memory access pattern with the18953 // base and offset18954 return (DAG.isBaseWithConstantOffset(N0) &&18955 hasMemSDNodeUser(*N0->user_begin()));18956}18957 18958bool SITargetLowering::isReassocProfitable(MachineRegisterInfo &MRI,18959 Register N0, Register N1) const {18960 return MRI.hasOneNonDBGUse(N0); // FIXME: handle regbanks18961}18962 18963MachineMemOperand::Flags18964SITargetLowering::getTargetMMOFlags(const Instruction &I) const {18965 // Propagate metadata set by AMDGPUAnnotateUniformValues to the MMO of a load.18966 MachineMemOperand::Flags Flags = MachineMemOperand::MONone;18967 if (I.getMetadata("amdgpu.noclobber"))18968 Flags |= MONoClobber;18969 if (I.getMetadata("amdgpu.last.use"))18970 Flags |= MOLastUse;18971 return Flags;18972}18973 18974void SITargetLowering::emitExpandAtomicAddrSpacePredicate(18975 Instruction *AI) const {18976 // Given: atomicrmw fadd ptr %addr, float %val ordering18977 //18978 // With this expansion we produce the following code:18979 // [...]18980 // %is.shared = call i1 @llvm.amdgcn.is.shared(ptr %addr)18981 // br i1 %is.shared, label %atomicrmw.shared, label %atomicrmw.check.private18982 //18983 // atomicrmw.shared:18984 // %cast.shared = addrspacecast ptr %addr to ptr addrspace(3)18985 // %loaded.shared = atomicrmw fadd ptr addrspace(3) %cast.shared,18986 // float %val ordering18987 // br label %atomicrmw.phi18988 //18989 // atomicrmw.check.private:18990 // %is.private = call i1 @llvm.amdgcn.is.private(ptr %int8ptr)18991 // br i1 %is.private, label %atomicrmw.private, label %atomicrmw.global18992 //18993 // atomicrmw.private:18994 // %cast.private = addrspacecast ptr %addr to ptr addrspace(5)18995 // %loaded.private = load float, ptr addrspace(5) %cast.private18996 // %val.new = fadd float %loaded.private, %val18997 // store float %val.new, ptr addrspace(5) %cast.private18998 // br label %atomicrmw.phi18999 //19000 // atomicrmw.global:19001 // %cast.global = addrspacecast ptr %addr to ptr addrspace(1)19002 // %loaded.global = atomicrmw fadd ptr addrspace(1) %cast.global,19003 // float %val ordering19004 // br label %atomicrmw.phi19005 //19006 // atomicrmw.phi:19007 // %loaded.phi = phi float [ %loaded.shared, %atomicrmw.shared ],19008 // [ %loaded.private, %atomicrmw.private ],19009 // [ %loaded.global, %atomicrmw.global ]19010 // br label %atomicrmw.end19011 //19012 // atomicrmw.end:19013 // [...]19014 //19015 //19016 // For 64-bit atomics which may reside in private memory, we perform a simpler19017 // version that only inserts the private check, and uses the flat operation.19018 19019 IRBuilder<> Builder(AI);19020 LLVMContext &Ctx = Builder.getContext();19021 19022 auto *RMW = dyn_cast<AtomicRMWInst>(AI);19023 const unsigned PtrOpIdx = RMW ? AtomicRMWInst::getPointerOperandIndex()19024 : AtomicCmpXchgInst::getPointerOperandIndex();19025 Value *Addr = AI->getOperand(PtrOpIdx);19026 19027 /// TODO: Only need to check private, then emit flat-known-not private (no19028 /// need for shared block, or cast to global).19029 AtomicCmpXchgInst *CX = dyn_cast<AtomicCmpXchgInst>(AI);19030 19031 Align Alignment;19032 if (RMW)19033 Alignment = RMW->getAlign();19034 else if (CX)19035 Alignment = CX->getAlign();19036 else19037 llvm_unreachable("unhandled atomic operation");19038 19039 // FullFlatEmulation is true if we need to issue the private, shared, and19040 // global cases.19041 //19042 // If this is false, we are only dealing with the flat-targeting-private case,19043 // where we only insert a check for private and still use the flat instruction19044 // for global and shared.19045 19046 bool FullFlatEmulation =19047 RMW && RMW->getOperation() == AtomicRMWInst::FAdd &&19048 ((Subtarget->hasAtomicFaddInsts() && RMW->getType()->isFloatTy()) ||19049 (Subtarget->hasFlatBufferGlobalAtomicFaddF64Inst() &&19050 RMW->getType()->isDoubleTy()));19051 19052 // If the return value isn't used, do not introduce a false use in the phi.19053 bool ReturnValueIsUsed = !AI->use_empty();19054 19055 BasicBlock *BB = Builder.GetInsertBlock();19056 Function *F = BB->getParent();19057 BasicBlock *ExitBB =19058 BB->splitBasicBlock(Builder.GetInsertPoint(), "atomicrmw.end");19059 BasicBlock *SharedBB = nullptr;19060 19061 BasicBlock *CheckPrivateBB = BB;19062 if (FullFlatEmulation) {19063 SharedBB = BasicBlock::Create(Ctx, "atomicrmw.shared", F, ExitBB);19064 CheckPrivateBB =19065 BasicBlock::Create(Ctx, "atomicrmw.check.private", F, ExitBB);19066 }19067 19068 BasicBlock *PrivateBB =19069 BasicBlock::Create(Ctx, "atomicrmw.private", F, ExitBB);19070 BasicBlock *GlobalBB = BasicBlock::Create(Ctx, "atomicrmw.global", F, ExitBB);19071 BasicBlock *PhiBB = BasicBlock::Create(Ctx, "atomicrmw.phi", F, ExitBB);19072 19073 std::prev(BB->end())->eraseFromParent();19074 Builder.SetInsertPoint(BB);19075 19076 Value *LoadedShared = nullptr;19077 if (FullFlatEmulation) {19078 CallInst *IsShared = Builder.CreateIntrinsic(Intrinsic::amdgcn_is_shared,19079 {Addr}, nullptr, "is.shared");19080 Builder.CreateCondBr(IsShared, SharedBB, CheckPrivateBB);19081 Builder.SetInsertPoint(SharedBB);19082 Value *CastToLocal = Builder.CreateAddrSpaceCast(19083 Addr, PointerType::get(Ctx, AMDGPUAS::LOCAL_ADDRESS));19084 19085 Instruction *Clone = AI->clone();19086 Clone->insertInto(SharedBB, SharedBB->end());19087 Clone->getOperandUse(PtrOpIdx).set(CastToLocal);19088 LoadedShared = Clone;19089 19090 Builder.CreateBr(PhiBB);19091 Builder.SetInsertPoint(CheckPrivateBB);19092 }19093 19094 CallInst *IsPrivate = Builder.CreateIntrinsic(Intrinsic::amdgcn_is_private,19095 {Addr}, nullptr, "is.private");19096 Builder.CreateCondBr(IsPrivate, PrivateBB, GlobalBB);19097 19098 Builder.SetInsertPoint(PrivateBB);19099 19100 Value *CastToPrivate = Builder.CreateAddrSpaceCast(19101 Addr, PointerType::get(Ctx, AMDGPUAS::PRIVATE_ADDRESS));19102 19103 Value *LoadedPrivate;19104 if (RMW) {19105 LoadedPrivate = Builder.CreateAlignedLoad(19106 RMW->getType(), CastToPrivate, RMW->getAlign(), "loaded.private");19107 19108 Value *NewVal = buildAtomicRMWValue(RMW->getOperation(), Builder,19109 LoadedPrivate, RMW->getValOperand());19110 19111 Builder.CreateAlignedStore(NewVal, CastToPrivate, RMW->getAlign());19112 } else {19113 auto [ResultLoad, Equal] =19114 buildCmpXchgValue(Builder, CastToPrivate, CX->getCompareOperand(),19115 CX->getNewValOperand(), CX->getAlign());19116 19117 Value *Insert = Builder.CreateInsertValue(PoisonValue::get(CX->getType()),19118 ResultLoad, 0);19119 LoadedPrivate = Builder.CreateInsertValue(Insert, Equal, 1);19120 }19121 19122 Builder.CreateBr(PhiBB);19123 19124 Builder.SetInsertPoint(GlobalBB);19125 19126 // Continue using a flat instruction if we only emitted the check for private.19127 Instruction *LoadedGlobal = AI;19128 if (FullFlatEmulation) {19129 Value *CastToGlobal = Builder.CreateAddrSpaceCast(19130 Addr, PointerType::get(Ctx, AMDGPUAS::GLOBAL_ADDRESS));19131 AI->getOperandUse(PtrOpIdx).set(CastToGlobal);19132 }19133 19134 AI->removeFromParent();19135 AI->insertInto(GlobalBB, GlobalBB->end());19136 19137 // The new atomicrmw may go through another round of legalization later.19138 if (!FullFlatEmulation) {19139 // We inserted the runtime check already, make sure we do not try to19140 // re-expand this.19141 // TODO: Should union with any existing metadata.19142 MDBuilder MDB(F->getContext());19143 MDNode *RangeNotPrivate =19144 MDB.createRange(APInt(32, AMDGPUAS::PRIVATE_ADDRESS),19145 APInt(32, AMDGPUAS::PRIVATE_ADDRESS + 1));19146 LoadedGlobal->setMetadata(LLVMContext::MD_noalias_addrspace,19147 RangeNotPrivate);19148 }19149 19150 Builder.CreateBr(PhiBB);19151 19152 Builder.SetInsertPoint(PhiBB);19153 19154 if (ReturnValueIsUsed) {19155 PHINode *Loaded = Builder.CreatePHI(AI->getType(), 3);19156 AI->replaceAllUsesWith(Loaded);19157 if (FullFlatEmulation)19158 Loaded->addIncoming(LoadedShared, SharedBB);19159 Loaded->addIncoming(LoadedPrivate, PrivateBB);19160 Loaded->addIncoming(LoadedGlobal, GlobalBB);19161 Loaded->takeName(AI);19162 }19163 19164 Builder.CreateBr(ExitBB);19165}19166 19167static void convertScratchAtomicToFlatAtomic(Instruction *I,19168 unsigned PtrOpIdx) {19169 Value *PtrOp = I->getOperand(PtrOpIdx);19170 assert(PtrOp->getType()->getPointerAddressSpace() ==19171 AMDGPUAS::PRIVATE_ADDRESS);19172 19173 Type *FlatPtr = PointerType::get(I->getContext(), AMDGPUAS::FLAT_ADDRESS);19174 Value *ASCast = CastInst::CreatePointerCast(PtrOp, FlatPtr, "scratch.ascast",19175 I->getIterator());19176 I->setOperand(PtrOpIdx, ASCast);19177}19178 19179void SITargetLowering::emitExpandAtomicRMW(AtomicRMWInst *AI) const {19180 AtomicRMWInst::BinOp Op = AI->getOperation();19181 19182 if (AI->getPointerAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS)19183 return convertScratchAtomicToFlatAtomic(AI, AI->getPointerOperandIndex());19184 19185 if (Op == AtomicRMWInst::Sub || Op == AtomicRMWInst::Or ||19186 Op == AtomicRMWInst::Xor) {19187 if (const auto *ConstVal = dyn_cast<Constant>(AI->getValOperand());19188 ConstVal && ConstVal->isNullValue()) {19189 // atomicrmw or %ptr, 0 -> atomicrmw add %ptr, 019190 AI->setOperation(AtomicRMWInst::Add);19191 19192 // We may still need the private-alias-flat handling below.19193 19194 // TODO: Skip this for cases where we cannot access remote memory.19195 }19196 }19197 19198 // The non-flat expansions should only perform the de-canonicalization of19199 // identity values.19200 if (AI->getPointerAddressSpace() != AMDGPUAS::FLAT_ADDRESS)19201 return;19202 19203 emitExpandAtomicAddrSpacePredicate(AI);19204}19205 19206void SITargetLowering::emitExpandAtomicCmpXchg(AtomicCmpXchgInst *CI) const {19207 if (CI->getPointerAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS)19208 return convertScratchAtomicToFlatAtomic(CI, CI->getPointerOperandIndex());19209 19210 emitExpandAtomicAddrSpacePredicate(CI);19211}19212 19213void SITargetLowering::emitExpandAtomicLoad(LoadInst *LI) const {19214 if (LI->getPointerAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS)19215 return convertScratchAtomicToFlatAtomic(LI, LI->getPointerOperandIndex());19216 19217 llvm_unreachable(19218 "Expand Atomic Load only handles SCRATCH -> FLAT conversion");19219}19220 19221void SITargetLowering::emitExpandAtomicStore(StoreInst *SI) const {19222 if (SI->getPointerAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS)19223 return convertScratchAtomicToFlatAtomic(SI, SI->getPointerOperandIndex());19224 19225 llvm_unreachable(19226 "Expand Atomic Store only handles SCRATCH -> FLAT conversion");19227}19228 19229LoadInst *19230SITargetLowering::lowerIdempotentRMWIntoFencedLoad(AtomicRMWInst *AI) const {19231 IRBuilder<> Builder(AI);19232 auto Order = AI->getOrdering();19233 19234 // The optimization removes store aspect of the atomicrmw. Therefore, cache19235 // must be flushed if the atomic ordering had a release semantics. This is19236 // not necessary a fence, a release fence just coincides to do that flush.19237 // Avoid replacing of an atomicrmw with a release semantics.19238 if (isReleaseOrStronger(Order))19239 return nullptr;19240 19241 LoadInst *LI = Builder.CreateAlignedLoad(19242 AI->getType(), AI->getPointerOperand(), AI->getAlign());19243 LI->setAtomic(Order, AI->getSyncScopeID());19244 LI->copyMetadata(*AI);19245 LI->takeName(AI);19246 AI->replaceAllUsesWith(LI);19247 AI->eraseFromParent();19248 return LI;19249}19250