mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-12 17:32:19 +00:00
Implement a signficant optimization for inline asm:
When choosing between constraints with multiple options, like "ir", test to see if we can use the 'i' constraint and go with that if possible. This produces more optimal ASM in all cases (sparing a register and an instruction to load it), and fixes inline asm like this: void test () { asm volatile (" %c0 %1 " : : "imr" (42), "imr"(14)); } Previously we would dump "42" into a memory location (which is ok for the 'm' constraint) which would cause a problem because the 'c' modifier is not valid on memory operands. Isn't it great how inline asm turns 'missed optimization' into 'compile failed'?? Incidentally, this was the todo in PowerPC/2007-04-24-InlineAsm-I-Modifier.ll Please do NOT pull this into Tak. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@50315 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
507ffd2423
commit
5a09690446
@ -109,7 +109,8 @@ public:
|
|||||||
/// srl/add/sra.
|
/// srl/add/sra.
|
||||||
bool isPow2DivCheap() const { return Pow2DivIsCheap; }
|
bool isPow2DivCheap() const { return Pow2DivIsCheap; }
|
||||||
|
|
||||||
/// getSetCCResultType - Return the ValueType of the result of setcc operations.
|
/// getSetCCResultType - Return the ValueType of the result of setcc
|
||||||
|
/// operations.
|
||||||
virtual MVT::ValueType getSetCCResultType(const SDOperand &) const;
|
virtual MVT::ValueType getSetCCResultType(const SDOperand &) const;
|
||||||
|
|
||||||
/// getSetCCResultContents - For targets without boolean registers, this flag
|
/// getSetCCResultContents - For targets without boolean registers, this flag
|
||||||
@ -1080,8 +1081,12 @@ public:
|
|||||||
|
|
||||||
/// ComputeConstraintToUse - Determines the constraint code and constraint
|
/// ComputeConstraintToUse - Determines the constraint code and constraint
|
||||||
/// type to use for the specific AsmOperandInfo, setting
|
/// type to use for the specific AsmOperandInfo, setting
|
||||||
/// OpInfo.ConstraintCode and OpInfo.ConstraintType.
|
/// OpInfo.ConstraintCode and OpInfo.ConstraintType. If the actual operand
|
||||||
virtual void ComputeConstraintToUse(AsmOperandInfo &OpInfo) const;
|
/// being passed in is available, it can be passed in as Op, otherwise an
|
||||||
|
/// empty SDOperand can be passed.
|
||||||
|
virtual void ComputeConstraintToUse(AsmOperandInfo &OpInfo,
|
||||||
|
SDOperand Op,
|
||||||
|
SelectionDAG *DAG = 0) const;
|
||||||
|
|
||||||
/// getConstraintType - Given a constraint, return the type of constraint it
|
/// getConstraintType - Given a constraint, return the type of constraint it
|
||||||
/// is for this target.
|
/// is for this target.
|
||||||
|
@ -3822,7 +3822,7 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
|
|||||||
OpInfo.ConstraintVT = OpVT;
|
OpInfo.ConstraintVT = OpVT;
|
||||||
|
|
||||||
// Compute the constraint code and ConstraintType to use.
|
// Compute the constraint code and ConstraintType to use.
|
||||||
TLI.ComputeConstraintToUse(OpInfo);
|
TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, &DAG);
|
||||||
|
|
||||||
// Keep track of whether we see an earlyclobber.
|
// Keep track of whether we see an earlyclobber.
|
||||||
SawEarlyClobber |= OpInfo.isEarlyClobber;
|
SawEarlyClobber |= OpInfo.isEarlyClobber;
|
||||||
|
@ -1688,7 +1688,8 @@ static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) {
|
|||||||
/// 'm' over 'r', for example.
|
/// 'm' over 'r', for example.
|
||||||
///
|
///
|
||||||
static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
|
static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
|
||||||
const TargetLowering &TLI) {
|
const TargetLowering &TLI,
|
||||||
|
SDOperand Op, SelectionDAG *DAG) {
|
||||||
assert(OpInfo.Codes.size() > 1 && "Doesn't have multiple constraint options");
|
assert(OpInfo.Codes.size() > 1 && "Doesn't have multiple constraint options");
|
||||||
unsigned BestIdx = 0;
|
unsigned BestIdx = 0;
|
||||||
TargetLowering::ConstraintType BestType = TargetLowering::C_Unknown;
|
TargetLowering::ConstraintType BestType = TargetLowering::C_Unknown;
|
||||||
@ -1699,6 +1700,23 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
|
|||||||
TargetLowering::ConstraintType CType =
|
TargetLowering::ConstraintType CType =
|
||||||
TLI.getConstraintType(OpInfo.Codes[i]);
|
TLI.getConstraintType(OpInfo.Codes[i]);
|
||||||
|
|
||||||
|
// If this is an 'other' constraint, see if the operand is valid for it.
|
||||||
|
// For example, on X86 we might have an 'rI' constraint. If the operand
|
||||||
|
// is an integer in the range [0..31] we want to use I (saving a load
|
||||||
|
// of a register), otherwise we must use 'r'.
|
||||||
|
if (CType == TargetLowering::C_Other && Op.Val) {
|
||||||
|
assert(OpInfo.Codes[i].size() == 1 &&
|
||||||
|
"Unhandled multi-letter 'other' constraint");
|
||||||
|
std::vector<SDOperand> ResultOps;
|
||||||
|
TLI.LowerAsmOperandForConstraint(Op, OpInfo.Codes[i][0],
|
||||||
|
ResultOps, *DAG);
|
||||||
|
if (!ResultOps.empty()) {
|
||||||
|
BestType = CType;
|
||||||
|
BestIdx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This constraint letter is more general than the previous one, use it.
|
// This constraint letter is more general than the previous one, use it.
|
||||||
int Generality = getConstraintGenerality(CType);
|
int Generality = getConstraintGenerality(CType);
|
||||||
if (Generality > BestGenerality) {
|
if (Generality > BestGenerality) {
|
||||||
@ -1715,7 +1733,9 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
|
|||||||
/// ComputeConstraintToUse - Determines the constraint code and constraint
|
/// ComputeConstraintToUse - Determines the constraint code and constraint
|
||||||
/// type to use for the specific AsmOperandInfo, setting
|
/// type to use for the specific AsmOperandInfo, setting
|
||||||
/// OpInfo.ConstraintCode and OpInfo.ConstraintType.
|
/// OpInfo.ConstraintCode and OpInfo.ConstraintType.
|
||||||
void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo) const {
|
void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo,
|
||||||
|
SDOperand Op,
|
||||||
|
SelectionDAG *DAG) const {
|
||||||
assert(!OpInfo.Codes.empty() && "Must have at least one constraint");
|
assert(!OpInfo.Codes.empty() && "Must have at least one constraint");
|
||||||
|
|
||||||
// Single-letter constraints ('r') are very common.
|
// Single-letter constraints ('r') are very common.
|
||||||
@ -1723,7 +1743,7 @@ void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo) const {
|
|||||||
OpInfo.ConstraintCode = OpInfo.Codes[0];
|
OpInfo.ConstraintCode = OpInfo.Codes[0];
|
||||||
OpInfo.ConstraintType = getConstraintType(OpInfo.ConstraintCode);
|
OpInfo.ConstraintType = getConstraintType(OpInfo.ConstraintCode);
|
||||||
} else {
|
} else {
|
||||||
ChooseConstraint(OpInfo, *this);
|
ChooseConstraint(OpInfo, *this, Op, DAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'X' matches anything.
|
// 'X' matches anything.
|
||||||
|
@ -962,7 +962,7 @@ bool CodeGenPrepare::OptimizeInlineAsmInst(Instruction *I, CallSite CS,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute the constraint code and ConstraintType to use.
|
// Compute the constraint code and ConstraintType to use.
|
||||||
TLI->ComputeConstraintToUse(OpInfo);
|
TLI->ComputeConstraintToUse(OpInfo, SDOperand());
|
||||||
|
|
||||||
if (OpInfo.ConstraintType == TargetLowering::C_Memory &&
|
if (OpInfo.ConstraintType == TargetLowering::C_Memory &&
|
||||||
OpInfo.isIndirect) {
|
OpInfo.isIndirect) {
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
; RUN: llvm-as < %s | llc -march=ppc32 -mtriple=powerpc-apple-darwin8.8.0 | grep {foo r3, r4}
|
; RUN: llvm-as < %s | llc -march=ppc32 -mtriple=powerpc-apple-darwin8.8.0 | grep {foo r3, r4}
|
||||||
; RUN: llvm-as < %s | llc -march=ppc32 -mtriple=powerpc-apple-darwin8.8.0 | grep {bar r3, r}
|
; RUN: llvm-as < %s | llc -march=ppc32 -mtriple=powerpc-apple-darwin8.8.0 | grep {bari r3, 47}
|
||||||
|
|
||||||
; PR1351
|
; PR1351
|
||||||
|
|
||||||
define i32 @test1(i32 %Y, i32 %X) {
|
define i32 @test1(i32 %Y, i32 %X) nounwind {
|
||||||
%tmp1 = tail call i32 asm "foo${1:I} $0, $1", "=r,rI"( i32 %X )
|
%tmp1 = tail call i32 asm "foo${1:I} $0, $1", "=r,rI"( i32 %X )
|
||||||
ret i32 %tmp1
|
ret i32 %tmp1
|
||||||
}
|
}
|
||||||
|
|
||||||
;; TODO: We'd actually prefer this to be 'bari r3, 47', but 'bar r3, rN' is also ok.
|
define i32 @test2(i32 %Y, i32 %X) nounwind {
|
||||||
define i32 @test2(i32 %Y, i32 %X) {
|
|
||||||
%tmp1 = tail call i32 asm "bar${1:I} $0, $1", "=r,rI"( i32 47 )
|
%tmp1 = tail call i32 asm "bar${1:I} $0, $1", "=r,rI"( i32 47 )
|
||||||
ret i32 %tmp1
|
ret i32 %tmp1
|
||||||
}
|
}
|
||||||
|
11
test/CodeGen/X86/2008-04-26-Asm-Optimize-Imm.ll
Normal file
11
test/CodeGen/X86/2008-04-26-Asm-Optimize-Imm.ll
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
; RUN: llvm-as < %s | llc | grep {1 \$2 3}
|
||||||
|
; rdar://5720231
|
||||||
|
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
|
||||||
|
target triple = "i386-apple-darwin8"
|
||||||
|
|
||||||
|
define void @test() nounwind {
|
||||||
|
entry:
|
||||||
|
tail call void asm sideeffect " ${0:c} $1 ${2:c} ", "imr,imr,i,~{dirflag},~{fpsr},~{flags}"( i32 1, i32 2, i32 3 ) nounwind
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user