[llvm] e858f51 - [InstCombine] Remove assumptions about int having 32 bits
Martin Sebor via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 16 14:36:20 PDT 2022
Author: Martin Sebor
Date: 2022-08-16T15:35:08-06:00
New Revision: e858f5120da77f46a6676c6fd63ccbbb83b23d2d
URL: https://github.com/llvm/llvm-project/commit/e858f5120da77f46a6676c6fd63ccbbb83b23d2d
DIFF: https://github.com/llvm/llvm-project/commit/e858f5120da77f46a6676c6fd63ccbbb83b23d2d.diff
LOG: [InstCombine] Remove assumptions about int having 32 bits
Reviewed By: bjope
Differential Revision: https://reviews.llvm.org/D131731
Added:
llvm/test/Transforms/InstCombine/ffs-i16.ll
llvm/test/Transforms/InstCombine/fls-i16.ll
llvm/test/Transforms/InstCombine/isascii-i16.ll
llvm/test/Transforms/InstCombine/isdigit-i16.ll
llvm/test/Transforms/InstCombine/printf-i16.ll
llvm/test/Transforms/InstCombine/puts-i16.ll
Modified:
llvm/lib/Transforms/Utils/BuildLibCalls.cpp
llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index 048f132f174b..b15e14b93ea8 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -1756,22 +1756,19 @@ Value *llvm::emitBinaryFloatFnCall(Value *Op1, Value *Op2,
return emitBinaryFloatFnCallHelper(Op1, Op2, TheLibFunc, Name, B, Attrs, TLI);
}
+// Emit a call to putchar(int) with Char as the argument. Char must have
+// the same precision as int, which need not be 32 bits.
Value *llvm::emitPutChar(Value *Char, IRBuilderBase &B,
const TargetLibraryInfo *TLI) {
Module *M = B.GetInsertBlock()->getModule();
if (!isLibFuncEmittable(M, TLI, LibFunc_putchar))
return nullptr;
+ Type *Ty = Char->getType();
StringRef PutCharName = TLI->getName(LibFunc_putchar);
- FunctionCallee PutChar = getOrInsertLibFunc(M, *TLI, LibFunc_putchar,
- B.getInt32Ty(), B.getInt32Ty());
+ FunctionCallee PutChar = getOrInsertLibFunc(M, *TLI, LibFunc_putchar, Ty, Ty);
inferNonMandatoryLibFuncAttrs(M, PutCharName, *TLI);
- CallInst *CI = B.CreateCall(PutChar,
- B.CreateIntCast(Char,
- B.getInt32Ty(),
- /*isSigned*/true,
- "chari"),
- PutCharName);
+ CallInst *CI = B.CreateCall(PutChar, Char, PutCharName);
if (const Function *F =
dyn_cast<Function>(PutChar.getCallee()->stripPointerCasts()))
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 3552215502c7..30f95cddff73 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -2550,21 +2550,24 @@ void LibCallSimplifier::classifyArgUse(
//===----------------------------------------------------------------------===//
Value *LibCallSimplifier::optimizeFFS(CallInst *CI, IRBuilderBase &B) {
- // ffs(x) -> x != 0 ? (i32)llvm.cttz(x)+1 : 0
+ // All variants of ffs return int which need not be 32 bits wide.
+ // ffs{,l,ll}(x) -> x != 0 ? (int)llvm.cttz(x)+1 : 0
+ Type *RetType = CI->getType();
Value *Op = CI->getArgOperand(0);
Type *ArgType = Op->getType();
Function *F = Intrinsic::getDeclaration(CI->getCalledFunction()->getParent(),
Intrinsic::cttz, ArgType);
Value *V = B.CreateCall(F, {Op, B.getTrue()}, "cttz");
V = B.CreateAdd(V, ConstantInt::get(V->getType(), 1));
- V = B.CreateIntCast(V, B.getInt32Ty(), false);
+ V = B.CreateIntCast(V, RetType, false);
Value *Cond = B.CreateICmpNE(Op, Constant::getNullValue(ArgType));
- return B.CreateSelect(Cond, V, B.getInt32(0));
+ return B.CreateSelect(Cond, V, ConstantInt::get(RetType, 0));
}
Value *LibCallSimplifier::optimizeFls(CallInst *CI, IRBuilderBase &B) {
- // fls(x) -> (i32)(sizeInBits(x) - llvm.ctlz(x, false))
+ // All variants of fls return int which need not be 32 bits wide.
+ // fls{,l,ll}(x) -> (int)(sizeInBits(x) - llvm.ctlz(x, false))
Value *Op = CI->getArgOperand(0);
Type *ArgType = Op->getType();
Function *F = Intrinsic::getDeclaration(CI->getCalledFunction()->getParent(),
@@ -2587,15 +2590,17 @@ Value *LibCallSimplifier::optimizeAbs(CallInst *CI, IRBuilderBase &B) {
Value *LibCallSimplifier::optimizeIsDigit(CallInst *CI, IRBuilderBase &B) {
// isdigit(c) -> (c-'0') <u 10
Value *Op = CI->getArgOperand(0);
- Op = B.CreateSub(Op, B.getInt32('0'), "isdigittmp");
- Op = B.CreateICmpULT(Op, B.getInt32(10), "isdigit");
+ Type *ArgType = Op->getType();
+ Op = B.CreateSub(Op, ConstantInt::get(ArgType, '0'), "isdigittmp");
+ Op = B.CreateICmpULT(Op, ConstantInt::get(ArgType, 10), "isdigit");
return B.CreateZExt(Op, CI->getType());
}
Value *LibCallSimplifier::optimizeIsAscii(CallInst *CI, IRBuilderBase &B) {
// isascii(c) -> c <u 128
Value *Op = CI->getArgOperand(0);
- Op = B.CreateICmpULT(Op, B.getInt32(128), "isascii");
+ Type *ArgType = Op->getType();
+ Op = B.CreateICmpULT(Op, ConstantInt::get(ArgType, 128), "isascii");
return B.CreateZExt(Op, CI->getType());
}
@@ -2701,9 +2706,15 @@ Value *LibCallSimplifier::optimizePrintFString(CallInst *CI, IRBuilderBase &B) {
if (!CI->use_empty())
return nullptr;
+ Type *IntTy = CI->getType();
// printf("x") -> putchar('x'), even for "%" and "%%".
- if (FormatStr.size() == 1 || FormatStr == "%%")
- return copyFlags(*CI, emitPutChar(B.getInt32(FormatStr[0]), B, TLI));
+ if (FormatStr.size() == 1 || FormatStr == "%%") {
+ // Convert the character to unsigned char before passing it to putchar
+ // to avoid host-specific sign extension in the IR. Putchar converts
+ // it to unsigned char regardless.
+ Value *IntChar = ConstantInt::get(IntTy, (unsigned char)FormatStr[0]);
+ return copyFlags(*CI, emitPutChar(IntChar, B, TLI));
+ }
// Try to remove call or emit putchar/puts.
if (FormatStr == "%s" && CI->arg_size() > 1) {
@@ -2714,8 +2725,13 @@ Value *LibCallSimplifier::optimizePrintFString(CallInst *CI, IRBuilderBase &B) {
if (OperandStr.empty())
return (Value *)CI;
// printf("%s", "a") --> putchar('a')
- if (OperandStr.size() == 1)
- return copyFlags(*CI, emitPutChar(B.getInt32(OperandStr[0]), B, TLI));
+ if (OperandStr.size() == 1) {
+ // Convert the character to unsigned char before passing it to putchar
+ // to avoid host-specific sign extension in the IR. Putchar converts
+ // it to unsigned char regardless.
+ Value *IntChar = ConstantInt::get(IntTy, (unsigned char)OperandStr[0]);
+ return copyFlags(*CI, emitPutChar(IntChar, B, TLI));
+ }
// printf("%s", str"\n") --> puts(str)
if (OperandStr.back() == '\n') {
OperandStr = OperandStr.drop_back();
@@ -2738,8 +2754,12 @@ Value *LibCallSimplifier::optimizePrintFString(CallInst *CI, IRBuilderBase &B) {
// Optimize specific format strings.
// printf("%c", chr) --> putchar(chr)
if (FormatStr == "%c" && CI->arg_size() > 1 &&
- CI->getArgOperand(1)->getType()->isIntegerTy())
- return copyFlags(*CI, emitPutChar(CI->getArgOperand(1), B, TLI));
+ CI->getArgOperand(1)->getType()->isIntegerTy()) {
+ // Convert the argument to the type expected by putchar, i.e., int, which
+ // need not be 32 bits wide but which is the same as printf's return type.
+ Value *IntChar = B.CreateIntCast(CI->getArgOperand(1), IntTy, false);
+ return copyFlags(*CI, emitPutChar(IntChar, B, TLI));
+ }
// printf("%s\n", str) --> puts(str)
if (FormatStr == "%s\n" && CI->arg_size() > 1 &&
@@ -3192,8 +3212,12 @@ Value *LibCallSimplifier::optimizePuts(CallInst *CI, IRBuilderBase &B) {
// Check for a constant string.
// puts("") -> putchar('\n')
StringRef Str;
- if (getConstantStringInfo(CI->getArgOperand(0), Str) && Str.empty())
- return copyFlags(*CI, emitPutChar(B.getInt32('\n'), B, TLI));
+ if (getConstantStringInfo(CI->getArgOperand(0), Str) && Str.empty()) {
+ // putchar takes an argument of the same type as puts returns, i.e.,
+ // int, which need not be 32 bits wide.
+ Type *IntTy = CI->getType();
+ return copyFlags(*CI, emitPutChar(ConstantInt::get(IntTy, '\n'), B, TLI));
+ }
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/ffs-i16.ll b/llvm/test/Transforms/InstCombine/ffs-i16.ll
new file mode 100644
index 000000000000..0984724511ef
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/ffs-i16.ll
@@ -0,0 +1,35 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+;
+; Test that the ffs library call simplifier works correctly even for
+; targets with 16-bit int.
+;
+; RUN: opt < %s -mtriple=avr-linux -passes=instcombine -S | FileCheck %s
+; RUN: opt < %s -mtriple=msp430-linux -passes=instcombine -S | FileCheck %s
+
+declare i16 @ffs(i16)
+
+declare void @sink(i16)
+
+
+define void @fold_ffs(i16 %x) {
+; CHECK-LABEL: @fold_ffs(
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 1)
+; CHECK-NEXT: [[CTTZ:%.*]] = call i16 @llvm.cttz.i16(i16 [[X:%.*]], i1 true), !range [[RNG0:![0-9]+]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i16 [[CTTZ]], 1
+; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i16 [[X]], 0
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[DOTNOT]], i16 0, i16 [[TMP1]]
+; CHECK-NEXT: call void @sink(i16 [[TMP2]])
+; CHECK-NEXT: ret void
+;
+ %n0 = call i16 @ffs(i16 0)
+ call void @sink(i16 %n0)
+
+ %n1 = call i16 @ffs(i16 1)
+ call void @sink(i16 %n1)
+
+ %nx = call i16 @ffs(i16 %x)
+ call void @sink(i16 %nx)
+
+ ret void
+}
diff --git a/llvm/test/Transforms/InstCombine/fls-i16.ll b/llvm/test/Transforms/InstCombine/fls-i16.ll
new file mode 100644
index 000000000000..83f3dbd33946
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/fls-i16.ll
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+;
+; Test that the fls library call simplifier works correctly even for
+; targets with 16-bit int. Although fls is available on a number of
+; targets it's supported (hardcoded as available) only on FreeBSD.
+;
+; RUN: opt < %s -mtriple=avr-freebsd -passes=instcombine -S | FileCheck %s
+; RUN: opt < %s -mtriple=msp430-freebsd -passes=instcombine -S | FileCheck %s
+
+declare i16 @fls(i16)
+
+declare void @sink(i16)
+
+
+define void @fold_fls(i16 %x) {
+; CHECK-LABEL: @fold_fls(
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 1)
+; CHECK-NEXT: [[CTLZ:%.*]] = call i16 @llvm.ctlz.i16(i16 [[X:%.*]], i1 false), !range [[RNG0:![0-9]+]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub nuw nsw i16 16, [[CTLZ]]
+; CHECK-NEXT: call void @sink(i16 [[TMP1]])
+; CHECK-NEXT: ret void
+;
+ %n0 = call i16 @fls(i16 0)
+ call void @sink(i16 %n0)
+
+ %n1 = call i16 @fls(i16 1)
+ call void @sink(i16 %n1)
+
+ %nx = call i16 @fls(i16 %x)
+ call void @sink(i16 %nx)
+
+ ret void
+}
diff --git a/llvm/test/Transforms/InstCombine/isascii-i16.ll b/llvm/test/Transforms/InstCombine/isascii-i16.ll
new file mode 100644
index 000000000000..131906d798a3
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/isascii-i16.ll
@@ -0,0 +1,57 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the isascii library call simplifier works correctly even for
+; targets with 16-bit int.
+;
+; RUN: opt < %s -mtriple=avr-freebsd -passes=instcombine -S | FileCheck %s
+; RUN: opt < %s -mtriple=msp430-linux -passes=instcombine -S | FileCheck %s
+
+declare i16 @isascii(i16)
+
+declare void @sink(i16)
+
+
+define void @fold_isascii(i16 %c) {
+; CHECK-LABEL: @fold_isascii(
+; CHECK-NEXT: call void @sink(i16 1)
+; CHECK-NEXT: call void @sink(i16 1)
+; CHECK-NEXT: call void @sink(i16 1)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: [[ISASCII:%.*]] = icmp ult i16 [[C:%.*]], 128
+; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[ISASCII]] to i16
+; CHECK-NEXT: call void @sink(i16 [[TMP1]])
+; CHECK-NEXT: ret void
+;
+ %i0 = call i16 @isascii(i16 0)
+ call void @sink(i16 %i0)
+
+ %i1 = call i16 @isascii(i16 1)
+ call void @sink(i16 %i1)
+
+ %i127 = call i16 @isascii(i16 127)
+ call void @sink(i16 %i127)
+
+ %i128 = call i16 @isascii(i16 128)
+ call void @sink(i16 %i128)
+
+ %i255 = call i16 @isascii(i16 255)
+ call void @sink(i16 %i255)
+
+ %i256 = call i16 @isascii(i16 256)
+ call void @sink(i16 %i256)
+
+ ; Fold isascii(INT_MAX) to 0. The call is valid with all int values.
+ %imax = call i16 @isascii(i16 32767)
+ call void @sink(i16 %imax)
+
+ %uimax = call i16 @isascii(i16 65535)
+ call void @sink(i16 %uimax)
+
+ %ic = call i16 @isascii(i16 %c)
+ call void @sink(i16 %ic)
+
+ ret void
+}
diff --git a/llvm/test/Transforms/InstCombine/isdigit-i16.ll b/llvm/test/Transforms/InstCombine/isdigit-i16.ll
new file mode 100644
index 000000000000..35c58c282a8a
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/isdigit-i16.ll
@@ -0,0 +1,82 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the isdigit library call simplifier works correctly even for
+; targets with 16-bit int.
+;
+; RUN: opt < %s -mtriple=avr-linux -passes=instcombine -S | FileCheck %s
+; RUN: opt < %s -mtriple=msp430-freebsd -passes=instcombine -S | FileCheck %s
+
+declare i16 @isdigit(i16)
+
+declare void @sink(i16)
+
+define void @fold_isdigit(i16 %c) {
+; CHECK-LABEL: @fold_isdigit(
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 1)
+; CHECK-NEXT: call void @sink(i16 1)
+; CHECK-NEXT: call void @sink(i16 1)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: call void @sink(i16 0)
+; CHECK-NEXT: [[ISDIGITTMP:%.*]] = add i16 [[C:%.*]], -48
+; CHECK-NEXT: [[ISDIGIT:%.*]] = icmp ult i16 [[ISDIGITTMP]], 10
+; CHECK-NEXT: [[TMP1:%.*]] = zext i1 [[ISDIGIT]] to i16
+; CHECK-NEXT: call void @sink(i16 [[TMP1]])
+; CHECK-NEXT: ret void
+;
+ %i0 = call i16 @isdigit(i16 0)
+ call void @sink(i16 %i0)
+
+ %i1 = call i16 @isdigit(i16 1)
+ call void @sink(i16 %i1)
+
+ ; Fold isdigit('/') to 0.
+ %i47 = call i16 @isdigit(i16 47)
+ call void @sink(i16 %i47)
+
+; Fold isdigit('0') to 1.
+ %i48 = call i16 @isdigit(i16 48)
+ call void @sink(i16 %i48)
+
+ ; Fold isdigit('1') to 1.
+ %i49 = call i16 @isdigit(i16 49)
+ call void @sink(i16 %i49)
+
+ ; Fold isdigit('9') to 1.
+ %i57 = call i16 @isdigit(i16 57)
+ call void @sink(i16 %i57)
+
+ ; Fold isdigit(':') to 0.
+ %i58 = call i16 @isdigit(i16 58)
+ call void @sink(i16 %i58)
+
+ %i127 = call i16 @isdigit(i16 127)
+ call void @sink(i16 %i127)
+
+ %i128 = call i16 @isdigit(i16 128)
+ call void @sink(i16 %i128)
+
+ %i255 = call i16 @isdigit(i16 255)
+ call void @sink(i16 %i255)
+
+ ; Fold isdigit(256) to 0. The argument is required to be representable
+ ; in unsigned char but it's a common mistake to call the function with
+ ; other arguments and it's arguably safer to fold such calls than to
+ ; let the library call return an arbitrary value or crash.
+ %i256 = call i16 @isdigit(i16 256)
+ call void @sink(i16 %i256)
+
+ ; Same as above.
+ %imax = call i16 @isdigit(i16 32767)
+ call void @sink(i16 %imax)
+
+ %ic = call i16 @isdigit(i16 %c)
+ call void @sink(i16 %ic)
+
+ ret void
+}
diff --git a/llvm/test/Transforms/InstCombine/printf-i16.ll b/llvm/test/Transforms/InstCombine/printf-i16.ll
new file mode 100644
index 000000000000..96609a87889d
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/printf-i16.ll
@@ -0,0 +1,72 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+;
+; RUN: opt < %s -mtriple=avr-freebsd -passes=instcombine -S | FileCheck %s
+; RUN: opt < %s -mtriple=msp430-linux -passes=instcombine -S | FileCheck %s
+;
+; Verify that the puts to putchar transformation works correctly even for
+; targets with 16-bit int.
+
+declare i16 @putchar(i16)
+declare i16 @puts(i8*)
+
+ at s1 = constant [2 x i8] c"\01\00"
+ at s7f = constant [2 x i8] c"\7f\00"
+ at s80 = constant [2 x i8] c"\80\00"
+ at sff = constant [2 x i8] c"\ff\00"
+
+ at pcnt_c = constant [3 x i8] c"%c\00"
+ at pcnt_s = constant [3 x i8] c"%s\00"
+
+declare i16 @printf(i8*, ...)
+
+; Verfify that the three printf to putchar transformations all result
+; in the same output for calls with equivalent arguments.
+
+define void @xform_printf(i8 %c8, i16 %c16) {
+; CHECK-LABEL: @xform_printf(
+; CHECK-NEXT: [[PUTCHAR:%.*]] = call i16 @putchar(i16 1)
+; CHECK-NEXT: [[PUTCHAR1:%.*]] = call i16 @putchar(i16 1)
+; CHECK-NEXT: [[PUTCHAR2:%.*]] = call i16 @putchar(i16 1)
+; CHECK-NEXT: [[PUTCHAR3:%.*]] = call i16 @putchar(i16 127)
+; CHECK-NEXT: [[PUTCHAR4:%.*]] = call i16 @putchar(i16 127)
+; CHECK-NEXT: [[PUTCHAR5:%.*]] = call i16 @putchar(i16 127)
+; CHECK-NEXT: [[PUTCHAR6:%.*]] = call i16 @putchar(i16 128)
+; CHECK-NEXT: [[PUTCHAR7:%.*]] = call i16 @putchar(i16 128)
+; CHECK-NEXT: [[PUTCHAR8:%.*]] = call i16 @putchar(i16 128)
+; CHECK-NEXT: [[PUTCHAR9:%.*]] = call i16 @putchar(i16 255)
+; CHECK-NEXT: [[PUTCHAR10:%.*]] = call i16 @putchar(i16 255)
+; CHECK-NEXT: [[PUTCHAR11:%.*]] = call i16 @putchar(i16 255)
+; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[C8:%.*]] to i16
+; CHECK-NEXT: [[PUTCHAR12:%.*]] = call i16 @putchar(i16 [[TMP1]])
+; CHECK-NEXT: [[PUTCHAR13:%.*]] = call i16 @putchar(i16 [[C16:%.*]])
+; CHECK-NEXT: ret void
+;
+ %ppcnt_c = getelementptr [3 x i8], [3 x i8]* @pcnt_c, i32 0, i32 0
+ %ppcnt_s = getelementptr [3 x i8], [3 x i8]* @pcnt_s, i32 0, i32 0
+
+ %ps1 = getelementptr [2 x i8], [2 x i8]* @s1, i32 0, i32 0
+ call i16 (i8*, ...) @printf(i8* %ps1)
+ call i16 (i8*, ...) @printf(i8* %ppcnt_c, i16 1)
+ call i16 (i8*, ...) @printf(i8* %ppcnt_s, i8* %ps1)
+
+ %ps7f = getelementptr [2 x i8], [2 x i8]* @s7f, i32 0, i32 0
+ call i16 (i8*, ...) @printf(i8* %ps7f)
+ call i16 (i8*, ...) @printf(i8* %ppcnt_c, i16 127)
+ call i16 (i8*, ...) @printf(i8* %ppcnt_s, i8* %ps7f)
+
+ %ps80 = getelementptr [2 x i8], [2 x i8]* @s80, i32 0, i32 0
+ call i16 (i8*, ...) @printf(i8* %ps80)
+ call i16 (i8*, ...) @printf(i8* %ppcnt_c, i16 128)
+ call i16 (i8*, ...) @printf(i8* %ppcnt_s, i8* %ps80)
+
+ %psff = getelementptr [2 x i8], [2 x i8]* @sff, i32 0, i32 0
+ call i16 (i8*, ...) @printf(i8* %psff)
+ call i16 (i8*, ...) @printf(i8* %ppcnt_c, i16 255)
+ call i16 (i8*, ...) @printf(i8* %ppcnt_s, i8* %psff)
+
+; The i8 argument to printf can be either zero-extended or sign-extended
+; when passed to putchar which then converts it to unsigned char.
+ call i16 (i8*, ...) @printf(i8* %ppcnt_c, i8 %c8)
+ call i16 (i8*, ...) @printf(i8* %ppcnt_c, i16 %c16)
+ ret void
+}
diff --git a/llvm/test/Transforms/InstCombine/puts-i16.ll b/llvm/test/Transforms/InstCombine/puts-i16.ll
new file mode 100644
index 000000000000..fb79fc59c95c
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/puts-i16.ll
@@ -0,0 +1,24 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+;
+; RUN: opt < %s -mtriple=avr-linux -passes=instcombine -S | FileCheck %s
+; RUN: opt < %s -mtriple=msp430-freebsd -passes=instcombine -S | FileCheck %s
+;
+; Test that the puts to putchar transformation works correctly even for
+; targets with 16-bit int.
+
+declare i16 @putchar(i16)
+declare i16 @puts(i8*)
+
+ at empty = constant [1 x i8] c"\00"
+
+define void @xform_puts(i16 %c) {
+; CHECK-LABEL: @xform_puts(
+; CHECK-NEXT: [[PUTCHAR:%.*]] = call i16 @putchar(i16 10)
+; CHECK-NEXT: ret void
+;
+; Transform puts("") to putchar("\n").
+ %s = getelementptr [1 x i8], [1 x i8]* @empty, i32 0, i32 0
+ call i16 @puts(i8* %s)
+
+ ret void
+}
More information about the llvm-commits
mailing list