OSDN Git Service

Assembly and Bitcode support for unsigned/signed overflow flags and
authorDan Gohman <gohman@apple.com>
Mon, 20 Jul 2009 21:19:07 +0000 (21:19 +0000)
committerDan Gohman <gohman@apple.com>
Mon, 20 Jul 2009 21:19:07 +0000 (21:19 +0000)
exact sdiv flags.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76475 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/llvm/Bitcode/LLVMBitCodes.h
lib/AsmParser/LLLexer.cpp
lib/AsmParser/LLParser.cpp
lib/AsmParser/LLToken.h
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/VMCore/AsmWriter.cpp
test/Assembler/flags-plain.ll [new file with mode: 0644]
test/Assembler/flags-reversed.ll [new file with mode: 0644]
test/Assembler/flags-signed.ll [new file with mode: 0644]
test/Assembler/flags-unsigned.ll [new file with mode: 0644]
test/Assembler/flags.ll [new file with mode: 0644]

index c3a1bc1..753d0ff 100644 (file)
@@ -171,6 +171,18 @@ namespace bitc {
     BINOP_XOR  = 12
   };
 
+  /// OverflowingBinaryOperatorOptionalFlags - Flags for serializing
+  /// OverflowingBinaryOperator's SubclassOptionalData contents.
+  enum OverflowingBinaryOperatorOptionalFlags {
+    OBO_NO_UNSIGNED_OVERFLOW = 0,
+    OBO_NO_SIGNED_OVERFLOW = 1
+  };
+
+  /// SDivOperatorOptionalFlags - Flags for serializing SDivOperator's
+  /// SubclassOptionalData contents.
+  enum SDivOperatorOptionalFlags {
+    SDIV_EXACT = 0
+  };
 
   // The function body block (FUNCTION_BLOCK_ID) describes function bodies.  It
   // can contain a constant block (CONSTANTS_BLOCK_ID).
index a2e5b76..313213c 100644 (file)
@@ -501,6 +501,9 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(deplibs);
   KEYWORD(datalayout);
   KEYWORD(volatile);
+  KEYWORD(signed);
+  KEYWORD(unsigned);
+  KEYWORD(exact);
   KEYWORD(align);
   KEYWORD(addrspace);
   KEYWORD(section);
index c0b74a2..cbed869 100644 (file)
@@ -21,6 +21,7 @@
 #include "llvm/LLVMContext.h"
 #include "llvm/MDNode.h"
 #include "llvm/Module.h"
+#include "llvm/Operator.h"
 #include "llvm/ValueSymbolTable.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringExtras.h"
@@ -2041,6 +2042,49 @@ bool LLParser::ParseValID(ValID &ID) {
     ID.Kind = ValID::t_Constant;
     return false;
   }
+  case lltok::kw_signed: {
+    Lex.Lex();
+    bool AlsoUnsigned = EatIfPresent(lltok::kw_unsigned);
+    if (Lex.getKind() != lltok::kw_add &&
+        Lex.getKind() != lltok::kw_sub &&
+        Lex.getKind() != lltok::kw_mul)
+      return TokError("expected 'add', 'sub', or 'mul'");
+    bool Result = LLParser::ParseValID(ID);
+    if (!Result) {
+      cast<OverflowingBinaryOperator>(ID.ConstantVal)
+        ->setHasNoSignedOverflow(true);
+      if (AlsoUnsigned)
+        cast<OverflowingBinaryOperator>(ID.ConstantVal)
+          ->setHasNoUnsignedOverflow(true);
+    }
+    return Result;
+  }
+  case lltok::kw_unsigned: {
+    Lex.Lex();
+    bool AlsoSigned = EatIfPresent(lltok::kw_signed);
+    if (Lex.getKind() != lltok::kw_add &&
+        Lex.getKind() != lltok::kw_sub &&
+        Lex.getKind() != lltok::kw_mul)
+      return TokError("expected 'add', 'sub', or 'mul'");
+    bool Result = LLParser::ParseValID(ID);
+    if (!Result) {
+      cast<OverflowingBinaryOperator>(ID.ConstantVal)
+        ->setHasNoUnsignedOverflow(true);
+      if (AlsoSigned)
+        cast<OverflowingBinaryOperator>(ID.ConstantVal)
+          ->setHasNoSignedOverflow(true);
+    }
+    return Result;
+  }
+  case lltok::kw_exact: {
+    Lex.Lex();
+    if (Lex.getKind() != lltok::kw_sdiv)
+      return TokError("expected 'sdiv'");
+    bool Result = LLParser::ParseValID(ID);
+    if (!Result)
+      cast<SDivOperator>(ID.ConstantVal)->setIsExact(true);
+    return Result;
+  }
   }
   
   Lex.Lex();
@@ -2558,6 +2602,50 @@ bool LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB,
       return ParseStore(Inst, PFS, true);
     else
       return TokError("expected 'load' or 'store'");
+  case lltok::kw_signed: {
+    bool AlsoUnsigned = EatIfPresent(lltok::kw_unsigned);
+    if (Lex.getKind() == lltok::kw_add ||
+        Lex.getKind() == lltok::kw_sub ||
+        Lex.getKind() == lltok::kw_mul) {
+      Lex.Lex();
+      KeywordVal = Lex.getUIntVal();
+      bool Result = ParseArithmetic(Inst, PFS, KeywordVal, 0);
+      if (!Result) {
+        cast<OverflowingBinaryOperator>(Inst)->setHasNoSignedOverflow(true);
+        if (AlsoUnsigned)
+          cast<OverflowingBinaryOperator>(Inst)->setHasNoUnsignedOverflow(true);
+      }
+      return Result;
+    }
+    return TokError("expected 'add', 'sub', or 'mul'");
+  }
+  case lltok::kw_unsigned: {
+    bool AlsoSigned = EatIfPresent(lltok::kw_signed);
+    if (Lex.getKind() == lltok::kw_add ||
+        Lex.getKind() == lltok::kw_sub ||
+        Lex.getKind() == lltok::kw_mul) {
+      Lex.Lex();
+      KeywordVal = Lex.getUIntVal();
+      bool Result = ParseArithmetic(Inst, PFS, KeywordVal, 1);
+      if (!Result) {
+        cast<OverflowingBinaryOperator>(Inst)->setHasNoUnsignedOverflow(true);
+        if (AlsoSigned)
+          cast<OverflowingBinaryOperator>(Inst)->setHasNoSignedOverflow(true);
+      }
+      return Result;
+    }
+    return TokError("expected 'add', 'sub', or 'mul'");
+  }
+  case lltok::kw_exact:
+    if (Lex.getKind() == lltok::kw_sdiv) {
+      Lex.Lex();
+      KeywordVal = Lex.getUIntVal();
+      bool Result = ParseArithmetic(Inst, PFS, KeywordVal, 1);
+      if (!Result)
+        cast<SDivOperator>(Inst)->setIsExact(true);
+      return Result;
+    }
+    return TokError("expected 'udiv'");
   case lltok::kw_getresult:     return ParseGetResult(Inst, PFS);
   case lltok::kw_getelementptr: return ParseGetElementPtr(Inst, PFS);
   case lltok::kw_extractvalue:  return ParseExtractValue(Inst, PFS);
index 0f00eb6..b78a09d 100644 (file)
@@ -51,6 +51,9 @@ namespace lltok {
     kw_deplibs,
     kw_datalayout,
     kw_volatile,
+    kw_signed,
+    kw_unsigned,
+    kw_exact,
     kw_align,
     kw_addrspace,
     kw_section,
index bc1eba0..95276b1 100644 (file)
@@ -20,6 +20,7 @@
 #include "llvm/LLVMContext.h"
 #include "llvm/MDNode.h"
 #include "llvm/Module.h"
+#include "llvm/Operator.h"
 #include "llvm/AutoUpgrade.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
@@ -747,6 +748,18 @@ bool BitcodeReader::ResolveGlobalAndAliasInits() {
   return false;
 }
 
+static void SetOptimizationFlags(Value *V, uint64_t Flags) {
+  if (OverflowingBinaryOperator *OBO =
+        dyn_cast<OverflowingBinaryOperator>(V)) {
+    if (Flags & (1 << bitc::OBO_NO_SIGNED_OVERFLOW))
+      OBO->setHasNoSignedOverflow(true);
+    if (Flags & (1 << bitc::OBO_NO_UNSIGNED_OVERFLOW))
+      OBO->setHasNoUnsignedOverflow(true);
+  } else if (SDivOperator *Div = dyn_cast<SDivOperator>(V)) {
+    if (Flags & (1 << bitc::SDIV_EXACT))
+      Div->setIsExact(true);
+  }
+}
 
 bool BitcodeReader::ParseConstants() {
   if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID))
@@ -778,7 +791,8 @@ bool BitcodeReader::ParseConstants() {
     // Read a record.
     Record.clear();
     Value *V = 0;
-    switch (Stream.ReadRecord(Code, Record)) {
+    unsigned BitCode = Stream.ReadRecord(Code, Record);
+    switch (BitCode) {
     default:  // Default behavior: unknown constant
     case bitc::CST_CODE_UNDEF:     // UNDEF
       V = Context.getUndef(CurTy);
@@ -899,6 +913,8 @@ bool BitcodeReader::ParseConstants() {
         Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy);
         V = Context.getConstantExpr(Opc, LHS, RHS);
       }
+      if (Record.size() >= 4)
+        SetOptimizationFlags(V, Record[3]);
       break;
     }  
     case bitc::CST_CODE_CE_CAST: {  // CE_CAST: [opcode, opty, opval]
@@ -1451,7 +1467,8 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
     // Read a record.
     Record.clear();
     Instruction *I = 0;
-    switch (Stream.ReadRecord(Code, Record)) {
+    unsigned BitCode = Stream.ReadRecord(Code, Record);
+    switch (BitCode) {
     default: // Default behavior: reject
       return Error("Unknown instruction");
     case bitc::FUNC_CODE_DECLAREBLOCKS:     // DECLAREBLOCKS: [nblocks]
@@ -1469,12 +1486,14 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
       Value *LHS, *RHS;
       if (getValueTypePair(Record, OpNum, NextValueNo, LHS) ||
           getValue(Record, OpNum, LHS->getType(), RHS) ||
-          OpNum+1 != Record.size())
+          OpNum+1 > Record.size())
         return Error("Invalid BINOP record");
       
-      int Opc = GetDecodedBinaryOpcode(Record[OpNum], LHS->getType());
+      int Opc = GetDecodedBinaryOpcode(Record[OpNum++], LHS->getType());
       if (Opc == -1) return Error("Invalid BINOP record");
       I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS);
+      if (OpNum < Record.size())
+        SetOptimizationFlags(I, Record[3]);
       break;
     }
     case bitc::FUNC_CODE_INST_CAST: {    // CAST: [opval, opty, destty, castopc]
index d7acd14..d245e5b 100644 (file)
@@ -21,6 +21,7 @@
 #include "llvm/Instructions.h"
 #include "llvm/MDNode.h"
 #include "llvm/Module.h"
+#include "llvm/Operator.h"
 #include "llvm/TypeSymbolTable.h"
 #include "llvm/ValueSymbolTable.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -50,6 +51,7 @@ enum {
   // FUNCTION_BLOCK abbrev id's.
   FUNCTION_INST_LOAD_ABBREV = bitc::FIRST_APPLICATION_ABBREV,
   FUNCTION_INST_BINOP_ABBREV,
+  FUNCTION_INST_BINOP_FLAGS_ABBREV,
   FUNCTION_INST_CAST_ABBREV,
   FUNCTION_INST_RET_VOID_ABBREV,
   FUNCTION_INST_RET_VAL_ABBREV,
@@ -454,6 +456,22 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
   }
 }
 
+static uint64_t GetOptimizationFlags(const Value *V) {
+  uint64_t Flags = 0;
+
+  if (const OverflowingBinaryOperator *OBO =
+        dyn_cast<OverflowingBinaryOperator>(V)) {
+    if (OBO->hasNoSignedOverflow())
+      Flags |= 1 << bitc::OBO_NO_SIGNED_OVERFLOW;
+    if (OBO->hasNoUnsignedOverflow())
+      Flags |= 1 << bitc::OBO_NO_UNSIGNED_OVERFLOW;
+  } else if (const SDivOperator *Div = dyn_cast<SDivOperator>(V)) {
+    if (Div->isExact())
+      Flags |= 1 << bitc::SDIV_EXACT;
+  }
+
+  return Flags;
+}
 
 static void WriteConstants(unsigned FirstVal, unsigned LastVal,
                            const ValueEnumerator &VE,
@@ -641,6 +659,9 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal,
           Record.push_back(GetEncodedBinaryOpcode(CE->getOpcode()));
           Record.push_back(VE.getValueID(C->getOperand(0)));
           Record.push_back(VE.getValueID(C->getOperand(1)));
+          uint64_t Flags = GetOptimizationFlags(CE);
+          if (Flags != 0)
+            Record.push_back(Flags);
         }
         break;
       case Instruction::GetElementPtr:
@@ -778,6 +799,12 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
         AbbrevToUse = FUNCTION_INST_BINOP_ABBREV;
       Vals.push_back(VE.getValueID(I.getOperand(1)));
       Vals.push_back(GetEncodedBinaryOpcode(I.getOpcode()));
+      uint64_t Flags = GetOptimizationFlags(&I);
+      if (Flags != 0) {
+        if (AbbrevToUse == FUNCTION_INST_BINOP_ABBREV)
+          AbbrevToUse = FUNCTION_INST_BINOP_FLAGS_ABBREV;
+        Vals.push_back(Flags);
+      }
     }
     break;
 
@@ -1225,6 +1252,17 @@ static void WriteBlockInfo(const ValueEnumerator &VE, BitstreamWriter &Stream) {
                                    Abbv) != FUNCTION_INST_BINOP_ABBREV)
       llvm_unreachable("Unexpected abbrev ordering!");
   }
+  { // INST_BINOP_FLAGS abbrev for FUNCTION_BLOCK.
+    BitCodeAbbrev *Abbv = new BitCodeAbbrev();
+    Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_BINOP));
+    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LHS
+    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // RHS
+    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc
+    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7)); // flags
+    if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID,
+                                   Abbv) != FUNCTION_INST_BINOP_FLAGS_ABBREV)
+      llvm_unreachable("Unexpected abbrev ordering!");
+  }
   { // INST_CAST abbrev for FUNCTION_BLOCK.
     BitCodeAbbrev *Abbv = new BitCodeAbbrev();
     Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_CAST));
index d5f211b..a091a93 100644 (file)
@@ -23,6 +23,7 @@
 #include "llvm/InlineAsm.h"
 #include "llvm/Instruction.h"
 #include "llvm/Instructions.h"
+#include "llvm/Operator.h"
 #include "llvm/MDNode.h"
 #include "llvm/Module.h"
 #include "llvm/ValueSymbolTable.h"
@@ -851,6 +852,19 @@ static void WriteMDNodes(raw_ostream &Out, TypePrinting &TypePrinter,
   }
 }
 
+static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
+  if (const OverflowingBinaryOperator *OBO =
+        dyn_cast<OverflowingBinaryOperator>(U)) {
+    if (OBO->hasNoUnsignedOverflow())
+      Out << "unsigned ";
+    if (OBO->hasNoSignedOverflow())
+      Out << "signed ";
+  } else if (const SDivOperator *Div = dyn_cast<SDivOperator>(U)) {
+    if (Div->isExact())
+      Out << "exact ";
+  }
+}
+
 static void WriteConstantInt(raw_ostream &Out, const Constant *CV,
                              TypePrinting &TypePrinter, SlotTracker *Machine) {
   if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
@@ -1062,6 +1076,7 @@ static void WriteConstantInt(raw_ostream &Out, const Constant *CV,
   }
 
   if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) {
+    WriteOptimizationInfo(Out, CE);
     Out << CE->getOpcodeName();
     if (CE->isCompare())
       Out << ' ' << getPredicateText(CE->getPredicate());
@@ -1682,6 +1697,9 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
     Out << "tail ";
   }
 
+  // Print out optimization information.
+  WriteOptimizationInfo(Out, &I);
+
   // Print out the opcode...
   Out << I.getOpcodeName();
 
diff --git a/test/Assembler/flags-plain.ll b/test/Assembler/flags-plain.ll
new file mode 100644 (file)
index 0000000..148d02f
--- /dev/null
@@ -0,0 +1,23 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+@addr = external global i64
+
+define i64 @add_plain_ce() {
+; CHECK: ret i64 add (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 add (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @sub_plain_ce() {
+; CHECK: ret i64 sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @mul_plain_ce() {
+; CHECK: ret i64 mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @sdiv_plain_ce() {
+; CHECK: ret i64 sdiv (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 sdiv (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
diff --git a/test/Assembler/flags-reversed.ll b/test/Assembler/flags-reversed.ll
new file mode 100644 (file)
index 0000000..b63ac84
--- /dev/null
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+@addr = external global i64
+
+define i64 @add_both_reversed_ce() {
+; CHECK: ret i64 unsigned signed add (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 signed unsigned add (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @sub_both_reversed_ce() {
+; CHECK: ret i64 unsigned signed sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 signed unsigned sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @mul_both_reversed_ce() {
+; CHECK: ret i64 unsigned signed mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 signed unsigned mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
diff --git a/test/Assembler/flags-signed.ll b/test/Assembler/flags-signed.ll
new file mode 100644 (file)
index 0000000..136dd57
--- /dev/null
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+@addr = external global i64
+
+define i64 @add_signed_ce() {
+; CHECK: ret i64 signed add (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 signed add (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @sub_signed_ce() {
+; CHECK: ret i64 signed sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 signed sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @mul_signed_ce() {
+; CHECK: ret i64 signed mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 signed mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
diff --git a/test/Assembler/flags-unsigned.ll b/test/Assembler/flags-unsigned.ll
new file mode 100644 (file)
index 0000000..1526db0
--- /dev/null
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+@addr = external global i64
+
+define i64 @add_unsigned_ce() {
+; CHECK: ret i64 unsigned add (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 unsigned add (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @sub_unsigned_ce() {
+; CHECK: ret i64 unsigned sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 unsigned sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @mul_unsigned_ce() {
+; CHECK: ret i64 unsigned mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 unsigned mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
diff --git a/test/Assembler/flags.ll b/test/Assembler/flags.ll
new file mode 100644 (file)
index 0000000..317bc0c
--- /dev/null
@@ -0,0 +1,125 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+@addr = external global i64
+
+define i64 @add_signed(i64 %x, i64 %y) {
+; CHECK: %z = signed add i64 %x, %y
+       %z = signed add i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @sub_signed(i64 %x, i64 %y) {
+; CHECK: %z = signed sub i64 %x, %y
+       %z = signed sub i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @mul_signed(i64 %x, i64 %y) {
+; CHECK: %z = signed mul i64 %x, %y
+       %z = signed mul i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @add_unsigned(i64 %x, i64 %y) {
+; CHECK: %z = unsigned add i64 %x, %y
+       %z = unsigned add i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @sub_unsigned(i64 %x, i64 %y) {
+; CHECK: %z = unsigned sub i64 %x, %y
+       %z = unsigned sub i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @mul_unsigned(i64 %x, i64 %y) {
+; CHECK: %z = unsigned mul i64 %x, %y
+       %z = unsigned mul i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @add_plain(i64 %x, i64 %y) {
+; CHECK: %z = add i64 %x, %y
+       %z = add i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @sub_plain(i64 %x, i64 %y) {
+; CHECK: %z = sub i64 %x, %y
+       %z = sub i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @mul_plain(i64 %x, i64 %y) {
+; CHECK: %z = mul i64 %x, %y
+       %z = mul i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @add_both(i64 %x, i64 %y) {
+; CHECK: %z = unsigned signed add i64 %x, %y
+       %z = unsigned signed add i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @sub_both(i64 %x, i64 %y) {
+; CHECK: %z = unsigned signed sub i64 %x, %y
+       %z = unsigned signed sub i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @mul_both(i64 %x, i64 %y) {
+; CHECK: %z = unsigned signed mul i64 %x, %y
+       %z = unsigned signed mul i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @add_both_reversed(i64 %x, i64 %y) {
+; CHECK: %z = unsigned signed add i64 %x, %y
+       %z = signed unsigned add i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @sub_both_reversed(i64 %x, i64 %y) {
+; CHECK: %z = unsigned signed sub i64 %x, %y
+       %z = signed unsigned sub i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @mul_both_reversed(i64 %x, i64 %y) {
+; CHECK: %z = unsigned signed mul i64 %x, %y
+       %z = signed unsigned mul i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @sdiv_exact(i64 %x, i64 %y) {
+; CHECK: %z = exact sdiv i64 %x, %y
+       %z = exact sdiv i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @sdiv_plain(i64 %x, i64 %y) {
+; CHECK: %z = sdiv i64 %x, %y
+       %z = sdiv i64 %x, %y
+       ret i64 %z
+}
+
+define i64 @add_both_ce() {
+; CHECK: ret i64 unsigned signed add (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 signed unsigned add (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @sub_both_ce() {
+; CHECK: ret i64 unsigned signed sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 signed unsigned sub (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @mul_both_ce() {
+; CHECK: ret i64 unsigned signed mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 unsigned signed mul (i64 ptrtoint (i64* @addr to i64), i64 91)
+}
+
+define i64 @sdiv_exact_ce() {
+; CHECK: ret i64 exact sdiv (i64 ptrtoint (i64* @addr to i64), i64 91)
+       ret i64 exact sdiv (i64 ptrtoint (i64* @addr to i64), i64 91)
+}