Add constants block to PNaCl bitcode reader.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=3894
R=jvoung@chromium.org, stichnot@chromium.org
Review URL: https://codereview.chromium.org/548553002
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index f315294..5bfa33b 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -821,6 +821,9 @@
~FunctionParser() LLVM_OVERRIDE;
+ // Set the next constant ID to the given constant C.
+ void setNextConstantID(Ice::Constant *C) { LocalOperands.push_back(C); }
+
private:
// Timer for reading function bitcode and converting to ICE.
Ice::Timer TConvert;
@@ -843,6 +846,8 @@
// instruction.
bool InstIsTerminating;
+ virtual bool ParseBlock(unsigned BlockID) LLVM_OVERRIDE;
+
virtual void ProcessRecord() LLVM_OVERRIDE;
virtual void ExitBlock() LLVM_OVERRIDE;
@@ -1519,6 +1524,130 @@
CurrentNode->appendInst(Inst);
}
+/// Parses constants within a function block.
+class ConstantsParser : public BlockParserBaseClass {
+ ConstantsParser(const ConstantsParser &) LLVM_DELETED_FUNCTION;
+ ConstantsParser &operator=(const ConstantsParser &) LLVM_DELETED_FUNCTION;
+
+public:
+ ConstantsParser(unsigned BlockID, FunctionParser *FuncParser)
+ : BlockParserBaseClass(BlockID, FuncParser), FuncParser(FuncParser),
+ NextConstantType(Ice::IceType_void) {}
+
+ ~ConstantsParser() LLVM_OVERRIDE {}
+
+private:
+ // The parser of the function block this constants block appears in.
+ FunctionParser *FuncParser;
+ // The type to use for succeeding constants.
+ Ice::Type NextConstantType;
+
+ virtual void ProcessRecord() LLVM_OVERRIDE;
+
+ Ice::GlobalContext *getContext() { return getTranslator().getContext(); }
+
+ // Returns true if the type to use for succeeding constants is defined.
+ // If false, also generates an error message.
+ bool isValidNextConstantType() {
+ if (NextConstantType != Ice::IceType_void)
+ return true;
+ Error("Constant record not preceded by set type record");
+ return false;
+ }
+};
+
+void ConstantsParser::ProcessRecord() {
+ const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
+ switch (Record.GetCode()) {
+ case naclbitc::CST_CODE_SETTYPE: {
+ // SETTYPE: [typeid]
+ if (!isValidRecordSize(1, "constants block set type"))
+ return;
+ NextConstantType =
+ Context->convertToIceType(Context->getTypeByID(Values[0]));
+ if (NextConstantType == Ice::IceType_void)
+ Error("constants block set type not allowed for void type");
+ return;
+ }
+ case naclbitc::CST_CODE_UNDEF: {
+ // UNDEF
+ if (!isValidRecordSize(0, "constants block undef"))
+ return;
+ if (!isValidNextConstantType())
+ return;
+ FuncParser->setNextConstantID(
+ getContext()->getConstantUndef(NextConstantType));
+ return;
+ }
+ case naclbitc::CST_CODE_INTEGER: {
+ // INTEGER: [intval]
+ if (!isValidRecordSize(1, "constants block integer"))
+ return;
+ if (!isValidNextConstantType())
+ return;
+ if (IntegerType *IType = dyn_cast<IntegerType>(
+ Context->convertToLLVMType(NextConstantType))) {
+ APInt Value(IType->getBitWidth(), NaClDecodeSignRotatedValue(Values[0]));
+ Ice::Constant *C =
+ getContext()->getConstantInt(NextConstantType, Value.getSExtValue());
+ FuncParser->setNextConstantID(C);
+ return;
+ }
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "constant block integer record for non-integer type "
+ << NextConstantType;
+ Error(StrBuf.str());
+ return;
+ }
+ case naclbitc::CST_CODE_FLOAT: {
+ // FLOAT: [fpval]
+ if (!isValidRecordSize(1, "constants block float"))
+ return;
+ if (!isValidNextConstantType())
+ return;
+ switch (NextConstantType) {
+ case Ice::IceType_f32: {
+ APFloat Value(APFloat::IEEEsingle,
+ APInt(32, static_cast<uint32_t>(Values[0])));
+ FuncParser->setNextConstantID(
+ getContext()->getConstantFloat(Value.convertToFloat()));
+ return;
+ }
+ case Ice::IceType_f64: {
+ APFloat Value(APFloat::IEEEdouble, APInt(64, Values[0]));
+ FuncParser->setNextConstantID(
+ getContext()->getConstantDouble(Value.convertToDouble()));
+ return;
+ }
+ default: {
+ std::string Buffer;
+ raw_string_ostream StrBuf(Buffer);
+ StrBuf << "constant block float record for non-floating type "
+ << NextConstantType;
+ Error(StrBuf.str());
+ return;
+ }
+ }
+ }
+ default:
+ // Generate error message!
+ BlockParserBaseClass::ProcessRecord();
+ return;
+ }
+}
+
+bool FunctionParser::ParseBlock(unsigned BlockID) {
+ switch (BlockID) {
+ case naclbitc::CONSTANTS_BLOCK_ID: {
+ ConstantsParser Parser(BlockID, this);
+ return Parser.ParseThisBlock();
+ }
+ default:
+ return BlockParserBaseClass::ParseBlock(BlockID);
+ }
+}
+
/// Parses the module block in the bitcode file.
class ModuleParser : public BlockParserBaseClass {
public:
diff --git a/tests_lit/reader_tests/constants.ll b/tests_lit/reader_tests/constants.ll
new file mode 100644
index 0000000..43827b0
--- /dev/null
+++ b/tests_lit/reader_tests/constants.ll
@@ -0,0 +1,155 @@
+; Test handling of constants in function blocks.
+
+; 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 @TestIntegers() {
+; CHECK: __0:
+
+ ; Test various sized integers
+ %v0 = or i1 true, false
+; CHECK-NEXT: %__0 = or i1 true, false
+
+ %v1 = add i8 0, 0
+; CHECK-NEXT: %__1 = add i8 0, 0
+
+ %v2 = add i8 5, 0
+; CHECK-NEXT: %__2 = add i8 5, 0
+
+ %v3 = add i8 -5, 0
+; CHECK-NEXT: %__3 = add i8 -5, 0
+
+ %v4 = and i16 10, 0
+; CHECK-NEXT: %__4 = and i16 10, 0
+
+ %v5 = add i16 -10, 0
+; CHECK-NEXT: %__5 = add i16 -10, 0
+
+ %v6 = add i32 20, 0
+; CHECK-NEXT: %__6 = add i32 20, 0
+
+ %v7 = add i32 -20, 0
+; CHECK-NEXT: %__7 = add i32 -20, 0
+
+ %v8 = add i64 30, 0
+; CHECK-NEXT: %__8 = add i64 30, 0
+
+ %v9 = add i64 -30, 0
+; CHECK-NEXT: %__9 = add i64 -30, 0
+
+ ; Test undefined integer values.
+ %v10 = xor i1 undef, false
+; CHECK-NEXT: %__10 = xor i1 undef, false
+
+ %v11 = add i8 undef, 0
+; CHECK-NEXT: %__11 = add i8 undef, 0
+
+ %v12 = add i16 undef, 0
+; CHECK-NEXT: %__12 = add i16 undef, 0
+
+ %v13 = add i32 undef, 0
+; CHECK-NEXT: %__13 = add i32 undef, 0
+
+ %v14 = add i64 undef, 0
+; CHECK-NEXT: %__14 = add i64 undef, 0
+
+ ret void
+; CHECK-NEXT: ret void
+
+}
+
+define void @TestFloats() {
+; CHECK: __0:
+
+ ; Test float and double constants
+ %v0 = fadd float 1.0, 0.0
+; CHECK-NEXT: %__0 = fadd float 1.000000e+00, 0.000000e+00
+
+ %v1 = fadd double 1.0, 0.0
+; CHECK-NEXT: %__1 = fadd double 1.000000e+00, 0.000000e+00
+
+ %v2 = fsub float 7.000000e+00, 8.000000e+00
+; CHECK-NEXT: %__2 = fsub float 7.000000e+00, 8.000000e+00
+
+ %v3 = fsub double 5.000000e+00, 6.000000e+00
+; CHECK-NEXT: %__3 = fsub double 5.000000e+00, 6.000000e+00
+
+ ; Test undefined float and double.
+ %v4 = fadd float undef, 0.0
+; CHECK-NEXT: %__4 = fadd float undef, 0.000000e+00
+
+ %v5 = fsub double undef, 6.000000e+00
+; CHECK-NEXT: %__5 = fsub double undef, 6.000000e+00
+
+ ; Test special floating point constants. Note: LLVM assembly appears
+ ; to use 64-bit integer constants for both float and double.
+
+ ; Generated from NAN in <math.h>
+ %v6 = fadd float 0x7FF8000000000000, 0.0
+; CHECK-NEXT: %__6 = fadd float nan, 0.000000e+00
+
+ ; Generated from -NAN in <math.h>
+ %v7 = fadd float 0xFFF8000000000000, 0.0
+; CHECK-NEXT: %__7 = fadd float -nan, 0.000000e+00
+
+ ; Generated from INFINITY in <math.h>
+ %v8 = fadd float 0x7FF0000000000000, 0.0
+; CHECK-NEXT: %__8 = fadd float inf, 0.000000e+00
+
+ ; Generated from -INFINITY in <math.h>
+ %v9 = fadd float 0xFFF0000000000000, 0.0
+; CHECK-NEXT: %__9 = fadd float -inf, 0.000000e+00
+
+ ; Generated from FLT_MIN in <float.h>
+ %v10 = fadd float 0x381000000000000000, 0.0
+; CHECK-NEXT: %__10 = fadd float 0.000000e+00, 0.000000e+00
+
+ ; Generated from -FLT_MIN in <float.h>
+ %v11 = fadd float 0xb81000000000000000, 0.0
+; CHECK-NEXT: %__11 = fadd float 0.000000e+00, 0.000000e+00
+
+ ; Generated from FLT_MAX in <float.h>
+ %v12 = fadd float 340282346638528859811704183484516925440.000000, 0.0
+; CHECK-NEXT: %__12 = fadd float 3.402823e+38, 0.000000e+00
+
+ ; Generated from -FLT_MAX in <float.h>
+ %v13 = fadd float -340282346638528859811704183484516925440.000000, 0.0
+; CHECK-NEXT: %__13 = fadd float -3.402823e+38, 0.000000e+00
+
+ ; Generated from NAN in <math.h>
+ %v14 = fadd double 0x7FF8000000000000, 0.0
+; CHECK-NEXT: %__14 = fadd double nan, 0.000000e+00
+
+ ; Generated from -NAN in <math.h>
+ %v15 = fadd double 0xFFF8000000000000, 0.0
+; CHECK-NEXT: %__15 = fadd double -nan, 0.000000e+00
+
+ ; Generated from INFINITY in <math.h>
+ %v16 = fadd double 0x7FF0000000000000, 0.0
+; CHECK-NEXT: %__16 = fadd double inf, 0.000000e+00
+
+ ; Generated from -INFINITY in <math.h>
+ %v17 = fadd double 0xFFF0000000000000, 0.0
+; CHECK-NEXT: %__17 = fadd double -inf, 0.000000e+00
+
+ ; Generated from DBL_MIN in <float.h>
+ %v18 = fadd double 0x0010000000000000, 0.0
+; CHECK-NEXT: %__18 = fadd double 2.225074e-308, 0.000000e+00
+
+ ; Generated from -DBL_MIN in <float.h>
+ %v19 = fadd double 0x8010000000000000, 0.0
+; CHECK-NEXT: %__19 = fadd double -2.225074e-308, 0.000000e+00
+
+ ; Generated from DBL_MAX in <float.h>
+ %v20 = fadd double 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000, 0.0
+; CHECK-NEXT: %__20 = fadd double 1.797693e+308, 0.000000e+00
+
+ ; Generated from -DBL_MAX in <float.h>
+ %v21 = fadd double -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000, 0.0
+; CHECK-NEXT: %__21 = fadd double -1.797693e+308, 0.000000e+00
+
+ ret void
+; CHECK-NEXT: ret void
+}