Subzero. Adds a pass for target-specific helper call generation.

This pass gives Targets the ability to pre-lower high-level
instructions that will later be lowered to a target-specific helper,
e.g., 64-bit division on targets that can't natively handle them.

This is a pre-requirement for correct outargs pre-allocation during
function prolog.

R=sehr@chromium.org

Review URL: https://codereview.chromium.org/1455033005 .
diff --git a/src/IceInst.h b/src/IceInst.h
index 7505924..a04584e 100644
--- a/src/IceInst.h
+++ b/src/IceInst.h
@@ -378,34 +378,40 @@
 
 public:
   static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest,
-                          Operand *CallTarget, bool HasTailCall) {
+                          Operand *CallTarget, bool HasTailCall,
+                          bool IsTargetHelperCall = false) {
     /// Set HasSideEffects to true so that the call instruction can't be
     /// dead-code eliminated. IntrinsicCalls can override this if the particular
     /// intrinsic is deletable and has no side-effects.
     constexpr bool HasSideEffects = true;
     constexpr InstKind Kind = Inst::Call;
-    return new (Func->allocate<InstCall>()) InstCall(
-        Func, NumArgs, Dest, CallTarget, HasTailCall, HasSideEffects, Kind);
+    return new (Func->allocate<InstCall>())
+        InstCall(Func, NumArgs, Dest, CallTarget, HasTailCall,
+                 IsTargetHelperCall, HasSideEffects, Kind);
   }
   void addArg(Operand *Arg) { addSource(Arg); }
   Operand *getCallTarget() const { return getSrc(0); }
   Operand *getArg(SizeT I) const { return getSrc(I + 1); }
   SizeT getNumArgs() const { return getSrcSize() - 1; }
   bool isTailcall() const { return HasTailCall; }
+  bool isTargetHelperCall() const { return IsTargetHelperCall; }
   void dump(const Cfg *Func) const override;
   static bool classof(const Inst *Inst) { return Inst->getKind() == Call; }
   Type getReturnType() const;
 
 protected:
   InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget,
-           bool HasTailCall, bool HasSideEff, InstKind Kind)
-      : InstHighLevel(Func, Kind, NumArgs + 1, Dest), HasTailCall(HasTailCall) {
+           bool HasTailCall, bool IsTargetHelperCall, bool HasSideEff,
+           InstKind Kind)
+      : InstHighLevel(Func, Kind, NumArgs + 1, Dest), HasTailCall(HasTailCall),
+        IsTargetHelperCall(IsTargetHelperCall) {
     HasSideEffects = HasSideEff;
     addSource(CallTarget);
   }
 
 private:
-  bool HasTailCall;
+  const bool HasTailCall;
+  const bool IsTargetHelperCall;
 };
 
 /// Cast instruction (a.k.a. conversion operation).
@@ -570,8 +576,8 @@
 private:
   InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest,
                     Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info)
-      : InstCall(Func, NumArgs, Dest, CallTarget, false, Info.HasSideEffects,
-                 Inst::IntrinsicCall),
+      : InstCall(Func, NumArgs, Dest, CallTarget, false, false,
+                 Info.HasSideEffects, Inst::IntrinsicCall),
         Info(Info) {}
 
   const Intrinsics::IntrinsicInfo Info;
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 92223c9..a5bd86b 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -137,6 +137,16 @@
   return nullptr;
 }
 
+void TargetLowering::genTargetHelperCalls() {
+  for (CfgNode *Node : Func->getNodes()) {
+    Context.init(Node);
+    while (!Context.atEnd()) {
+      PostIncrLoweringContext _(Context);
+      genTargetHelperCallFor(Context.getCur());
+    }
+  }
+}
+
 void TargetLowering::doAddressOpt() {
   if (llvm::isa<InstLoad>(*Context.getCur()))
     doAddressOptLoad();
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index c613d99..5489b8b 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -170,6 +170,8 @@
     Func->setError("Target doesn't specify O2 lowering steps.");
   }
 
+  /// Generates calls to intrinsics for operations the Target can't handle.
+  void genTargetHelperCalls();
   /// Tries to do address mode optimization on a single instruction.
   void doAddressOpt();
   /// Randomly insert NOPs.
@@ -308,6 +310,8 @@
   virtual void lowerUnreachable(const InstUnreachable *Inst) = 0;
   virtual void lowerOther(const Inst *Instr);
 
+  virtual void genTargetHelperCallFor(Inst *Instr) = 0;
+
   virtual void doAddressOptLoad() {}
   virtual void doAddressOptStore() {}
   virtual void doMockBoundsCheck(Operand *) {}
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 24cced8..60d3a37 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -238,6 +238,7 @@
 
   // TODO(stichnot): share passes with X86?
   // https://code.google.com/p/nativeclient/issues/detail?id=4094
+  genTargetHelperCalls();
 
   // Do not merge Alloca instructions, and lay out the stack.
   static constexpr bool SortAndCombineAllocas = false;
@@ -344,6 +345,7 @@
   TimerMarker T(TimerStack::TT_Om1, Func);
 
   // TODO: share passes with X86?
+  genTargetHelperCalls();
 
   // Do not merge Alloca instructions, and lay out the stack.
   static constexpr bool SortAndCombineAllocas = false;
diff --git a/src/IceTargetLoweringARM32.h b/src/IceTargetLoweringARM32.h
index 318bce5..c0266eb 100644
--- a/src/IceTargetLoweringARM32.h
+++ b/src/IceTargetLoweringARM32.h
@@ -237,6 +237,7 @@
   void lowerSwitch(const InstSwitch *Inst) override;
   void lowerUnreachable(const InstUnreachable *Inst) override;
   void prelowerPhis() override;
+  void genTargetHelperCallFor(Inst *Instr) override { (void)Instr; }
   void doAddressOptLoad() override;
   void doAddressOptStore() override;
   void randomlyInsertNop(float Probability,
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 8e24808..85a9a46 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -91,6 +91,7 @@
 
   // TODO(stichnot): share passes with X86?
   // https://code.google.com/p/nativeclient/issues/detail?id=4094
+  genTargetHelperCalls();
 
   // Merge Alloca instructions, and lay out the stack.
   static constexpr bool SortAndCombineAllocas = true;
@@ -191,6 +192,7 @@
   TimerMarker T(TimerStack::TT_Om1, Func);
 
   // TODO: share passes with X86?
+  genTargetHelperCalls();
 
   // Do not merge Alloca instructions, and lay out the stack.
   static constexpr bool SortAndCombineAllocas = false;
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index 1f91eee..5523360 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -235,6 +235,7 @@
   void lowerSwitch(const InstSwitch *Inst) override;
   void lowerUnreachable(const InstUnreachable *Inst) override;
   void prelowerPhis() override;
+  void genTargetHelperCallFor(Inst *Instr) override { (void)Instr; }
   void doAddressOptLoad() override;
   void doAddressOptStore() override;
   void randomlyInsertNop(float Probability,
diff --git a/src/IceTargetLoweringX86Base.h b/src/IceTargetLoweringX86Base.h
index 90bbed2..3127151 100644
--- a/src/IceTargetLoweringX86Base.h
+++ b/src/IceTargetLoweringX86Base.h
@@ -182,6 +182,7 @@
   void lowerOther(const Inst *Instr) override;
   void lowerRMW(const typename Traits::Insts::FakeRMW *RMW);
   void prelowerPhis() override;
+  void genTargetHelperCallFor(Inst *Instr) override { (void)Instr; }
   void doAddressOptLoad() override;
   void doAddressOptStore() override;
   void doMockBoundsCheck(Operand *Opnd) override;
diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h
index 739ebb5..2653925 100644
--- a/src/IceTargetLoweringX86BaseImpl.h
+++ b/src/IceTargetLoweringX86BaseImpl.h
@@ -302,6 +302,8 @@
 template <class Machine> void TargetX86Base<Machine>::translateO2() {
   TimerMarker T(TimerStack::TT_O2, Func);
 
+  genTargetHelperCalls();
+
   // Merge Alloca instructions, and lay out the stack.
   static constexpr bool SortAndCombineAllocas = true;
   Func->processAllocas(SortAndCombineAllocas);
@@ -425,6 +427,8 @@
 template <class Machine> void TargetX86Base<Machine>::translateOm1() {
   TimerMarker T(TimerStack::TT_Om1, Func);
 
+  genTargetHelperCalls();
+
   // Do not merge Alloca instructions, and lay out the stack.
   static constexpr bool SortAndCombineAllocas = false;
   Func->processAllocas(SortAndCombineAllocas);