mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-11-06 20:18:14 +00:00
R600/SI: Enable selecting SALU inside branches
We can do this now that the FixSGPRLiveRanges pass is working. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218353 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -79,11 +79,6 @@ private:
|
|||||||
bool isLocalLoad(const LoadSDNode *N) const;
|
bool isLocalLoad(const LoadSDNode *N) const;
|
||||||
bool isRegionLoad(const LoadSDNode *N) const;
|
bool isRegionLoad(const LoadSDNode *N) const;
|
||||||
|
|
||||||
/// \returns True if the current basic block being selected is at control
|
|
||||||
/// flow depth 0. Meaning that the current block dominates the
|
|
||||||
// exit block.
|
|
||||||
bool isCFDepth0() const;
|
|
||||||
|
|
||||||
const TargetRegisterClass *getOperandRegClass(SDNode *N, unsigned OpNo) const;
|
const TargetRegisterClass *getOperandRegClass(SDNode *N, unsigned OpNo) const;
|
||||||
bool SelectGlobalValueConstantOffset(SDValue Addr, SDValue& IntPtr);
|
bool SelectGlobalValueConstantOffset(SDValue Addr, SDValue& IntPtr);
|
||||||
bool SelectGlobalValueVariableOffset(SDValue Addr, SDValue &BaseReg,
|
bool SelectGlobalValueVariableOffset(SDValue Addr, SDValue &BaseReg,
|
||||||
@@ -605,14 +600,6 @@ bool AMDGPUDAGToDAGISel::isPrivateLoad(const LoadSDNode *N) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AMDGPUDAGToDAGISel::isCFDepth0() const {
|
|
||||||
// FIXME: Figure out a way to use DominatorTree analysis here.
|
|
||||||
const BasicBlock *CurBlock = FuncInfo->MBB->getBasicBlock();
|
|
||||||
const Function *Fn = FuncInfo->Fn;
|
|
||||||
return &Fn->front() == CurBlock || &Fn->back() == CurBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *AMDGPUDAGToDAGISel::getPassName() const {
|
const char *AMDGPUDAGToDAGISel::getPassName() const {
|
||||||
return "AMDGPU DAG->DAG Pattern Instruction Selection";
|
return "AMDGPU DAG->DAG Pattern Instruction Selection";
|
||||||
}
|
}
|
||||||
@@ -718,11 +705,6 @@ SDNode *AMDGPUDAGToDAGISel::SelectADD_SUB_I64(SDNode *N) {
|
|||||||
unsigned Opc = IsAdd ? AMDGPU::S_ADD_U32 : AMDGPU::S_SUB_U32;
|
unsigned Opc = IsAdd ? AMDGPU::S_ADD_U32 : AMDGPU::S_SUB_U32;
|
||||||
unsigned CarryOpc = IsAdd ? AMDGPU::S_ADDC_U32 : AMDGPU::S_SUBB_U32;
|
unsigned CarryOpc = IsAdd ? AMDGPU::S_ADDC_U32 : AMDGPU::S_SUBB_U32;
|
||||||
|
|
||||||
if (!isCFDepth0()) {
|
|
||||||
Opc = IsAdd ? AMDGPU::V_ADD_I32_e32 : AMDGPU::V_SUB_I32_e32;
|
|
||||||
CarryOpc = IsAdd ? AMDGPU::V_ADDC_U32_e32 : AMDGPU::V_SUBB_U32_e32;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDNode *AddLo = CurDAG->getMachineNode( Opc, DL, VTList, AddLoArgs);
|
SDNode *AddLo = CurDAG->getMachineNode( Opc, DL, VTList, AddLoArgs);
|
||||||
SDValue Carry(AddLo, 1);
|
SDValue Carry(AddLo, 1);
|
||||||
SDNode *AddHi
|
SDNode *AddHi
|
||||||
|
|||||||
@@ -33,12 +33,9 @@ def isCI : Predicate<"Subtarget.getGeneration() "
|
|||||||
">= AMDGPUSubtarget::SEA_ISLANDS">;
|
">= AMDGPUSubtarget::SEA_ISLANDS">;
|
||||||
def HasFlatAddressSpace : Predicate<"Subtarget.hasFlatAddressSpace()">;
|
def HasFlatAddressSpace : Predicate<"Subtarget.hasFlatAddressSpace()">;
|
||||||
|
|
||||||
def isCFDepth0 : Predicate<"isCFDepth0()">;
|
|
||||||
|
|
||||||
def WAIT_FLAG : InstFlag<"printWaitFlag">;
|
def WAIT_FLAG : InstFlag<"printWaitFlag">;
|
||||||
|
|
||||||
let SubtargetPredicate = isSI in {
|
let SubtargetPredicate = isSI in {
|
||||||
let OtherPredicates = [isCFDepth0] in {
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// SMRD Instructions
|
// SMRD Instructions
|
||||||
@@ -365,8 +362,6 @@ def S_GETREG_REGRD_B32 : SOPK_32 <0x00000014, "S_GETREG_REGRD_B32", []>;
|
|||||||
//def S_SETREG_IMM32_B32 : SOPK_32 <0x00000015, "S_SETREG_IMM32_B32", []>;
|
//def S_SETREG_IMM32_B32 : SOPK_32 <0x00000015, "S_SETREG_IMM32_B32", []>;
|
||||||
//def EXP : EXP_ <0x00000000, "EXP", []>;
|
//def EXP : EXP_ <0x00000000, "EXP", []>;
|
||||||
|
|
||||||
} // End let OtherPredicates = [isCFDepth0]
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// SOPP Instructions
|
// SOPP Instructions
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@@ -1944,8 +1939,6 @@ def : Pat <
|
|||||||
// SOP1 Patterns
|
// SOP1 Patterns
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
let Predicates = [isSI, isCFDepth0] in {
|
|
||||||
|
|
||||||
def : Pat <
|
def : Pat <
|
||||||
(i64 (ctpop i64:$src)),
|
(i64 (ctpop i64:$src)),
|
||||||
(INSERT_SUBREG (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
|
(INSERT_SUBREG (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
|
||||||
@@ -1964,8 +1957,6 @@ def : Pat <
|
|||||||
(S_ADD_U32 $src0, $src1)
|
(S_ADD_U32 $src0, $src1)
|
||||||
>;
|
>;
|
||||||
|
|
||||||
} // Predicates = [isSI, isCFDepth0]
|
|
||||||
|
|
||||||
let Predicates = [isSI] in {
|
let Predicates = [isSI] in {
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|||||||
@@ -141,12 +141,10 @@ entry:
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Test i64 add inside a branch. We don't allow SALU instructions inside of
|
; Test i64 add inside a branch.
|
||||||
; branches.
|
|
||||||
; FIXME: We are being conservative here. We could allow this in some cases.
|
|
||||||
; FUNC-LABEL: @add64_in_branch
|
; FUNC-LABEL: @add64_in_branch
|
||||||
; SI-CHECK-NOT: S_ADD_I32
|
; SI-CHECK: S_ADD_U32
|
||||||
; SI-CHECK-NOT: S_ADDC_U32
|
; SI-CHECK: S_ADDC_U32
|
||||||
define void @add64_in_branch(i64 addrspace(1)* %out, i64 addrspace(1)* %in, i64 %a, i64 %b, i64 %c) {
|
define void @add64_in_branch(i64 addrspace(1)* %out, i64 addrspace(1)* %in, i64 %a, i64 %b, i64 %c) {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i64 %a, 0
|
%0 = icmp eq i64 %a, 0
|
||||||
|
|||||||
@@ -270,28 +270,28 @@ define void @v_ctpop_i32_add_vvar_inv(i32 addrspace(1)* noalias %out, i32 addrsp
|
|||||||
; but there are some cases when the should be allowed.
|
; but there are some cases when the should be allowed.
|
||||||
|
|
||||||
; FUNC-LABEL: @ctpop_i32_in_br
|
; FUNC-LABEL: @ctpop_i32_in_br
|
||||||
; SI: BUFFER_LOAD_DWORD [[VAL:v[0-9]+]],
|
; SI: S_LOAD_DWORD [[VAL:s[0-9]+]], s[{{[0-9]+:[0-9]+}}], 0xd
|
||||||
; SI: V_BCNT_U32_B32_e64 [[RESULT:v[0-9]+]], [[VAL]], 0
|
; SI: S_BCNT1_I32_B32 [[SRESULT:s[0-9]+]], [[VAL]]
|
||||||
|
; SI: V_MOV_B32_e32 [[RESULT]], [[SRESULT]]
|
||||||
; SI: BUFFER_STORE_DWORD [[RESULT]],
|
; SI: BUFFER_STORE_DWORD [[RESULT]],
|
||||||
; SI: S_ENDPGM
|
; SI: S_ENDPGM
|
||||||
; EG: BCNT_INT
|
; EG: BCNT_INT
|
||||||
define void @ctpop_i32_in_br(i32 addrspace(1)* %out, i32 addrspace(1)* %in, i32 %cond) {
|
define void @ctpop_i32_in_br(i32 addrspace(1)* %out, i32 addrspace(1)* %in, i32 %ctpop_arg, i32 %cond) {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i32 %cond, 0
|
%tmp0 = icmp eq i32 %cond, 0
|
||||||
br i1 %0, label %if, label %else
|
br i1 %tmp0, label %if, label %else
|
||||||
|
|
||||||
if:
|
if:
|
||||||
%1 = load i32 addrspace(1)* %in
|
%tmp2 = call i32 @llvm.ctpop.i32(i32 %ctpop_arg)
|
||||||
%2 = call i32 @llvm.ctpop.i32(i32 %1)
|
|
||||||
br label %endif
|
br label %endif
|
||||||
|
|
||||||
else:
|
else:
|
||||||
%3 = getelementptr i32 addrspace(1)* %in, i32 1
|
%tmp3 = getelementptr i32 addrspace(1)* %in, i32 1
|
||||||
%4 = load i32 addrspace(1)* %3
|
%tmp4 = load i32 addrspace(1)* %tmp3
|
||||||
br label %endif
|
br label %endif
|
||||||
|
|
||||||
endif:
|
endif:
|
||||||
%5 = phi i32 [%2, %if], [%4, %else]
|
%tmp5 = phi i32 [%tmp2, %if], [%tmp4, %else]
|
||||||
store i32 %5, i32 addrspace(1)* %out
|
store i32 %tmp5, i32 addrspace(1)* %out
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,29 +94,28 @@ define void @v_ctpop_v4i64(<4 x i32> addrspace(1)* noalias %out, <4 x i64> addrs
|
|||||||
; but there are some cases when the should be allowed.
|
; but there are some cases when the should be allowed.
|
||||||
|
|
||||||
; FUNC-LABEL: @ctpop_i64_in_br
|
; FUNC-LABEL: @ctpop_i64_in_br
|
||||||
; SI: V_BCNT_U32_B32_e64 [[BCNT_LO:v[0-9]+]], v{{[0-9]+}}, 0
|
; SI: S_LOAD_DWORDX2 s{{\[}}[[LOVAL:[0-9]+]]:[[HIVAL:[0-9]+]]{{\]}}, s[{{[0-9]+:[0-9]+}}], 0xd
|
||||||
; SI: V_BCNT_U32_B32_e32 v[[BCNT:[0-9]+]], v{{[0-9]+}}, [[BCNT_LO]]
|
; SI: S_BCNT1_I32_B64 [[RESULT:s[0-9]+]], {{s\[}}[[LOVAL]]:[[HIVAL]]{{\]}}
|
||||||
; SI: V_MOV_B32_e32 v[[ZERO:[0-9]+]], 0
|
; SI: V_MOV_B32_e32 v[[VLO:[0-9]+]], [[RESULT]]
|
||||||
; SI: BUFFER_STORE_DWORDX2 v[
|
; SI: V_MOV_B32_e32 v[[VHI:[0-9]+]], s[[HIVAL]]
|
||||||
; SI: [[BCNT]]:[[ZERO]]]
|
; SI: BUFFER_STORE_DWORDX2 {{v\[}}[[VLO]]:[[VHI]]{{\]}}
|
||||||
; SI: S_ENDPGM
|
; SI: S_ENDPGM
|
||||||
define void @ctpop_i64_in_br(i64 addrspace(1)* %out, i64 addrspace(1)* %in, i32 %cond) {
|
define void @ctpop_i64_in_br(i64 addrspace(1)* %out, i64 addrspace(1)* %in, i64 %ctpop_arg, i32 %cond) {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i32 %cond, 0
|
%tmp0 = icmp eq i32 %cond, 0
|
||||||
br i1 %0, label %if, label %else
|
br i1 %tmp0, label %if, label %else
|
||||||
|
|
||||||
if:
|
if:
|
||||||
%1 = load i64 addrspace(1)* %in
|
%tmp2 = call i64 @llvm.ctpop.i64(i64 %ctpop_arg)
|
||||||
%2 = call i64 @llvm.ctpop.i64(i64 %1)
|
|
||||||
br label %endif
|
br label %endif
|
||||||
|
|
||||||
else:
|
else:
|
||||||
%3 = getelementptr i64 addrspace(1)* %in, i32 1
|
%tmp3 = getelementptr i64 addrspace(1)* %in, i32 1
|
||||||
%4 = load i64 addrspace(1)* %3
|
%tmp4 = load i64 addrspace(1)* %tmp3
|
||||||
br label %endif
|
br label %endif
|
||||||
|
|
||||||
endif:
|
endif:
|
||||||
%5 = phi i64 [%2, %if], [%4, %else]
|
%tmp5 = phi i64 [%tmp2, %if], [%tmp4, %else]
|
||||||
store i64 %5, i64 addrspace(1)* %out
|
store i64 %tmp5, i64 addrspace(1)* %out
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ define void @v_mul_i64(i64 addrspace(1)* %out, i64 addrspace(1)* %aptr, i64 addr
|
|||||||
}
|
}
|
||||||
|
|
||||||
; FUNC-LABEL: @mul32_in_branch
|
; FUNC-LABEL: @mul32_in_branch
|
||||||
; SI: V_MUL_LO_I32
|
; SI: S_MUL_I32
|
||||||
define void @mul32_in_branch(i32 addrspace(1)* %out, i32 addrspace(1)* %in, i32 %a, i32 %b, i32 %c) {
|
define void @mul32_in_branch(i32 addrspace(1)* %out, i32 addrspace(1)* %in, i32 %a, i32 %b, i32 %c) {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i32 %a, 0
|
%0 = icmp eq i32 %a, 0
|
||||||
@@ -176,7 +176,7 @@ endif:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; FUNC-LABEL: @mul64_in_branch
|
; FUNC-LABEL: @mul64_in_branch
|
||||||
; SI-DAG: V_MUL_LO_I32
|
; SI-DAG: S_MUL_I32
|
||||||
; SI-DAG: V_MUL_HI_U32
|
; SI-DAG: V_MUL_HI_U32
|
||||||
; SI: S_ENDPGM
|
; SI: S_ENDPGM
|
||||||
define void @mul64_in_branch(i64 addrspace(1)* %out, i64 addrspace(1)* %in, i64 %a, i64 %b, i64 %c) {
|
define void @mul64_in_branch(i64 addrspace(1)* %out, i64 addrspace(1)* %in, i64 %a, i64 %b, i64 %c) {
|
||||||
|
|||||||
@@ -4,9 +4,14 @@
|
|||||||
; Most SALU instructions ignore control flow, so we need to make sure
|
; Most SALU instructions ignore control flow, so we need to make sure
|
||||||
; they don't overwrite values from other blocks.
|
; they don't overwrite values from other blocks.
|
||||||
|
|
||||||
; SI-NOT: S_ADD
|
; If the branch decision is made based on a value in an SGPR then all
|
||||||
|
; threads will execute the same code paths, so we don't need to worry
|
||||||
|
; about instructions in different blocks overwriting each other.
|
||||||
|
; SI-LABEL: @sgpr_if_else_salu_br
|
||||||
|
; SI: S_ADD
|
||||||
|
; SI: S_ADD
|
||||||
|
|
||||||
define void @sgpr_if_else(i32 addrspace(1)* %out, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
|
define void @sgpr_if_else_salu_br(i32 addrspace(1)* %out, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i32 %a, 0
|
%0 = icmp eq i32 %a, 0
|
||||||
br i1 %0, label %if, label %else
|
br i1 %0, label %if, label %else
|
||||||
@@ -25,3 +30,35 @@ endif:
|
|||||||
store i32 %4, i32 addrspace(1)* %out
|
store i32 %4, i32 addrspace(1)* %out
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; The two S_ADD instructions should write to different registers, since
|
||||||
|
; different threads will take different control flow paths.
|
||||||
|
|
||||||
|
; SI-LABEL: @sgpr_if_else_valu_br
|
||||||
|
; SI: S_ADD_I32 [[SGPR:s[0-9]+]]
|
||||||
|
; SI-NOT: S_ADD_I32 [[SGPR]]
|
||||||
|
|
||||||
|
define void @sgpr_if_else_valu_br(i32 addrspace(1)* %out, float %a, i32 %b, i32 %c, i32 %d, i32 %e) {
|
||||||
|
entry:
|
||||||
|
%tid = call i32 @llvm.r600.read.tidig.x() #0
|
||||||
|
%tid_f = uitofp i32 %tid to float
|
||||||
|
%tmp1 = fcmp ueq float %tid_f, 0.0
|
||||||
|
br i1 %tmp1, label %if, label %else
|
||||||
|
|
||||||
|
if:
|
||||||
|
%tmp2 = add i32 %b, %c
|
||||||
|
br label %endif
|
||||||
|
|
||||||
|
else:
|
||||||
|
%tmp3 = add i32 %d, %e
|
||||||
|
br label %endif
|
||||||
|
|
||||||
|
endif:
|
||||||
|
%tmp4 = phi i32 [%tmp2, %if], [%tmp3, %else]
|
||||||
|
store i32 %tmp4, i32 addrspace(1)* %out
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i32 @llvm.r600.read.tidig.x() #0
|
||||||
|
|
||||||
|
attributes #0 = { readnone }
|
||||||
|
|||||||
@@ -136,8 +136,7 @@ define void @vector_not_i64(i64 addrspace(1)* %out, i64 addrspace(1)* %in0, i64
|
|||||||
; use an SALU instruction for this.
|
; use an SALU instruction for this.
|
||||||
|
|
||||||
; SI-CHECK-LABEL: @xor_cf
|
; SI-CHECK-LABEL: @xor_cf
|
||||||
; SI-CHECK: V_XOR
|
; SI-CHECK: S_XOR_B64
|
||||||
; SI-CHECK: V_XOR
|
|
||||||
define void @xor_cf(i64 addrspace(1)* %out, i64 addrspace(1)* %in, i64 %a, i64 %b) {
|
define void @xor_cf(i64 addrspace(1)* %out, i64 addrspace(1)* %in, i64 %a, i64 %b) {
|
||||||
entry:
|
entry:
|
||||||
%0 = icmp eq i64 %a, 0
|
%0 = icmp eq i64 %a, 0
|
||||||
|
|||||||
Reference in New Issue
Block a user