diff options
author | Chris Lattner <sabre@nondot.org> | 2006-01-31 02:03:41 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2006-01-31 02:03:41 +0000 |
commit | 6656dd1a7888e6dabc82ebce734734127b1df6a7 (patch) | |
tree | fdf0a15fb83d43f440315b1881827cbe1c80c5a2 /lib/CodeGen | |
parent | 594086d494e5282d8f8b665efe5af2170f83c653 (diff) |
Handle physreg input/outputs. We now compile this:
int %test_cpuid(int %op) {
%B = alloca int
%C = alloca int
%D = alloca int
%A = call int asm "cpuid", "=eax,==ebx,==ecx,==edx,eax"(int* %B, int* %C, int* %D, int %op)
%Bv = load int* %B
%Cv = load int* %C
%Dv = load int* %D
%x = add int %A, %Bv
%y = add int %x, %Cv
%z = add int %y, %Dv
ret int %z
}
to this:
_test_cpuid:
sub %ESP, 16
mov DWORD PTR [%ESP], %EBX
mov %EAX, DWORD PTR [%ESP + 20]
cpuid
mov DWORD PTR [%ESP + 8], %ECX
mov DWORD PTR [%ESP + 12], %EBX
mov DWORD PTR [%ESP + 4], %EDX
mov %ECX, DWORD PTR [%ESP + 12]
add %EAX, %ECX
mov %ECX, DWORD PTR [%ESP + 8]
add %EAX, %ECX
mov %ECX, DWORD PTR [%ESP + 4]
add %EAX, %ECX
mov %EBX, DWORD PTR [%ESP]
add %ESP, 16
ret
... note the proper register allocation. :)
it is unclear to me why the loads aren't folded into the adds.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@25827 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/SelectionDAG/ScheduleDAG.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 99 |
2 files changed, 97 insertions, 4 deletions
diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp index 4e45bd6564..9f285d5c9c 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp @@ -300,7 +300,7 @@ void ScheduleDAG::EmitNode(NodeInfo *NI) { // Add all of the operand registers to the instruction. for (unsigned i = 2; i != NumOps; i += 2) { unsigned Reg = cast<RegisterSDNode>(Node->getOperand(i))->getReg(); - unsigned Flags = cast<ConstantSDNode>(Node->getOperand(i))->getValue(); + unsigned Flags =cast<ConstantSDNode>(Node->getOperand(i+1))->getValue(); MachineOperand::UseType UseTy; switch (Flags) { default: assert(0 && "Bad flags!"); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 78db4554da..32fff90e96 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1158,7 +1158,6 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { std::vector<std::pair<InlineAsm::ConstraintPrefix, std::string> > Constraints = IA->ParseConstraints(); - /// AsmNodeOperands - A list of pairs. The first element is a register, the /// second is a bitfield where bit #0 is set if it is a use and bit #1 is set @@ -1170,7 +1169,69 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { SDOperand Chain = getRoot(); SDOperand Flag; - // FIXME: input copies. + // Loop over all of the inputs, copying the operand values into the + // appropriate registers and processing the output regs. + unsigned RetValReg = 0; + std::vector<std::pair<unsigned, Value*> > IndirectStoresToEmit; + unsigned OpNum = 1; + bool FoundOutputConstraint = false; + for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { + switch (Constraints[i].first) { + case InlineAsm::isOutput: { + assert(!FoundOutputConstraint && + "Cannot have multiple output constraints yet!"); + FoundOutputConstraint = true; + assert(I.getType() != Type::VoidTy && "Bad inline asm!"); + // Copy the output from the appropriate register. + std::vector<unsigned> Regs = + TLI.getRegForInlineAsmConstraint(Constraints[i].second); + assert(Regs.size() == 1 && "Only handle simple regs right now!"); + RetValReg = Regs[0]; + + // Add information to the INLINEASM node to know that this register is + // set. + AsmNodeOperands.push_back(DAG.getRegister(RetValReg, + TLI.getValueType(I.getType()))); + AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF + break; + } + case InlineAsm::isIndirectOutput: { + // Copy the output from the appropriate register. + std::vector<unsigned> Regs = + TLI.getRegForInlineAsmConstraint(Constraints[i].second); + assert(Regs.size() == 1 && "Only handle simple regs right now!"); + IndirectStoresToEmit.push_back(std::make_pair(Regs[0], + I.getOperand(OpNum))); + OpNum++; // Consumes a call operand. + + // Add information to the INLINEASM node to know that this register is + // set. + AsmNodeOperands.push_back(DAG.getRegister(Regs[0], + TLI.getValueType(I.getType()))); + AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF + break; + } + case InlineAsm::isInput: { + // Copy the input into the appropriate register. + std::vector<unsigned> Regs = + TLI.getRegForInlineAsmConstraint(Constraints[i].second); + assert(Regs.size() == 1 && "Only handle simple regs right now!"); + Chain = DAG.getCopyToReg(Chain, Regs[0], + getValue(I.getOperand(OpNum)), Flag); + Flag = Chain.getValue(1); + + // Add information to the INLINEASM node to know that this register is + // read. + AsmNodeOperands.push_back(DAG.getRegister(Regs[0], + TLI.getValueType(I.getType()))); + AsmNodeOperands.push_back(DAG.getConstant(1, MVT::i32)); // ISUSE + break; + } + case InlineAsm::isClobber: + // Nothing to do. + break; + } + } // Finish up input operands. AsmNodeOperands[0] = Chain; @@ -1182,8 +1243,40 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { Chain = DAG.getNode(ISD::INLINEASM, VTs, AsmNodeOperands); Flag = Chain.getValue(1); - // FIXME: Copies out of registers here, setValue(CI). + // If this asm returns a register value, copy the result from that register + // and set it as the value of the call. + if (RetValReg) { + SDOperand Val = DAG.getCopyFromReg(Chain, RetValReg, + TLI.getValueType(I.getType()), Flag); + Chain = Val.getValue(1); + Flag = Val.getValue(2); + setValue(&I, Val); + } + + std::vector<std::pair<SDOperand, Value*> > StoresToEmit; + + // Process indirect outputs, first output all of the flagged copies out of + // physregs. + for (unsigned i = 0, e = IndirectStoresToEmit.size(); i != e; ++i) { + Value *Ptr = IndirectStoresToEmit[i].second; + const Type *Ty = cast<PointerType>(Ptr->getType())->getElementType(); + SDOperand Val = DAG.getCopyFromReg(Chain, IndirectStoresToEmit[i].first, + TLI.getValueType(Ty), Flag); + 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. + std::vector<SDOperand> OutChains; + for (unsigned i = 0, e = StoresToEmit.size(); i != e; ++i) + OutChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain, + StoresToEmit[i].first, + getValue(StoresToEmit[i].second), + DAG.getSrcValue(StoresToEmit[i].second))); + if (!OutChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, OutChains); DAG.setRoot(Chain); } |