From 0d24145a7bcb6561c18701cfe32ef1fc1496acd7 Mon Sep 17 00:00:00 2001 From: arphaman Date: Thu, 19 Sep 2013 11:16:17 +0100 Subject: added codegen for bit operations --- include/flang/Basic/TokenKinds.def | 29 +++++++++------- lib/Basic/IdentifierTable.cpp | 1 + lib/CodeGen/CGArray.cpp | 6 ++++ lib/CodeGen/CGExprScalar.cpp | 58 +++++++++++++++++++++++++++++++- lib/CodeGen/CGIntrinsic.cpp | 5 +++ lib/CodeGen/CodeGenFunction.h | 3 ++ lib/Parse/ParseExpr.cpp | 2 +- test/CodeGen/Intrinsics/bitops.f95 | 40 ++++++++++++++++++++++ test/CodeGenInAction/arrayOperations.f95 | 6 ++++ test/Sema/Intrinsics/bitops.f95 | 7 ++-- 10 files changed, 138 insertions(+), 19 deletions(-) create mode 100644 test/CodeGen/Intrinsics/bitops.f95 diff --git a/include/flang/Basic/TokenKinds.def b/include/flang/Basic/TokenKinds.def index 8fafd1649e..ea32a81e3e 100644 --- a/include/flang/Basic/TokenKinds.def +++ b/include/flang/Basic/TokenKinds.def @@ -23,6 +23,9 @@ #ifndef FORMAT_SPEC #define FORMAT_SPEC(X, Y) TOK(fs_ ## X) #endif +#ifndef OPERATOR(X,Y) +#define OPERATOR(X,Y) TOK(kw_ ## X) +#endif //===----------------------------------------------------------------------===// // Language keywords. @@ -293,25 +296,25 @@ KEYWORD(STOP , KEYALL) // [3.2.4] R309: Intrinsic Operators // [3.2.4] R713: rel-op -KEYWORD(EQ , KEYALL) -KEYWORD(NE , KEYALL) -KEYWORD(LT , KEYALL) -KEYWORD(LE , KEYALL) -KEYWORD(GT , KEYALL) -KEYWORD(GE , KEYALL) +OPERATOR(EQ , KEYALL) +OPERATOR(NE , KEYALL) +OPERATOR(LT , KEYALL) +OPERATOR(LE , KEYALL) +OPERATOR(GT , KEYALL) +OPERATOR(GE , KEYALL) // [3.2.4] R718: not-op -KEYWORD(NOT , KEYALL) +OPERATOR(NOT , KEYALL) // [3.2.4] R719: and-op -KEYWORD(AND , KEYALL) +OPERATOR(AND , KEYALL) // [3.2.4] R720: or-op -KEYWORD(OR , KEYALL) +OPERATOR(OR , KEYALL) // [3.2.4] R721: equiv-op -KEYWORD(EQV , KEYALL) -KEYWORD(NEQV , KEYALL) +OPERATOR(EQV , KEYALL) +OPERATOR(NEQV , KEYALL) // [4.4.4] R424: logical-literal-constant -KEYWORD(TRUE , KEYALL) -KEYWORD(FALSE , KEYALL) +OPERATOR(TRUE , KEYALL) +OPERATOR(FALSE , KEYALL) KEYWORD(UNIT , KEYALL) KEYWORD(FMT , KEYALL) diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 8aa574f524..7f3fbbe3cf 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -90,6 +90,7 @@ void IdentifierTable::AddPredefineds(const LangOptions &LangOpts) { #define FORMAT_SPEC(NAME, FLAGS) \ AddPredefined(llvm::StringRef(#NAME), tok::fs_ ## NAME, \ FLAGS, LangOpts, *this, true); +#define OPERATOR(NAME, FLAGS) #include "flang/Basic/TokenKinds.def" } diff --git a/lib/CodeGen/CGArray.cpp b/lib/CodeGen/CGArray.cpp index 30974e2d63..459de63cd3 100644 --- a/lib/CodeGen/CGArray.cpp +++ b/lib/CodeGen/CGArray.cpp @@ -605,6 +605,12 @@ RValueTy ArrayOperationEmitter::VisitIntrinsicCallExpr(const IntrinsicCallExpr * Emit(Args[1]).asScalar() : nullptr); break; } + + case GROUP_BITOPS: { + return CGF.EmitBitOperation(Func, Emit(Args[0]).asScalar(), + Args.size() > 1? Emit(Args[1]).asScalar() : nullptr, + Args.size() > 2? Emit(Args[2]).asScalar() : nullptr); + } default: llvm_unreachable("invalid intrinsic group"); } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index e888d38742..a6c7464788 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -313,7 +313,7 @@ llvm::Value *ScalarExprEmitter::VisitBinaryExprOr(const BinaryExpr *E) { } llvm::Value *CodeGenFunction::EmitIntToInt32Conversion(llvm::Value *Value) { - return Value; // FIXME: Kinds + return Builder.CreateSExtOrTrunc(Value, CGM.Int32Ty); } llvm::Value *CodeGenFunction::EmitSizeIntToIntConversion(llvm::Value *Value) { @@ -420,5 +420,61 @@ llvm::Value *CodeGenFunction::GetConstantScalarMinValue(QualType T) { return EmitIntrinsicNumericInquiry(intrinsic::TINY, T, T); } +llvm::Value *CodeGenFunction::EmitBitOperation(intrinsic::FunctionKind Op, + llvm::Value *A1, llvm::Value *A2, + llvm::Value *A3) { + switch(Op) { + case intrinsic::NOT: + return Builder.CreateNot(A1); + case intrinsic::IAND: + return Builder.CreateAnd(A1, A2); + case intrinsic::IOR: + return Builder.CreateOr(A1, A2); + case intrinsic::IEOR: + return Builder.CreateXor(A1, A2); + case intrinsic::BTEST: { + auto Mask = Builder.CreateShl(llvm::ConstantInt::get(A1->getType(), 1), + Builder.CreateZExtOrTrunc(A2, A1->getType())); + auto Result = Builder.CreateAnd(A1, Mask); + return Builder.CreateSelect(Builder.CreateICmpNE(Result, llvm::ConstantInt::get(A1->getType(), 0)), + Builder.getTrue(), Builder.getFalse()); + } + case intrinsic::IBSET: { + auto Mask = Builder.CreateShl(llvm::ConstantInt::get(A1->getType(), 1), + Builder.CreateZExtOrTrunc(A2, A1->getType())); + return Builder.CreateOr(A1, Mask); + } + case intrinsic::IBCLR:{ + auto Mask = Builder.CreateNot( + Builder.CreateShl(llvm::ConstantInt::get(A1->getType(), 1), + Builder.CreateZExtOrTrunc(A2, A1->getType()))); + return Builder.CreateAnd(A1, Mask); + } + case intrinsic::IBITS: { + auto MaskOne = llvm::ConstantInt::get(A1->getType(), 1); + auto Mask = Builder.CreateSub(Builder.CreateShl(MaskOne, + Builder.CreateZExtOrTrunc(A3, A1->getType())), MaskOne); + return Builder.CreateAnd(Builder.CreateLShr(A1, Builder.CreateZExtOrTrunc(A2, A1->getType())), + Mask); + } + case intrinsic::ISHFT: { + auto A1Ty = A1->getType(); + if(auto Val = dyn_cast(A2)) { + if(Val->isNegative()) + return Builder.CreateLShr(A1, + Builder.CreateZExtOrTrunc(Builder.CreateNeg(A2), A1Ty)); + return Builder.CreateShl(A1, Builder.CreateZExtOrTrunc(A2, A1Ty)); + } + return Builder.CreateSelect(Builder.CreateICmpSGE(A2, llvm::ConstantInt::get(A2->getType(), 0)), + Builder.CreateShl(A1, Builder.CreateZExtOrTrunc(A2, A1Ty)), + Builder.CreateLShr(A1, + Builder.CreateZExtOrTrunc(Builder.CreateNeg(A2), A1Ty))); + } + // FIXME: ishftc + default: + llvm_unreachable("Invalid bit operation!"); + } +} + } } // end namespace flang diff --git a/lib/CodeGen/CGIntrinsic.cpp b/lib/CodeGen/CGIntrinsic.cpp index c1a200a7a2..af8da96806 100644 --- a/lib/CodeGen/CGIntrinsic.cpp +++ b/lib/CodeGen/CGIntrinsic.cpp @@ -110,6 +110,11 @@ RValueTy CodeGenFunction::EmitIntrinsicCall(const IntrinsicCallExpr *E) { return EmitInquiryIntrinsic(Func, Args); } + case GROUP_BITOPS: + return EmitBitOperation(Func, EmitScalarExpr(Args[0]), + Args.size() > 1? EmitScalarExpr(Args[1]) : nullptr, + Args.size() > 2? EmitScalarExpr(Args[2]) : nullptr); + default: llvm_unreachable("invalid intrinsic"); break; diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 785f071bc0..11d5a5cc01 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -316,6 +316,9 @@ public: llvm::Value *EmitFunctionPointer(const FunctionDecl *F); llvm::Value *GetConstantScalarMaxValue(QualType T); llvm::Value *GetConstantScalarMinValue(QualType T); + llvm::Value *EmitBitOperation(intrinsic::FunctionKind Op, + llvm::Value *A1, llvm::Value *A2, + llvm::Value *A3); // complex expressions. ComplexValueTy ExtractComplexValue(llvm::Value *Agg); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index ea626c5604..dd43fcfdc0 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -361,7 +361,7 @@ Parser::ExprResult Parser::ParseLevel2Expr() { Parser::ExprResult Parser::ParseLevel1Expr() { SourceLocation OpLoc = Tok.getLocation(); IdentifierInfo *II = 0; - if (IsPresent(tok::defined_operator)) { + if (IsPresent(tok::defined_operator) && !IsNextToken(tok::l_paren)) { II = Tok.getIdentifierInfo(); Lex(); } diff --git a/test/CodeGen/Intrinsics/bitops.f95 b/test/CodeGen/Intrinsics/bitops.f95 new file mode 100644 index 0000000000..9fe1c7ef4b --- /dev/null +++ b/test/CodeGen/Intrinsics/bitops.f95 @@ -0,0 +1,40 @@ +! RUN: %flang -emit-llvm -o - %s | %file_check %s + +PROGRAM bittest + + integer i + integer(8) i64 + logical l + + i = 12 + i = not(i) ! CHECK: xor i32 {{.*}}, -1 + i = iand(i, 15) ! CHECK: and i32 + i = iand(1,2) ! CHECK: store i32 0 + i = ior(i, 1) ! CHECK: or i32 + i = ior(7,8) ! CHECK: store i32 15 + i64 = ieor(i64, i64) ! CHECK: xor i64 + i = ieor(1,3) ! CHECK: store i32 2 + + l = btest(i, 2) ! CHECK: and i32 {{.*}}, 4 + continue ! CHECK-NEXT: icmp ne i32 + continue ! CHECK-NEXT: select i1 {{.*}}, i1 true, i1 false + l = btest(8,3) ! CHECK: store i32 1 + + i = ibset(i, 2) ! CHECK: or i32 {{.*}}, 4 + i = ibset(12,1) ! CHECK: store i32 14 + i64 = ibclr(i64, 1) ! CHECK: and i64 {{.*}}, -3 + i = ibclr(14,1) ! CHECK: store i32 12 + + i = ibits(i, 2, 4) ! CHECK: lshr i32 {{.*}}, 2 + continue ! CHECK-NEXT: and i32 {{.*}}, 15 + i = ibits(14, 1, 3) ! CHECK: store i32 7 + + i = ishft(i, 4) ! CHECK: shl i32 {{.*}}, 4 + i = ishft(i, -2) ! CHECK: lshr i32 {{.*}}, 2 + i = ishft(i, i/4) ! CHECK: icmp sge i32 {{.*}}, 0 + continue ! CHECK-NEXT: select i1 + + i = ishft(3, 1) ! CHECK: store i32 6 + i = ishft(8, -1) ! CHECK: store i32 4 + +end diff --git a/test/CodeGenInAction/arrayOperations.f95 b/test/CodeGenInAction/arrayOperations.f95 index ef7ab993da..21aacaf0df 100644 --- a/test/CodeGenInAction/arrayOperations.f95 +++ b/test/CodeGenInAction/arrayOperations.f95 @@ -62,4 +62,10 @@ program arrayops i_mat(1,3), ', ', i_mat(2,3), ', ', i_mat(3,3) continue ! CHECK-NEXT: 10, 10, 10, 10, 20, 10, 10, 10, 22 + i_mat = iand(i_mat, 7) + print *, i_mat(1,1), ', ', i_mat(2,1), ', ', i_mat(3,1), ', ', & + i_mat(1,2), ', ', i_mat(2,2), ', ', i_mat(3,2), ', ', & + i_mat(1,3), ', ', i_mat(2,3), ', ', i_mat(3,3) + continue ! CHECK-NEXT: 2, 2, 2, 2, 4, 2, 2, 2, 6 + end diff --git a/test/Sema/Intrinsics/bitops.f95 b/test/Sema/Intrinsics/bitops.f95 index 43fd36ae81..758db6869c 100644 --- a/test/Sema/Intrinsics/bitops.f95 +++ b/test/Sema/Intrinsics/bitops.f95 @@ -10,10 +10,9 @@ PROGRAM test integer(8) i64, i64_arr(10) logical l, l_arr(10) - ! FIXME: - !i = not(i) - !i = not(2.0) - !i = not(i64) + i = not(i) + i = not(2.0) ! expected-error {{passing 'real' to parameter of incompatible type 'integer'}} + i = not(i64) ! CHECK: i = int(not(i64)) i = iand(i,1) i = ior(i,i) ! CHECK: i = ior(i, i) -- cgit v1.2.1