summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorarphaman <arphaman@gmail.com>2013-09-19 11:16:17 +0100
committerarphaman <arphaman@gmail.com>2013-09-19 11:16:17 +0100
commit0d24145a7bcb6561c18701cfe32ef1fc1496acd7 (patch)
tree89b1da141140dfc2e48f93645b910f3f0ec54700
parenta6262ee5f15927e70c2b733334a7f2c3e4804354 (diff)
downloadflang-0d24145a7bcb6561c18701cfe32ef1fc1496acd7.tar.gz
added codegen for bit operations
-rw-r--r--include/flang/Basic/TokenKinds.def29
-rw-r--r--lib/Basic/IdentifierTable.cpp1
-rw-r--r--lib/CodeGen/CGArray.cpp6
-rw-r--r--lib/CodeGen/CGExprScalar.cpp58
-rw-r--r--lib/CodeGen/CGIntrinsic.cpp5
-rw-r--r--lib/CodeGen/CodeGenFunction.h3
-rw-r--r--lib/Parse/ParseExpr.cpp2
-rw-r--r--test/CodeGen/Intrinsics/bitops.f9540
-rw-r--r--test/CodeGenInAction/arrayOperations.f956
-rw-r--r--test/Sema/Intrinsics/bitops.f957
10 files changed, 138 insertions, 19 deletions
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<llvm::ConstantInt>(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)