diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index 98cb6986..689d21a1 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -2232,6 +2232,15 @@ static void defineThreadFence(raw_ostream &Out) { << "#endif\n\n"; } +static void defineTrap(raw_ostream &Out) { + Out << "extern void abort(void);\n" + << "#if defined(__GNUC__)\n" + << "extern void __builtin_trap(void);\n" + << "#else\n" + << "#define __builtin_trap() abort()\n" + << "#endif\n\n"; +} + /// FindStaticTors - Given a static ctor/dtor list, unpack its contents into /// the StaticTors set. static void FindStaticTors(GlobalVariable *GV, @@ -2348,6 +2357,8 @@ void CWriter::generateCompilerSpecificCode(raw_ostream &Out, defineThreadFence(Out); if (headerIncStackSaveRestore()) defineStackSaveRestore(Out); + if (headerIncTrap()) + defineTrap(Out); } bool CWriter::doInitialization(Module &M) { @@ -2573,6 +2584,8 @@ void CWriter::generateHeader(Module &M) { case Intrinsic::trunc: case Intrinsic::umax: case Intrinsic::umin: + case Intrinsic::smin: + case Intrinsic::smax: case Intrinsic::is_constant: intrinsicsToDefine.push_back(&*I); continue; @@ -4485,6 +4498,8 @@ void CWriter::printIntrinsicDefinition(FunctionType *funT, unsigned Opcode, case Intrinsic::sadd_with_overflow: case Intrinsic::ssub_with_overflow: case Intrinsic::smul_with_overflow: + case Intrinsic::smin: + case Intrinsic::smax: isSigned = true; break; } @@ -4601,47 +4616,63 @@ void CWriter::printIntrinsicDefinition(FunctionType *funT, unsigned Opcode, case Intrinsic::bswap: cwriter_assert(retT == elemT); - Out << " LLVMFlipAllBits(8 * sizeof(a), &a, &r);\n"; + cwriter_assert(!isa(retT)); + cwriter_assert(elemT->getIntegerBitWidth() <= 64); + Out << " int i;\n"; + Out << " r = 0;\n"; + Out << " int bitwidth = " << elemT->getIntegerBitWidth() << ";\n"; + Out << " for (i = 0; i < bitwidth/8; i++)\n"; + Out << " r |= ((a >> (i*8)) & 0xff) << (bitwidth - (i+1)*8);\n"; break; case Intrinsic::ctpop: cwriter_assert(retT == elemT); - Out << " r = "; - if (retT->getPrimitiveSizeInBits() > 64) - Out << "llvm_ctor_u128(0, "; - Out << "LLVMCountPopulation(8 * sizeof(a), &a)"; - if (retT->getPrimitiveSizeInBits() > 64) - Out << ")"; - Out << ";\n"; + cwriter_assert(!isa(retT)); + cwriter_assert(elemT->getIntegerBitWidth() <= 64); + Out << " int i;\n"; + Out << " r = 0;\n"; + Out << " int bitwidth = " << elemT->getIntegerBitWidth() << ";\n"; + Out << " for (i = 0; i < bitwidth; i++)\n"; + Out << " if ( (a >> i ) & 1 )\n"; + Out << " r++;\n"; + break; case Intrinsic::ctlz: cwriter_assert(retT == elemT); - Out << " (void)b;\n r = "; - if (retT->getPrimitiveSizeInBits() > 64) - Out << "llvm_ctor_u128(0, "; - Out << "LLVMCountLeadingZeros(8 * sizeof(a), &a)"; - if (retT->getPrimitiveSizeInBits() > 64) - Out << ")"; - Out << ";\n"; + cwriter_assert(!isa(retT)); + cwriter_assert(elemT->getIntegerBitWidth() <= 64); + Out << " int i;\n"; + Out << " r = 0;\n"; + Out << " int bitwidth = " << elemT->getIntegerBitWidth() << ";\n"; + Out << " for (i = bitwidth - 1; i >= 0; i--)\n"; + Out << " if ( ((a >> i ) & 1) == 0 )\n"; + Out << " r++;\n"; + Out << " else\n"; + Out << " break;\n"; break; case Intrinsic::cttz: cwriter_assert(retT == elemT); - Out << " (void)b;\n r = "; - if (retT->getPrimitiveSizeInBits() > 64) - Out << "llvm_ctor_u128(0, "; - Out << "LLVMCountTrailingZeros(8 * sizeof(a), &a)"; - if (retT->getPrimitiveSizeInBits() > 64) - Out << ")"; - Out << ";\n"; + cwriter_assert(!isa(retT)); + cwriter_assert(elemT->getIntegerBitWidth() <= 64); + Out << " int i;\n"; + Out << " r = 0;\n"; + Out << " int bitwidth = " << elemT->getIntegerBitWidth() << ";\n"; + Out << " for (i = 0; i < bitwidth; i++)\n"; + Out << " if ( ((a >> i) & 1) == 0 )\n"; + Out << " r++;\n"; + Out << " else\n"; + Out << " break;\n"; break; case Intrinsic::umax: + case Intrinsic::smax: Out << " r = a > b ? a : b;\n"; break; case Intrinsic::umin: + case Intrinsic::smin: Out << " r = a < b ? a : b;\n"; break; case Intrinsic::is_constant: @@ -4768,6 +4799,8 @@ bool CWriter::lowerIntrinsics(Function &F) { case Intrinsic::dbg_declare: case Intrinsic::umax: case Intrinsic::umin: + case Intrinsic::smin: + case Intrinsic::smax: case Intrinsic::is_constant: // We directly implement these intrinsics break; @@ -5054,6 +5087,10 @@ bool CWriter::visitBuiltinCall(CallInst &I, Intrinsic::ID ID) { Out << " = "; writeOperand(I.getArgOperand(0), ContextCasted); return true; + case Intrinsic::trap: + headerUseTrap(); + Out << "__builtin_trap()"; + return true; // these use the normal function call emission case Intrinsic::sadd_with_overflow: @@ -5080,9 +5117,10 @@ bool CWriter::visitBuiltinCall(CallInst &I, Intrinsic::ID ID) { case Intrinsic::ctpop: case Intrinsic::cttz: case Intrinsic::fmuladd: - case Intrinsic::trap: case Intrinsic::umax: case Intrinsic::umin: + case Intrinsic::smax: + case Intrinsic::smin: case Intrinsic::is_constant: return false; // these use the normal function call emission } diff --git a/lib/Target/CBackend/CBackend.h b/lib/Target/CBackend/CBackend.h index 275e4e1c..2e435a97 100644 --- a/lib/Target/CBackend/CBackend.h +++ b/lib/Target/CBackend/CBackend.h @@ -121,6 +121,7 @@ class CWriter : public FunctionPass, public InstVisitor { bool ConstantFP80Ty : 1; bool ConstantFP128Ty : 1; bool ForceInline : 1; + bool Trap : 1; } UsedHeaders; #define USED_HEADERS_FLAG(Name) \ @@ -155,6 +156,7 @@ class CWriter : public FunctionPass, public InstVisitor { USED_HEADERS_FLAG(ConstantFP80Ty) USED_HEADERS_FLAG(ConstantFP128Ty) USED_HEADERS_FLAG(ForceInline) + USED_HEADERS_FLAG(Trap) llvm::SmallSet FCmpOps; void headerUseFCmpOp(CmpInst::Predicate P); diff --git a/test/ll_tests/test_bitcounts.ll b/test/ll_tests/test_bitcounts.ll new file mode 100644 index 00000000..1ee810be --- /dev/null +++ b/test/ll_tests/test_bitcounts.ll @@ -0,0 +1,69 @@ +declare i64 @llvm.ctpop.i64(i64) +declare i64 @llvm.ctlz.i64(i64, i1) ; i1: is_zero_poison +declare i16 @llvm.ctlz.i16(i16, i1) ; i1: is_zero_poison +declare i64 @llvm.cttz.i64(i64, i1); i1: is_zero_poison> +declare i16 @llvm.cttz.i16(i16, i1); i1: is_zero_poison> + + +define dso_local i32 @main() #0 { +ctpop.1: + %ctpop.1.val = call i64 @llvm.ctpop.i64(i64 18446744073709551615) ; 0xffffffffffffffff + %ctpop.1.ok = icmp eq i64 %ctpop.1.val, 64 + br i1 %ctpop.1.ok, label %ctpop.2, label %error + +ctpop.2: + %ctpop.2.val = call i64 @llvm.ctpop.i64(i64 0) + %ctpop.2.ok = icmp eq i64 %ctpop.2.val, 0 + br i1 %ctpop.2.ok, label %ctpop.3, label %error + +ctpop.3: + %ctpop.3.val = call i64 @llvm.ctpop.i64(i64 181) ; 0b10110101 + %ctpop.3.ok = icmp eq i64 %ctpop.3.val, 5 + br i1 %ctpop.3.ok, label %ctlz.1, label %error + +ctlz.1: + %ctlz.1.val = call i64 @llvm.ctlz.i64(i64 18446744073709551615, i1 0) ; 0xffffffffffffffff + %ctlz.1.ok = icmp eq i64 %ctlz.1.val, 0 + br i1 %ctlz.1.ok, label %ctlz.2, label %error + +ctlz.2: + %ctlz.2.val = call i64 @llvm.ctlz.i64(i64 1, i1 0) + %ctlz.2.ok = icmp eq i64 %ctlz.2.val, 63 + br i1 %ctlz.2.ok, label %ctlz.3, label %error + +ctlz.3: + %ctlz.3.val = call i16 @llvm.ctlz.i16(i16 181, i1 0) ; 0b10110101 + %ctlz.3.ok = icmp eq i16 %ctlz.3.val, 8 + br i1 %ctlz.3.ok, label %cttz.1, label %error + +cttz.1: + %cttz.1.val = call i64 @llvm.cttz.i64(i64 18446744073709551615, i1 0) ; 0xffffffffffffffff + %cttz.1.ok = icmp eq i64 %cttz.1.val, 0 + br i1 %cttz.1.ok, label %cttz.2, label %error + +cttz.2: + %cttz.2.val = call i64 @llvm.cttz.i64(i64 1, i1 0) + %cttz.2.ok = icmp eq i64 %cttz.2.val, 0 + br i1 %cttz.2.ok, label %cttz.3, label %error + +cttz.3: + %cttz.3.val = call i16 @llvm.cttz.i16(i16 180, i1 0) ; 0b10110100 + %cttz.3.ok = icmp eq i16 %cttz.3.val, 2 + br i1 %cttz.3.ok, label %ok, label %error + +ok: + ret i32 6 + +error: + %retVal = phi i32 + [ 20, %ctpop.1 ], + [ 21, %ctpop.2 ], + [ 22, %ctpop.3 ], + [ 23, %ctlz.1 ], + [ 24, %ctlz.2 ], + [ 25, %ctlz.3 ], + [ 26, %cttz.1 ], + [ 27, %cttz.2 ], + [ 28, %cttz.3 ] + ret i32 %retVal +} diff --git a/test/ll_tests/test_bswap.ll b/test/ll_tests/test_bswap.ll new file mode 100644 index 00000000..ffcbe8ff --- /dev/null +++ b/test/ll_tests/test_bswap.ll @@ -0,0 +1,30 @@ +declare i16 @llvm.bswap.i16(i16) +declare i32 @llvm.bswap.i32(i32) +declare i64 @llvm.bswap.i64(i64) + +define dso_local i32 @main() #0 { +bswap.i16: + %bswap.i16.val = call i16 @llvm.bswap.i16(i16 4660) ; 0x1234 + %bswap.i16.ok = icmp eq i16 %bswap.i16.val, 13330 ; 0x3412 + br i1 %bswap.i16.ok, label %bswap.i32, label %error + +bswap.i32: + %bswap.i32.val = call i32 @llvm.bswap.i32(i32 305419896) ; 0x12345678 + %bswap.i32.ok = icmp eq i32 %bswap.i32.val, 2018915346 ; 0x78563412 + br i1 %bswap.i32.ok, label %bswap.i64, label %error + +bswap.i64: + %bswap.i64.val = call i64 @llvm.bswap.i64(i64 1311768467463790320) ; 0x123456789abcdef0 + %bswap.i64.ok = icmp eq i64 %bswap.i64.val, 17356517385562371090 ; 0xf0debc9a78563412 + br i1 %bswap.i64.ok, label %ok, label %error + +ok: + ret i32 6 + +error: + %retVal = phi i32 + [ 20, %bswap.i16 ], + [ 21, %bswap.i32 ], + [ 22, %bswap.i64 ] + ret i32 %retVal +} diff --git a/test/ll_tests/test_min_max_intrinsics.ll b/test/ll_tests/test_min_max_intrinsics.ll new file mode 100644 index 00000000..649448ac --- /dev/null +++ b/test/ll_tests/test_min_max_intrinsics.ll @@ -0,0 +1,38 @@ +declare i64 @llvm.smin.i64(i64, i64) +declare i64 @llvm.smax.i64(i64, i64) +declare i64 @llvm.umin.i64(i64, i64) +declare i64 @llvm.umax.i64(i64, i64) + +define dso_local i32 @main() #0 { +smin.check: + %smin.res = call i64 @llvm.smin.i64(i64 6, i64 -6) + %smin.ok = icmp eq i64 %smin.res, -6 + br i1 %smin.ok, label %smax.check, label %error + +smax.check: + %smax.res = call i64 @llvm.smax.i64(i64 6, i64 -6) + %smax.ok = icmp eq i64 %smax.res, 6 + br i1 %smax.ok, label %umin.check, label %error + +umin.check: + %umin.res = call i64 @llvm.umin.i64(i64 6, i64 -6) + %umin.ok = icmp eq i64 %umin.res, 6 + br i1 %umin.ok, label %umax.check, label %error + +umax.check: + %umax.res = call i64 @llvm.umax.i64(i64 6, i64 -6) + %umax.ok = icmp eq i64 %umax.res, -6 + br i1 %umax.ok, label %ok, label %error + + +ok: + ret i32 6 + +error: + %retVal = phi i32 + [ 20, %smin.check ], + [ 21, %smax.check ], + [ 22, %umin.check ], + [ 23, %umax.check ] + ret i32 %retVal +} diff --git a/test/ll_tests/test_trap.ll b/test/ll_tests/test_trap.ll new file mode 100644 index 00000000..d281c75d --- /dev/null +++ b/test/ll_tests/test_trap.ll @@ -0,0 +1,10 @@ +declare void @llvm.trap() cold noreturn nounwind + +define dso_local i32 @main() #0 { + ret i32 6 +} + +define dso_local void @this_should_not_happen() { + call void @llvm.trap() + unreachable +}