[llvm-commits] CVS: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
Chris Lattner
lattner at cs.uiuc.edu
Wed Feb 1 10:59:59 PST 2006
Changes in directory llvm/lib/CodeGen/SelectionDAG:
SelectionDAGISel.cpp updated: 1.144 -> 1.145
---
Log message:
Implement simple register assignment for inline asms. This allows us to compile:
int %test(int %A, int %B) {
%C = call int asm "xyz $0, $1, $2", "=r,r,r"(int %A, int %B)
ret int %C
}
into:
(0x8906130, LLVM BB @0x8902220):
%r2 = OR4 %r3, %r3
%r3 = OR4 %r4, %r4
INLINEASM <es:xyz $0, $1, $2>, %r2<def>, %r2, %r3
%r3 = OR4 %r2, %r2
BLR
which asmprints as:
_test:
or r2, r3, r3
or r3, r4, r4
xyz $0, $1, $2 ;; need to print the operands now :)
or r3, r2, r2
blr
---
Diffs of the changes: (+103 -8)
SelectionDAGISel.cpp | 111 +++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 103 insertions(+), 8 deletions(-)
Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
diff -u llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.144 llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.145
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.144 Tue Jan 31 19:28:23 2006
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp Wed Feb 1 12:59:47 2006
@@ -40,6 +40,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Debug.h"
#include <map>
+#include <set>
#include <iostream>
using namespace llvm;
@@ -410,6 +411,11 @@
assert(N.Val == 0 && "Already set a value for this node!");
return N = NewN;
}
+
+ unsigned GetAvailableRegister(bool OutReg, bool InReg,
+ const std::vector<unsigned> &RegChoices,
+ std::set<unsigned> &OutputRegs,
+ std::set<unsigned> &InputRegs);
// Terminator instructions.
void visitRet(ReturnInst &I);
@@ -1143,6 +1149,49 @@
DAG.setRoot(Result.second);
}
+/// GetAvailableRegister - Pick a register from RegChoices that is available
+/// for input and/or output as specified by isOutReg/isInReg. If an allocatable
+/// register is found, it is returned and added to the specified set of used
+/// registers. If not, zero is returned.
+unsigned SelectionDAGLowering::
+GetAvailableRegister(bool isOutReg, bool isInReg,
+ const std::vector<unsigned> &RegChoices,
+ std::set<unsigned> &OutputRegs,
+ std::set<unsigned> &InputRegs) {
+ const MRegisterInfo *MRI = DAG.getTarget().getRegisterInfo();
+ MachineFunction &MF = *CurMBB->getParent();
+ for (unsigned i = 0, e = RegChoices.size(); i != e; ++i) {
+ unsigned Reg = RegChoices[i];
+ // See if this register is available.
+ if (isOutReg && OutputRegs.count(Reg)) continue; // Already used.
+ if (isInReg && InputRegs.count(Reg)) continue; // Already used.
+
+ // Check to see if this register is allocatable (i.e. don't give out the
+ // stack pointer).
+ bool Found = false;
+ for (MRegisterInfo::regclass_iterator RC = MRI->regclass_begin(),
+ E = MRI->regclass_end(); !Found && RC != E; ++RC) {
+ // NOTE: This isn't ideal. In particular, this might allocate the
+ // frame pointer in functions that need it (due to them not being taken
+ // out of allocation, because a variable sized allocation hasn't been seen
+ // yet). This is a slight code pessimization, but should still work.
+ for (TargetRegisterClass::iterator I = (*RC)->allocation_order_begin(MF),
+ E = (*RC)->allocation_order_end(MF); I != E; ++I)
+ if (*I == Reg) {
+ Found = true;
+ break;
+ }
+ }
+ if (!Found) continue;
+
+ // Okay, this register is good, return it.
+ if (isOutReg) OutputRegs.insert(Reg); // Mark used.
+ if (isInReg) InputRegs.insert(Reg); // Mark used.
+ return Reg;
+ }
+ return 0;
+}
+
/// visitInlineAsm - Handle a call to an InlineAsm object.
///
void SelectionDAGLowering::visitInlineAsm(CallInst &I) {
@@ -1174,21 +1223,60 @@
std::vector<std::pair<unsigned, Value*> > IndirectStoresToEmit;
unsigned OpNum = 1;
bool FoundOutputConstraint = false;
- //std::set<unsigned> OutputRegs;
- //std::set<unsigned> InputRegs;
+
+ // We fully assign registers here at isel time. This is not optimal, but
+ // should work. For register classes that correspond to LLVM classes, we
+ // could let the LLVM RA do its thing, but we currently don't. Do a prepass
+ // over the constraints, collecting fixed registers that we know we can't use.
+ std::set<unsigned> OutputRegs, InputRegs;
+ for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
+ assert(Constraints[i].Codes.size() == 1 && "Only handles one code so far!");
+ std::string &ConstraintCode = Constraints[i].Codes[0];
+ std::vector<unsigned> Regs =
+ TLI.getRegForInlineAsmConstraint(ConstraintCode);
+ if (Regs.size() != 1) continue; // Not assigned a fixed reg.
+ unsigned TheReg = Regs[0];
+
+ switch (Constraints[i].Type) {
+ case InlineAsm::isOutput:
+ // We can't assign any other output to this register.
+ OutputRegs.insert(TheReg);
+ // If this is an early-clobber output, it cannot be assigned to the same
+ // value as the input reg.
+ if (Constraints[i].isEarlyClobber)
+ InputRegs.insert(TheReg);
+ break;
+ case InlineAsm::isClobber:
+ // Clobbered regs cannot be used as inputs or outputs.
+ InputRegs.insert(TheReg);
+ OutputRegs.insert(TheReg);
+ break;
+ case InlineAsm::isInput:
+ // We can't assign any other input to this register.
+ InputRegs.insert(TheReg);
+ break;
+ }
+ }
for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
assert(Constraints[i].Codes.size() == 1 && "Only handles one code so far!");
std::string &ConstraintCode = Constraints[i].Codes[0];
switch (Constraints[i].Type) {
case InlineAsm::isOutput: {
- bool isEarlyClobber = Constraints[i].isEarlyClobber;
// Copy the output from the appropriate register.
std::vector<unsigned> Regs =
TLI.getRegForInlineAsmConstraint(ConstraintCode);
- assert(Regs.size() == 1 && "Only handle simple regs right now!");
- unsigned DestReg = Regs[0];
+
+ // Find a regsister that we can use.
+ unsigned DestReg;
+ if (Regs.size() == 1)
+ DestReg = Regs[0];
+ else
+ DestReg = GetAvailableRegister(true, Constraints[i].isEarlyClobber,
+ Regs, OutputRegs, InputRegs);
+
+ assert(DestReg && "Couldn't allocate output reg!");
const Type *OpTy;
if (!Constraints[i].isIndirectOutput) {
@@ -1218,12 +1306,20 @@
case InlineAsm::isInput: {
Value *Operand = I.getOperand(OpNum);
const Type *OpTy = Operand->getType();
+ OpNum++; // Consumes a call operand.
// Copy the input into the appropriate register.
std::vector<unsigned> Regs =
TLI.getRegForInlineAsmConstraint(ConstraintCode);
- assert(Regs.size() == 1 && "Only handle simple regs right now!");
- unsigned SrcReg = Regs[0];
+ unsigned SrcReg;
+ if (Regs.size() == 1)
+ SrcReg = Regs[0];
+ else
+ SrcReg = GetAvailableRegister(false, true, Regs,
+ OutputRegs, InputRegs);
+
+ assert(SrcReg && "Couldn't allocate input reg!");
+
Chain = DAG.getCopyToReg(Chain, SrcReg, getValue(Operand), Flag);
Flag = Chain.getValue(1);
@@ -1271,7 +1367,6 @@
Chain = Val.getValue(1);
Flag = Val.getValue(2);
StoresToEmit.push_back(std::make_pair(Val, Ptr));
- OpNum++; // Consumes a call operand.
}
// Emit the non-flagged stores from the physregs.
More information about the llvm-commits
mailing list