forked from OSchip/llvm-project
[TargetLowering] Handle multi depth GEPs w/ inline asm constraints
Summary: X86TargetLowering::LowerAsmOperandForConstraint had better support than TargetLowering::LowerAsmOperandForConstraint for arbitrary depth getelementpointers for "i", "n", and "s" extended inline assembly constraints. Hoist its support from the derived class into the base class. Link: https://github.com/ClangBuiltLinux/linux/issues/469 Reviewers: echristo, t.p.northover Reviewed By: t.p.northover Subscribers: t.p.northover, E5ten, kees, jyknight, nemanjai, javed.absar, eraman, hiraditya, jsji, llvm-commits, void, craig.topper, nathanchance, srhines Tags: #llvm Differential Revision: https://reviews.llvm.org/D61560 llvm-svn: 360604
This commit is contained in:
parent
b38e4b28e3
commit
c33f754e74
|
@ -3542,46 +3542,41 @@ void TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
|
|||
case 'i': // Simple Integer or Relocatable Constant
|
||||
case 'n': // Simple Integer
|
||||
case 's': { // Relocatable Constant
|
||||
// These operands are interested in values of the form (GV+C), where C may
|
||||
// be folded in as an offset of GV, or it may be explicitly added. Also, it
|
||||
// is possible and fine if either GV or C are missing.
|
||||
ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op);
|
||||
GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op);
|
||||
|
||||
// If we have "(add GV, C)", pull out GV/C
|
||||
if (Op.getOpcode() == ISD::ADD) {
|
||||
C = dyn_cast<ConstantSDNode>(Op.getOperand(1));
|
||||
GA = dyn_cast<GlobalAddressSDNode>(Op.getOperand(0));
|
||||
if (!C || !GA) {
|
||||
C = dyn_cast<ConstantSDNode>(Op.getOperand(0));
|
||||
GA = dyn_cast<GlobalAddressSDNode>(Op.getOperand(1));
|
||||
}
|
||||
if (!C || !GA) {
|
||||
C = nullptr;
|
||||
GA = nullptr;
|
||||
}
|
||||
}
|
||||
GlobalAddressSDNode *GA;
|
||||
ConstantSDNode *C;
|
||||
uint64_t Offset = 0;
|
||||
|
||||
// If we find a valid operand, map to the TargetXXX version so that the
|
||||
// value itself doesn't get selected.
|
||||
if (GA) { // Either &GV or &GV+C
|
||||
if (ConstraintLetter != 'n') {
|
||||
int64_t Offs = GA->getOffset();
|
||||
if (C) Offs += C->getZExtValue();
|
||||
Ops.push_back(DAG.getTargetGlobalAddress(GA->getGlobal(),
|
||||
C ? SDLoc(C) : SDLoc(),
|
||||
Op.getValueType(), Offs));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (C) { // just C, no GV.
|
||||
// Simple constants are not allowed for 's'.
|
||||
if (ConstraintLetter != 's') {
|
||||
// gcc prints these as sign extended. Sign extend value to 64 bits
|
||||
// now; without this it would get ZExt'd later in
|
||||
// ScheduleDAGSDNodes::EmitNode, which is very generic.
|
||||
Ops.push_back(DAG.getTargetConstant(C->getSExtValue(),
|
||||
// Match (GA) or (C) or (GA+C) or (GA-C) or ((GA+C)+C) or (((GA+C)+C)+C),
|
||||
// etc., since getelementpointer is variadic. We can't use
|
||||
// SelectionDAG::FoldSymbolOffset because it expects the GA to be accessible
|
||||
// while in this case the GA may be furthest from the root node which is
|
||||
// likely an ISD::ADD.
|
||||
while (1) {
|
||||
if ((GA = dyn_cast<GlobalAddressSDNode>(Op)) && ConstraintLetter != 'n') {
|
||||
Ops.push_back(DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(Op),
|
||||
GA->getValueType(0),
|
||||
Offset + GA->getOffset()));
|
||||
return;
|
||||
} else if ((C = dyn_cast<ConstantSDNode>(Op)) &&
|
||||
ConstraintLetter != 's') {
|
||||
Ops.push_back(DAG.getTargetConstant(Offset + C->getSExtValue(),
|
||||
SDLoc(C), MVT::i64));
|
||||
return;
|
||||
} else {
|
||||
const unsigned OpCode = Op.getOpcode();
|
||||
if (OpCode == ISD::ADD || OpCode == ISD::SUB) {
|
||||
if ((C = dyn_cast<ConstantSDNode>(Op.getOperand(0))))
|
||||
Op = Op.getOperand(1);
|
||||
// Subtraction is not commutative.
|
||||
else if (OpCode == ISD::ADD &&
|
||||
(C = dyn_cast<ConstantSDNode>(Op.getOperand(1))))
|
||||
Op = Op.getOperand(0);
|
||||
else
|
||||
return;
|
||||
Offset += (OpCode == ISD::ADD ? 1 : -1) * C->getSExtValue();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -44027,40 +44027,12 @@ void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
|
|||
|
||||
// If we are in non-pic codegen mode, we allow the address of a global (with
|
||||
// an optional displacement) to be used with 'i'.
|
||||
GlobalAddressSDNode *GA = nullptr;
|
||||
int64_t Offset = 0;
|
||||
|
||||
// Match either (GA), (GA+C), (GA+C1+C2), etc.
|
||||
while (1) {
|
||||
if ((GA = dyn_cast<GlobalAddressSDNode>(Op))) {
|
||||
Offset += GA->getOffset();
|
||||
break;
|
||||
} else if (Op.getOpcode() == ISD::ADD) {
|
||||
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
|
||||
Offset += C->getZExtValue();
|
||||
Op = Op.getOperand(0);
|
||||
continue;
|
||||
}
|
||||
} else if (Op.getOpcode() == ISD::SUB) {
|
||||
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
|
||||
Offset += -C->getZExtValue();
|
||||
Op = Op.getOperand(0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, this isn't something we can handle, reject it.
|
||||
return;
|
||||
}
|
||||
|
||||
const GlobalValue *GV = GA->getGlobal();
|
||||
// If we require an extra load to get this address, as in PIC mode, we
|
||||
// can't accept it.
|
||||
if (isGlobalStubReference(Subtarget.classifyGlobalReference(GV)))
|
||||
return;
|
||||
|
||||
Result = DAG.getTargetGlobalAddress(GV, SDLoc(Op),
|
||||
GA->getValueType(0), Offset);
|
||||
if (auto *GA = dyn_cast<GlobalAddressSDNode>(Op))
|
||||
// If we require an extra load to get this address, as in PIC mode, we
|
||||
// can't accept it.
|
||||
if (isGlobalStubReference(
|
||||
Subtarget.classifyGlobalReference(GA->getGlobal())))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
; RUN: llc < %s -mtriple aarch64-gnu-linux | FileCheck %s
|
||||
|
||||
; @foo is a 2d array of i32s, ex.
|
||||
; i32 foo [2][2]
|
||||
@foo = internal global [2 x [2 x i32]] zeroinitializer, align 4
|
||||
|
||||
define void @bar() {
|
||||
; access foo[1][1]
|
||||
; CHECK: // foo+12
|
||||
tail call void asm sideeffect "// ${0:c}", "i"(i32* getelementptr inbounds ([2 x [2 x i32]], [2 x [2 x i32]]* @foo, i64 0, i64 1, i64 1))
|
||||
ret void
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
; RUN: llc < %s -mtriple armv7-linux-gnueabi | FileCheck %s
|
||||
|
||||
; @foo is a 2d array of i32s, ex.
|
||||
; i32 foo [2][2]
|
||||
@foo = internal global [2 x [2 x i32]] zeroinitializer, align 4
|
||||
|
||||
define void @bar() {
|
||||
; access foo[1][1]
|
||||
; CHECK: @ foo+12
|
||||
tail call void asm sideeffect "@ ${0:c}", "i"(i32* getelementptr inbounds ([2 x [2 x i32]], [2 x [2 x i32]]* @foo, i64 0, i64 1, i64 1))
|
||||
ret void
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
; RUN: llc < %s -mtriple ppc32-- | FileCheck %s
|
||||
|
||||
; @foo is a 2d array of i32s, ex.
|
||||
; i32 foo [2][2]
|
||||
@foo = internal global [2 x [2 x i32]] zeroinitializer, align 4
|
||||
|
||||
define void @bar() {
|
||||
; access foo[1][1]
|
||||
; CHECK: # foo+12
|
||||
tail call void asm sideeffect "# ${0:c}", "i"(i32* getelementptr inbounds ([2 x [2 x i32]], [2 x [2 x i32]]* @foo, i64 0, i64 1, i64 1))
|
||||
ret void
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
; RUN: llc < %s -mtriple x86_64-gnu-linux | FileCheck %s
|
||||
|
||||
; @foo is a 2d array of i32s, ex.
|
||||
; i32 foo [2][2]
|
||||
@foo = internal global [2 x [2 x i32]] zeroinitializer, align 4
|
||||
|
||||
define void @bar() {
|
||||
; access foo[1][1]
|
||||
; CHECK: # foo+12
|
||||
tail call void asm sideeffect "# ${0:c}", "i"(i32* getelementptr inbounds ([2 x [2 x i32]], [2 x [2 x i32]]* @foo, i64 0, i64 1, i64 1))
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue