OSDN Git Service

Add branch instructions to Subzero bitcode reader.
authorKarl Schimpf <kschimpf@google.com>
Fri, 5 Sep 2014 15:32:47 +0000 (08:32 -0700)
committerKarl Schimpf <kschimpf@google.com>
Fri, 5 Sep 2014 15:32:47 +0000 (08:32 -0700)
BUG= https://code.google.com/p/nativeclient/issues/detail?id=3894
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/545603003

src/PNaClTranslator.cpp
tests_lit/reader_tests/branch.ll [new file with mode: 0644]

index 2b92ad7..f315294 100644 (file)
@@ -865,6 +865,18 @@ private:
     return Nodes[Index];
   }
 
+  // Returns the Index-th basic block in the list of basic blocks.
+  // Assumes Index corresponds to a branch instruction. Hence, if
+  // the branch references the entry block, it also generates a
+  // corresponding error.
+  Ice::CfgNode *getBranchBasicBlock(uint32_t Index) {
+    if (Index == 0) {
+      Error("Branch to entry block not allowed");
+      // TODO(kschimpf) Remove error recovery once implementation complete.
+    }
+    return GetBasicBlock(Index);
+  }
+
   // Generates the next available local variable using the given
   // type.  Note: if Ty is void, this function returns NULL.
   Ice::Variable *NextInstVar(Ice::Type Ty) {
@@ -1203,7 +1215,12 @@ void FunctionParser::ExitBlock() {
       Node->appendInst(Ice::InstUnreachable::create(Func));
     }
   }
-  getTranslator().translateFcn(Func);
+  // Note: Once any errors have been found, we turn off all
+  // translation of all remaining functions. This allows use to see
+  // multiple errors, without adding extra checks to the translator
+  // for such parsing errors.
+  if (Context->getNumErrors() == 0)
+    getTranslator().translateFcn(Func);
 }
 
 void FunctionParser::ReportInvalidBinaryOp(Ice::InstArithmetic::OpKind Op,
@@ -1455,7 +1472,6 @@ void FunctionParser::ProcessRecord() {
   }
   case naclbitc::FUNC_CODE_INST_RET: {
     // RET: [opval?]
-    InstIsTerminating = true;
     if (!isValidRecordSizeInRange(0, 1, "function block ret"))
       return;
     if (Values.size() == 0) {
@@ -1463,6 +1479,35 @@ void FunctionParser::ProcessRecord() {
     } else {
       Inst = Ice::InstRet::create(Func, getRelativeOperand(Values[0]));
     }
+    InstIsTerminating = true;
+    break;
+  }
+  case naclbitc::FUNC_CODE_INST_BR: {
+    if (Values.size() == 1) {
+      // BR: [bb#]
+      Ice::CfgNode *Block = getBranchBasicBlock(Values[0]);
+      if (Block == NULL)
+        return;
+      Inst = Ice::InstBr::create(Func, Block);
+    } else {
+      // BR: [bb#, bb#, opval]
+      if (!isValidRecordSize(3, "function block branch"))
+        return;
+      Ice::Operand *Cond = getRelativeOperand(Values[2]);
+      if (Cond->getType() != Ice::IceType_i1) {
+        std::string Buffer;
+        raw_string_ostream StrBuf(Buffer);
+        StrBuf << "Branch condition not i1";
+        Error(StrBuf.str());
+        return;
+      }
+      Ice::CfgNode *ThenBlock = getBranchBasicBlock(Values[0]);
+      Ice::CfgNode *ElseBlock = getBranchBasicBlock(Values[1]);
+      if (ThenBlock == NULL || ElseBlock == NULL)
+        return;
+      Inst = Ice::InstBr::create(Func, Cond, ThenBlock, ElseBlock);
+    }
+    InstIsTerminating = true;
     break;
   }
   default:
diff --git a/tests_lit/reader_tests/branch.ll b/tests_lit/reader_tests/branch.ll
new file mode 100644 (file)
index 0000000..f57be6d
--- /dev/null
@@ -0,0 +1,46 @@
+; Tests if we handle a branch instructions.
+
+; RUN: llvm-as < %s | pnacl-freeze \
+; RUN:              | %llvm2ice -notranslate -verbose=inst -build-on-read \
+; RUN:                -allow-pnacl-reader-error-recovery \
+; RUN:              | FileCheck %s
+
+define void @SimpleBranch() {
+  br label %b3
+b1:
+  br label %b2
+b2:
+  ret void
+b3:
+  br label %b1
+}
+
+; CHECK:      define void @SimpleBranch() {
+; CHECK-NEXT: __0:
+; CHECK-NEXT:   br label %__3
+; CHECK-NEXT: __1:
+; CHECK-NEXT:   br label %__2
+; CHECK-NEXT: __2:
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: __3:
+; CHECK-NEXT:   br label %__1
+; CHECK-NEXT: }
+
+define void @CondBranch(i32 %p) {
+  %test = trunc i32 %p to i1
+  br i1 %test, label %b1, label %b2
+b1:
+  ret void
+b2:
+  br i1 %test, label %b2, label %b1
+}
+
+; CHECK-NEXT: define void @CondBranch(i32 %__0) {
+; CHECK-NEXT: __0:
+; CHECK-NEXT:   %__1 = trunc i32 %__0 to i1
+; CHECK-NEXT:   br i1 %__1, label %__1, label %__2
+; CHECK-NEXT: __1:
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: __2:
+; CHECK-NEXT:   br i1 %__1, label %__2, label %__1
+; CHECK-NEXT: }