GlobalISel: add code to widen scalar G_ADD
authorTim Northover <tnorthover@apple.com>
Thu, 4 Aug 2016 18:35:11 +0000 (18:35 +0000)
committerTim Northover <tnorthover@apple.com>
Thu, 4 Aug 2016 18:35:11 +0000 (18:35 +0000)
llvm-svn: 277747

llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
llvm/include/llvm/Target/GenericOpcodes.td
llvm/include/llvm/Target/TargetOpcodes.def
llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
llvm/lib/CodeGen/GlobalISel/MachineLegalizeHelper.cpp
llvm/lib/CodeGen/GlobalISel/MachineLegalizer.cpp
llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir

index e83ade6..1178503 100644 (file)
@@ -131,6 +131,18 @@ public:
   MachineInstrBuilder buildAdd(LLT Ty, unsigned Res, unsigned Op0,
                                 unsigned Op1);
 
+  /// Build and insert \p Res<def> = G_ANYEXTEND \p Ty \p Op0
+  ///
+  /// G_ANYEXTEND produces a register of the specified width, with bits 0 to
+  /// sizeof(\p Ty) * 8 set to \p Op. The remaining bits are unspecified
+  /// (i.e. this is neither zero nor sign-extension). For a vector register,
+  /// each element is extended individually.
+  ///
+  /// \pre setBasicBlock or setMI must have been called.
+  ///
+  /// \return The newly created instruction.
+  MachineInstrBuilder buildAnyExtend(LLT Ty, unsigned Res, unsigned Op);
+
   /// Build and insert G_BR unsized \p Dest
   ///
   /// G_BR is an unconditional branch to \p Dest.
@@ -217,6 +229,16 @@ public:
   /// \return a MachineInstrBuilder for the newly created instruction.
   MachineInstrBuilder buildIntrinsic(ArrayRef<LLT> Tys, Intrinsic::ID ID,
                                      unsigned Res, bool HasSideEffects);
+
+  /// Build and insert \p Res<def> = G_TRUNC \p Ty \p Op
+  ///
+  /// G_TRUNC extracts the low bits of a type. For a vector type each element is
+  /// truncated independently before being packed into the destination.
+  ///
+  /// \pre setBasicBlock or setMI must have been called.
+  ///
+  /// \return The newly created instruction.
+  MachineInstrBuilder buildTrunc(LLT Ty, unsigned Res, unsigned Op);
 };
 
 } // End namespace llvm.
index 7dd0c07..aa7639c 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
+// Unary ops.
+//------------------------------------------------------------------------------
+
+// Extend the underlying scalar type of an operation, leaving the high bits
+// unspecified.
+def G_ANYEXTEND : Instruction {
+  let OutOperandList = (outs unknown:$dst);
+  let InOperandList = (ins unknown:$src);
+  let hasSideEffects = 0;
+}
+
+// Truncate the underlying scalar type of an operation. This is equivalent to
+// G_EXTRACT for scalar types, but acts elementwise on vectors.
+def G_TRUNC : Instruction {
+  let OutOperandList = (outs unknown:$dst);
+  let InOperandList = (ins unknown:$src);
+  let hasSideEffects = 0;
+}
+
 //------------------------------------------------------------------------------
 // Unary ops.
 //------------------------------------------------------------------------------
index 7c8a1df..01a589b 100644 (file)
@@ -208,6 +208,12 @@ HANDLE_TARGET_OPCODE(G_INTRINSIC)
 /// Generic intrinsic use (with side effects).
 HANDLE_TARGET_OPCODE(G_INTRINSIC_W_SIDE_EFFECTS)
 
+/// Generic extension allowing rubbish in high bits.
+HANDLE_TARGET_OPCODE(G_ANYEXTEND)
+
+/// Generic truncation.
+HANDLE_TARGET_OPCODE(G_TRUNC)
+
 /// Generic BRANCH instruction. This is an unconditional branch.
 HANDLE_TARGET_OPCODE(G_BR)
 
index 5e737d5..09a8fa6 100644 (file)
@@ -119,6 +119,11 @@ MachineInstrBuilder MachineIRBuilder::buildStore(LLT VTy, LLT PTy,
       .addMemOperand(&MMO);
 }
 
+MachineInstrBuilder MachineIRBuilder::buildAnyExtend(LLT Ty, unsigned Res,
+                                                     unsigned Op) {
+  return buildInstr(TargetOpcode::G_ANYEXTEND, Ty).addDef(Res).addUse(Op);
+}
+
 MachineInstrBuilder
 MachineIRBuilder::buildExtract(LLT Ty, ArrayRef<unsigned> Results, unsigned Src,
                                ArrayRef<unsigned> Indexes) {
@@ -157,3 +162,8 @@ MachineInstrBuilder MachineIRBuilder::buildIntrinsic(ArrayRef<LLT> Tys,
   MIB.addIntrinsicID(ID);
   return MIB;
 }
+
+MachineInstrBuilder MachineIRBuilder::buildTrunc(LLT Ty, unsigned Res,
+                                           unsigned Op) {
+  return buildInstr(TargetOpcode::G_TRUNC, Ty).addDef(Res).addUse(Op);
+}
index 55adbbd..71d3206 100644 (file)
@@ -66,7 +66,30 @@ MachineLegalizeHelper::narrowScalar(MachineInstr &MI, LLT NarrowTy) {
 
 MachineLegalizeHelper::LegalizeResult
 MachineLegalizeHelper::widenScalar(MachineInstr &MI, LLT WideTy) {
-  return UnableToLegalize;
+  switch (MI.getOpcode()) {
+  default:
+    return UnableToLegalize;
+  case TargetOpcode::G_ADD: {
+    // Perform operation at larger width (any extension is fine here, high bits
+    // don't affect the result) and then truncate the result back to the
+    // original type.
+    unsigned WideSize = WideTy.getSizeInBits();
+
+    MIRBuilder.setInstr(MI);
+
+    unsigned Src1Ext = MRI.createGenericVirtualRegister(WideSize);
+    unsigned Src2Ext = MRI.createGenericVirtualRegister(WideSize);
+    MIRBuilder.buildAnyExtend(WideTy, Src1Ext, MI.getOperand(1).getReg());
+    MIRBuilder.buildAnyExtend(WideTy, Src2Ext, MI.getOperand(2).getReg());
+
+    unsigned DstExt = MRI.createGenericVirtualRegister(WideSize);
+    MIRBuilder.buildAdd(WideTy, DstExt, Src1Ext, Src2Ext);
+
+    MIRBuilder.buildTrunc(MI.getType(), MI.getOperand(0).getReg(), DstExt);
+    MI.eraseFromParent();
+    return Legalized;
+  }
+  }
 }
 
 MachineLegalizeHelper::LegalizeResult
index 6856ed5..881b502 100644 (file)
 using namespace llvm;
 
 MachineLegalizer::MachineLegalizer() : TablesInitialized(false) {
+  // FIXME: these two can be legalized to the fundamental load/store Jakob
+  // proposed. Once loads & stores are supported.
+  DefaultActions[TargetOpcode::G_ANYEXTEND] = Legal;
+  DefaultActions[TargetOpcode::G_TRUNC] = Legal;
+
   DefaultActions[TargetOpcode::G_ADD] = NarrowScalar;
 }
 
index b47d875..9078db5 100644 (file)
@@ -3,6 +3,10 @@
 --- |
   target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
   target triple = "aarch64-apple-ios"
+  define void @test_scalar_add_small() {
+  entry:
+    ret void
+  }
   define void @test_vector_add() {
   entry:
     ret void
 ...
 
 ---
+name:            test_scalar_add_small
+isSSA:           true
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+  - { id: 2, class: _ }
+body: |
+  bb.0.entry:
+    liveins: %x0, %x1, %x2, %x3
+    ; CHECK-LABEL: name: test_scalar_add_small
+    ; CHECK-DAG: [[LHS:%.*]](32) = G_ANYEXTEND s32 %0
+    ; CHECK-DAG: [[RHS:%.*]](32) = G_ANYEXTEND s32 %1
+    ; CHECK: [[RES:%.*]](32) = G_ADD s32 [[LHS]], [[RHS]]
+    ; CHECK: %2(8) = G_TRUNC s8 [[RES]]
+
+    %0(8) = G_TRUNC s8 %x0
+    %1(8) = G_TRUNC s8 %x1
+    %2(8) = G_ADD s8 %0, %1
+    %x0 = G_ANYEXTEND s64 %2
+...
+
+---
 name:            test_vector_add
 isSSA:           true
 registers: