From 6656dd1a7888e6dabc82ebce734734127b1df6a7 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 31 Jan 2006 02:03:41 +0000 Subject: [PATCH] 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 --- lib/CodeGen/SelectionDAG/ScheduleDAG.cpp | 2 +- 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 4e45bd65646..9f285d5c9c9 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(Node->getOperand(i))->getReg(); - unsigned Flags = cast(Node->getOperand(i))->getValue(); + unsigned Flags =cast(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 78db4554dae..32fff90e966 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1158,7 +1158,6 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { std::vector > 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 > 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 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 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 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 > 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(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 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); } -- 2.34.1