From 4df83ed159f21fdf73a57729c3e9d8c9fcd73607 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 7 Jul 2010 19:20:32 +0000 Subject: [PATCH] Implement bottom-up fast-isel. This has the advantage of not requiring a separate DCE pass over MachineInstrs. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@107804 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/FastISel.h | 11 ++-- lib/CodeGen/LLVMTargetMachine.cpp | 20 +++--- lib/CodeGen/SelectionDAG/FastISel.cpp | 43 +++++++++---- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp | 7 ++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 29 ++++----- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 78 ++++++++++++----------- lib/Target/X86/X86FastISel.cpp | 64 ++++++++++++------- test/CodeGen/X86/fast-isel-loads.ll | 2 +- test/CodeGen/X86/fast-isel.ll | 14 ++-- 9 files changed, 156 insertions(+), 112 deletions(-) diff --git a/include/llvm/CodeGen/FastISel.h b/include/llvm/CodeGen/FastISel.h index 2067ca81325..24499dd9ffa 100644 --- a/include/llvm/CodeGen/FastISel.h +++ b/include/llvm/CodeGen/FastISel.h @@ -19,6 +19,7 @@ #include "llvm/ADT/SmallSet.h" #endif #include "llvm/CodeGen/ValueTypes.h" +#include "llvm/CodeGen/MachineBasicBlock.h" namespace llvm { @@ -55,15 +56,17 @@ protected: const TargetInstrInfo &TII; const TargetLowering &TLI; const TargetRegisterInfo &TRI; - bool IsBottomUp; + MachineBasicBlock::iterator LastLocalValue; public: + /// getLastLocalValue - Return the position of the last instruction + /// emitted for materializing constants for use in the current block. + MachineBasicBlock::iterator getLastLocalValue() { return LastLocalValue; } + /// startNewBlock - Set the current block to which generated machine /// instructions will be appended, and clear the local CSE map. /// - void startNewBlock() { - LocalValueMap.clear(); - } + void startNewBlock(); /// getCurDebugLoc() - Return current debug location information. DebugLoc getCurDebugLoc() const { return DL; } diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp index d437370031d..bf3137e4953 100644 --- a/lib/CodeGen/LLVMTargetMachine.cpp +++ b/lib/CodeGen/LLVMTargetMachine.cpp @@ -329,19 +329,15 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, if (OptLevel != CodeGenOpt::None) PM.add(createOptimizePHIsPass()); - // Delete dead machine instructions regardless of optimization level. - // - // At -O0, fast-isel frequently creates dead instructions. - // - // With optimization, dead code should already be eliminated. However - // there is one known exception: lowered code for arguments that are only - // used by tail calls, where the tail calls reuse the incoming stack - // arguments directly (see t11 in test/CodeGen/X86/sibcall.ll). - PM.add(createDeadMachineInstructionElimPass()); - printAndVerify(PM, "After codegen DCE pass", - /* allowDoubleDefs= */ true); - if (OptLevel != CodeGenOpt::None) { + // With optimization, dead code should already be eliminated. However + // there is one known exception: lowered code for arguments that are only + // used by tail calls, where the tail calls reuse the incoming stack + // arguments directly (see t11 in test/CodeGen/X86/sibcall.ll). + PM.add(createDeadMachineInstructionElimPass()); + printAndVerify(PM, "After codegen DCE pass", + /* allowDoubleDefs= */ true); + PM.add(createOptimizeExtsPass()); if (!DisableMachineLICM) PM.add(createMachineLICMPass()); diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index 2ba8315a7e6..5a245122775 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -57,6 +57,17 @@ #include "llvm/Support/ErrorHandling.h" using namespace llvm; +/// startNewBlock - Set the current block to which generated machine +/// instructions will be appended, and clear the local CSE map. +/// +void FastISel::startNewBlock() { + LocalValueMap.clear(); + + // Start out as end(), meaining no local-value instructions have + // been emitted. + LastLocalValue = FuncInfo.MBB->end(); +} + bool FastISel::hasTrivialKill(const Value *V) const { // Don't consider constants or arguments to have trivial kills. const Instruction *I = dyn_cast(V); @@ -109,12 +120,9 @@ unsigned FastISel::getRegForValue(const Value *V) { // In bottom-up mode, just create the virtual register which will be used // to hold the value. It will be materialized later. - if (IsBottomUp) { + if (isa(V)) { Reg = createResultReg(TLI.getRegClassFor(VT)); - if (isa(V)) - FuncInfo.ValueMap[V] = Reg; - else - LocalValueMap[V] = Reg; + FuncInfo.ValueMap[V] = Reg; return Reg; } @@ -180,8 +188,10 @@ unsigned FastISel::materializeRegForValue(const Value *V, MVT VT) { // Don't cache constant materializations in the general ValueMap. // To do so would require tracking what uses they dominate. - if (Reg != 0) + if (Reg != 0) { LocalValueMap[V] = Reg; + LastLocalValue = MRI.getVRegDef(Reg); + } return Reg; } @@ -210,12 +220,20 @@ unsigned FastISel::UpdateValueMap(const Value *I, unsigned Reg) { unsigned &AssignedReg = FuncInfo.ValueMap[I]; if (AssignedReg == 0) + // Use the new register. AssignedReg = Reg; else if (Reg != AssignedReg) { - const TargetRegisterClass *RegClass = MRI.getRegClass(Reg); - TII.copyRegToReg(*FuncInfo.MBB, FuncInfo.InsertPt, AssignedReg, - Reg, RegClass, RegClass, DL); + // We already have a register for this value. Replace uses of + // the existing register with uses of the new one. + MRI.replaceRegWith(AssignedReg, Reg); + // Replace uses of the existing register in PHINodesToUpdate too. + for (unsigned i = 0, e = FuncInfo.PHINodesToUpdate.size(); i != e; ++i) + if (FuncInfo.PHINodesToUpdate[i].second == AssignedReg) + FuncInfo.PHINodesToUpdate[i].second = Reg; + // And update the ValueMap. + AssignedReg = Reg; } + return AssignedReg; } @@ -736,11 +754,15 @@ FastISel::SelectLoad(const User *I) { BasicBlock::iterator ScanFrom = LI; if (const Value *V = FindAvailableLoadedValue(LI->getPointerOperand(), LI->getParent(), ScanFrom)) { + if (!isa(V) || + cast(V)->getParent() == LI->getParent() || + (isa(V) && FuncInfo.StaticAllocaMap.count(cast(V)))) { unsigned ResultReg = getRegForValue(V); if (ResultReg != 0) { UpdateValueMap(I, ResultReg); return true; } + } } } @@ -871,8 +893,7 @@ FastISel::FastISel(FunctionLoweringInfo &funcInfo) TD(*TM.getTargetData()), TII(*TM.getInstrInfo()), TLI(*TM.getTargetLowering()), - TRI(*TM.getRegisterInfo()), - IsBottomUp(false) { + TRI(*TM.getRegisterInfo()) { } FastISel::~FastISel() {} diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 8c4211ab29a..55171fca096 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -78,6 +78,13 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf) { MF = &mf; RegInfo = &MF->getRegInfo(); + // Check whether the function can return without sret-demotion. + SmallVector Outs; + GetReturnInfo(Fn->getReturnType(), + Fn->getAttributes().getRetAttributes(), Outs, TLI); + CanLowerReturn = TLI.CanLowerReturn(Fn->getCallingConv(), Fn->isVarArg(), + Outs, Fn->getContext()); + // Create a vreg for each argument register that is not dead and is used // outside of the entry block for the function. for (Function::const_arg_iterator AI = Fn->arg_begin(), E = Fn->arg_end(); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index f855f3a16ac..3b3ee3e3434 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -951,12 +951,10 @@ SDValue SelectionDAGBuilder::getValueImpl(const Value *V) { // If this is an instruction which fast-isel has deferred, select it now. if (const Instruction *Inst = dyn_cast(V)) { - assert(Inst->isSafeToSpeculativelyExecute() && - "Instruction with side effects deferred!"); - visit(*Inst); - DenseMap::iterator NIt = NodeMap.find(Inst); - if (NIt != NodeMap.end() && NIt->second.getNode()) - return NIt->second; + unsigned InReg = FuncInfo.InitializeRegForValue(Inst); + RegsForValue RFV(*DAG.getContext(), TLI, InReg, Inst->getType()); + SDValue Chain = DAG.getEntryNode(); + return RFV.getCopyFromRegs(DAG, FuncInfo, getCurDebugLoc(), Chain, NULL); } llvm_unreachable("Can't get register for value!"); @@ -1259,7 +1257,7 @@ SelectionDAGBuilder::ShouldEmitAsBranches(const std::vector &Cases){ } void SelectionDAGBuilder::visitBr(const BranchInst &I) { - MachineBasicBlock *BrMBB = FuncInfo.MBBMap[I.getParent()]; + MachineBasicBlock *BrMBB = FuncInfo.MBB; // Update machine-CFG edges. MachineBasicBlock *Succ0MBB = FuncInfo.MBBMap[I.getSuccessor(0)]; @@ -1585,7 +1583,7 @@ void SelectionDAGBuilder::visitBitTestCase(MachineBasicBlock* NextMBB, } void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) { - MachineBasicBlock *InvokeMBB = FuncInfo.MBBMap[I.getParent()]; + MachineBasicBlock *InvokeMBB = FuncInfo.MBB; // Retrieve successors. MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)]; @@ -2113,7 +2111,7 @@ size_t SelectionDAGBuilder::Clusterify(CaseVector& Cases, } void SelectionDAGBuilder::visitSwitch(const SwitchInst &SI) { - MachineBasicBlock *SwitchMBB = FuncInfo.MBBMap[SI.getParent()]; + MachineBasicBlock *SwitchMBB = FuncInfo.MBB; // Figure out which block is immediately after the current one. MachineBasicBlock *NextBlock = 0; @@ -2179,7 +2177,7 @@ void SelectionDAGBuilder::visitSwitch(const SwitchInst &SI) { } void SelectionDAGBuilder::visitIndirectBr(const IndirectBrInst &I) { - MachineBasicBlock *IndirectBrMBB = FuncInfo.MBBMap[I.getParent()]; + MachineBasicBlock *IndirectBrMBB = FuncInfo.MBB; // Update machine-CFG edges with unique successors. SmallVector succs; @@ -3839,7 +3837,7 @@ SelectionDAGBuilder::EmitFuncArgumentDbgValue(const DbgValueInst &DI, if (DV.isInlinedFnArgument(MF.getFunction())) return false; - MachineBasicBlock *MBB = FuncInfo.MBBMap[DI.getParent()]; + MachineBasicBlock *MBB = FuncInfo.MBB; if (MBB != &MF.front()) return false; @@ -4102,7 +4100,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { } case Intrinsic::eh_exception: { // Insert the EXCEPTIONADDR instruction. - assert(FuncInfo.MBBMap[I.getParent()]->isLandingPad() && + assert(FuncInfo.MBB->isLandingPad() && "Call to eh.exception not in landing pad!"); SDVTList VTs = DAG.getVTList(TLI.getPointerTy(), MVT::Other); SDValue Ops[1]; @@ -4114,7 +4112,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { } case Intrinsic::eh_selector: { - MachineBasicBlock *CallMBB = FuncInfo.MBBMap[I.getParent()]; + MachineBasicBlock *CallMBB = FuncInfo.MBB; MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); if (CallMBB->isLandingPad()) AddCatchInfo(I, &MMI, CallMBB); @@ -4124,7 +4122,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { #endif // FIXME: Mark exception selector register as live in. Hack for PR1508. unsigned Reg = TLI.getExceptionSelectorRegister(); - if (Reg) FuncInfo.MBBMap[I.getParent()]->addLiveIn(Reg); + if (Reg) FuncInfo.MBB->addLiveIn(Reg); } // Insert the EHSELECTION instruction. @@ -5901,9 +5899,6 @@ void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) { GetReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(), Outs, TLI); - FuncInfo->CanLowerReturn = TLI.CanLowerReturn(F.getCallingConv(), - F.isVarArg(), - Outs, F.getContext()); if (!FuncInfo->CanLowerReturn) { // Put in an sret pointer parameter before all the other parameters. SmallVector ValueVTs; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index bea65b2d20e..8918516e75f 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -680,60 +680,55 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { BasicBlock::const_iterator const Begin = LLVMBB->getFirstNonPHI(); BasicBlock::const_iterator const End = LLVMBB->end(); - BasicBlock::const_iterator BI = Begin; + BasicBlock::const_iterator BI = End; - // Lower any arguments needed in this block if this is the entry block. - if (LLVMBB == &Fn.getEntryBlock()) - LowerArguments(LLVMBB); - - // Setup an EH landing-pad block. - if (FuncInfo->MBB->isLandingPad()) - PrepareEHLandingPad(); - // Before doing SelectionDAG ISel, see if FastISel has been requested. if (FastIS) { - // Emit code for any incoming arguments. This must happen before - // beginning FastISel on the entry block. - if (LLVMBB == &Fn.getEntryBlock()) { - CurDAG->setRoot(SDB->getControlRoot()); - SDB->clear(); - CodeGenAndEmitDAG(); - } FastIS->startNewBlock(); + // Do FastISel on as many instructions as possible. - for (; BI != End; ++BI) { -#if 0 - // Defer instructions with no side effects; they'll be emitted - // on-demand later. - if (BI->isSafeToSpeculativelyExecute() && - !FuncInfo->isExportedInst(BI)) + for (; BI != Begin; --BI) { + const Instruction *Inst = llvm::prior(BI); + + // If we no longer require this instruction, skip it. + if (!Inst->mayWriteToMemory() && + !isa(Inst) && + !isa(Inst) && + !FuncInfo->isExportedInst(Inst)) continue; -#endif + + // Bottom-up: reset the insert pos at the top, after any local-value + // instructions. + MachineBasicBlock::iterator LVIP = FastIS->getLastLocalValue(); + if (LVIP != FuncInfo->MBB->end()) + FuncInfo->InsertPt = next(LVIP); + else + FuncInfo->InsertPt = FuncInfo->MBB->getFirstNonPHI(); // Try to select the instruction with FastISel. - if (FastIS->SelectInstruction(BI)) + if (FastIS->SelectInstruction(Inst)) continue; // Then handle certain instructions as single-LLVM-Instruction blocks. - if (isa(BI)) { + if (isa(Inst)) { ++NumFastIselFailures; if (EnableFastISelVerbose || EnableFastISelAbort) { dbgs() << "FastISel missed call: "; - BI->dump(); + Inst->dump(); } - if (!BI->getType()->isVoidTy() && !BI->use_empty()) { - unsigned &R = FuncInfo->ValueMap[BI]; + if (!Inst->getType()->isVoidTy() && !Inst->use_empty()) { + unsigned &R = FuncInfo->ValueMap[Inst]; if (!R) - R = FuncInfo->CreateRegs(BI->getType()); + R = FuncInfo->CreateRegs(Inst->getType()); } bool HadTailCall = false; - SelectBasicBlock(BI, llvm::next(BI), HadTailCall); + SelectBasicBlock(Inst, BI, HadTailCall); // If the call was emitted as a tail call, we're done with the block. if (HadTailCall) { - BI = End; + --BI; break; } @@ -746,7 +741,7 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { ++NumFastIselFailures; if (EnableFastISelVerbose || EnableFastISelAbort) { dbgs() << "FastISel miss: "; - BI->dump(); + Inst->dump(); } if (EnableFastISelAbort) // The "fast" selector couldn't handle something and bailed. @@ -757,13 +752,21 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { } } + FuncInfo->InsertPt = FuncInfo->MBB->getFirstNonPHI(); + + // Setup an EH landing-pad block. + if (FuncInfo->MBB->isLandingPad()) + PrepareEHLandingPad(); + + // Lower any arguments needed in this block if this is the entry block. + if (LLVMBB == &Fn.getEntryBlock()) + LowerArguments(LLVMBB); + // Run SelectionDAG instruction selection on the remainder of the block // not handled by FastISel. If FastISel is not run, this is the entire // block. - if (BI != End) { - bool HadTailCall; - SelectBasicBlock(BI, End, HadTailCall); - } + bool HadTailCall; + SelectBasicBlock(Begin, BI, HadTailCall); FinishBasicBlock(); FuncInfo->PHINodesToUpdate.clear(); @@ -963,7 +966,8 @@ SelectionDAGISel::FinishBasicBlock() { for (unsigned i = 0, e = Succs.size(); i != e; ++i) { FuncInfo->MBB = Succs[i]; FuncInfo->InsertPt = FuncInfo->MBB->end(); - // BB may have been removed from the CFG if a branch was constant folded. + // FuncInfo->MBB may have been removed from the CFG if a branch was + // constant folded. if (ThisBB->isSuccessor(FuncInfo->MBB)) { for (MachineBasicBlock::iterator Phi = FuncInfo->MBB->begin(); Phi != FuncInfo->MBB->end() && Phi->isPHI(); diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index 594ca4b1128..8300715c97a 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -108,6 +108,7 @@ private: bool X86SelectCall(const Instruction *I); CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool isTailCall = false); + CCAssignFn *CCAssignFnForRet(CallingConv::ID CC, bool isTailCall = false); const X86InstrInfo *getInstrInfo() const { return getTargetMachine()->getInstrInfo(); @@ -181,6 +182,20 @@ CCAssignFn *X86FastISel::CCAssignFnForCall(CallingConv::ID CC, return CC_X86_32_C; } +/// CCAssignFnForRet - Selects the correct CCAssignFn for a given calling +/// convention. +CCAssignFn *X86FastISel::CCAssignFnForRet(CallingConv::ID CC, + bool isTaillCall) { + if (Subtarget->is64Bit()) { + if (Subtarget->isTargetWin64()) + return RetCC_X86_Win64_C; + else + return RetCC_X86_64_C; + } + + return RetCC_X86_32_C; +} + /// X86FastEmitLoad - Emit a machine instruction to load a value of type VT. /// The address is either pre-computed, i.e. Ptr, or a GlobalAddress, i.e. GV. /// Return true and the result register by reference if it is possible. @@ -689,34 +704,39 @@ bool X86FastISel::X86SelectRet(const Instruction *I) { if (F.isVarArg()) return false; - SmallVector Outs; - GetReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(), - Outs, TLI); + if (Ret->getNumOperands() > 0) { + SmallVector Outs; + GetReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(), + Outs, TLI); - // Analyze operands of the call, assigning locations to each operand. - SmallVector ValLocs; - CCState CCInfo(CC, F.isVarArg(), TM, ValLocs, I->getContext()); - CCInfo.AnalyzeReturn(Outs, CCAssignFnForCall(CC)); + // Analyze operands of the call, assigning locations to each operand. + SmallVector ValLocs; + CCState CCInfo(CC, F.isVarArg(), TM, ValLocs, I->getContext()); + CCInfo.AnalyzeReturn(Outs, CCAssignFnForRet(CC)); - // Copy the return value into registers. - for (unsigned i = 0, e = ValLocs.size(); i != e; ++i) { - CCValAssign &VA = ValLocs[i]; - - // Don't bother handling odd stuff for now. - if (VA.getLocInfo() != CCValAssign::Full) - return false; - if (!VA.isRegLoc()) + const Value *RV = Ret->getOperand(0); + unsigned Reg = getRegForValue(RV); + if (Reg == 0) return false; - const Value *RV = Ret->getOperand(VA.getValNo()); - unsigned Reg = getRegForValue(RV); + // Copy the return value into registers. + for (unsigned i = 0, e = ValLocs.size(); i != e; ++i) { + CCValAssign &VA = ValLocs[i]; + + // Don't bother handling odd stuff for now. + if (VA.getLocInfo() != CCValAssign::Full) + return false; + if (!VA.isRegLoc()) + return false; - TargetRegisterClass* RC = TLI.getRegClassFor(VA.getValVT()); - bool Emitted = TII.copyRegToReg(*FuncInfo.MBB, FuncInfo.InsertPt, - VA.getLocReg(), Reg, RC, RC, DL); - assert(Emitted && "Failed to emit a copy instruction!"); Emitted=Emitted; + TargetRegisterClass* RC = TLI.getRegClassFor(VA.getValVT()); + bool Emitted = TII.copyRegToReg(*FuncInfo.MBB, FuncInfo.InsertPt, + VA.getLocReg(), Reg + VA.getValNo(), + RC, RC, DL); + assert(Emitted && "Failed to emit a copy instruction!"); Emitted=Emitted; - MRI.addLiveOut(X86::XMM0); + MRI.addLiveOut(VA.getLocReg()); + } } // Now emit the RET. diff --git a/test/CodeGen/X86/fast-isel-loads.ll b/test/CodeGen/X86/fast-isel-loads.ll index 027363e4688..2fbb46c0b9f 100644 --- a/test/CodeGen/X86/fast-isel-loads.ll +++ b/test/CodeGen/X86/fast-isel-loads.ll @@ -5,7 +5,7 @@ ; CHECK: foo: ; CHECK-NEXT: movq %rdi, -8(%rsp) ; CHECK-NEXT: movq %rsi, -16(%rsp) -; CHECK: movsd 128(%rsi,%rdi,8), %xmm0 +; CHECK-NEXT: movsd 128(%rsi,%rdi,8), %xmm0 ; CHECK-NEXT: ret define double @foo(i64 %x, double* %p) nounwind { diff --git a/test/CodeGen/X86/fast-isel.ll b/test/CodeGen/X86/fast-isel.ll index 3d26ae7018b..177c06b45dc 100644 --- a/test/CodeGen/X86/fast-isel.ll +++ b/test/CodeGen/X86/fast-isel.ll @@ -49,9 +49,10 @@ entry: ret i32 %tmp2 } -define i1 @ptrtoint_i1(i8* %p) nounwind { +define void @ptrtoint_i1(i8* %p, i1* %q) nounwind { %t = ptrtoint i8* %p to i1 - ret i1 %t + store i1 %t, i1* %q + ret void } define i8* @inttoptr_i1(i1 %p) nounwind { %t = inttoptr i1 %p to i8* @@ -86,11 +87,8 @@ define i8 @mul_i8(i8 %a) nounwind { ret i8 %tmp } -define void @store_i1(i1* %p, i1 %t) nounwind { - store i1 %t, i1* %p - ret void -} -define i1 @load_i1(i1* %p) nounwind { +define void @load_store_i1(i1* %p, i1* %q) nounwind { %t = load i1* %p - ret i1 %t + store i1 %t, i1* %q + ret void } -- 2.11.0