Index: lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIParser.cpp +++ lib/CodeGen/MIRParser/MIParser.cpp @@ -1306,7 +1306,7 @@ if (Token.range().front() == 's' || Token.range().front() == 'p') { StringRef SizeStr = Token.range().drop_front(); if (SizeStr.size() == 0 || !llvm::all_of(SizeStr, isdigit)) - return error("Expected integers after 's'/'p' type character"); + return error("expected integers after 's'/'p' type character"); } if (Token.range().front() == 's') { @@ -1324,32 +1324,39 @@ // Now we're looking for a vector. if (Token.isNot(MIToken::less)) return error(Loc, - "expected unsized, pN, sN or for GlobalISel type"); - + "expected sN, pA, , or for GlobalISel type"); lex(); if (Token.isNot(MIToken::IntegerLiteral)) - return error(Loc, "expected for vctor type"); + return error(Loc, "expected or for vector type"); uint64_t NumElements = Token.integerValue().getZExtValue(); lex(); if (Token.isNot(MIToken::Identifier) || Token.stringValue() != "x") - return error(Loc, "expected '' for vector type"); + return error(Loc, "expected or for vector type"); lex(); - if (Token.range().front() != 's') - return error(Loc, "expected '' for vector type"); + if (Token.range().front() != 's' && Token.range().front() != 'p') + return error(Loc, "expected or for vector type"); StringRef SizeStr = Token.range().drop_front(); if (SizeStr.size() == 0 || !llvm::all_of(SizeStr, isdigit)) - return error("Expected integers after 's' type character"); - uint64_t ScalarSize = APSInt(Token.range().drop_front()).getZExtValue(); + return error("expected integers after 's'/'p' type character"); + + if (Token.range().front() == 's') + Ty = LLT::scalar(APSInt(Token.range().drop_front()).getZExtValue()); + else if (Token.range().front() == 'p') { + const DataLayout &DL = MF.getDataLayout(); + unsigned AS = APSInt(Token.range().drop_front()).getZExtValue(); + Ty = LLT::pointer(AS, DL.getPointerSizeInBits(AS)); + } else + return error(Loc, "expected or for vector type"); lex(); if (Token.isNot(MIToken::greater)) - return error(Loc, "expected '' for vector type"); + return error(Loc, "expected or for vector type"); lex(); - Ty = LLT::vector(NumElements, ScalarSize); + Ty = LLT::vector(NumElements, Ty); return false; } @@ -1359,10 +1366,10 @@ if (TypeStr.front() != 'i' && TypeStr.front() != 's' && TypeStr.front() != 'p') return error( - "A typed immediate operand should start with one of 'i', 's', or 'p'"); + "a typed immediate operand should start with one of 'i', 's', or 'p'"); StringRef SizeStr = Token.range().drop_front(); if (SizeStr.size() == 0 || !llvm::all_of(SizeStr, isdigit)) - return error("Expected integers after 'i'/'s'/'p' type character"); + return error("expected integers after 'i'/'s'/'p' type character"); auto Loc = Token.location(); lex(); Index: lib/CodeGen/MachineVerifier.cpp =================================================================== --- lib/CodeGen/MachineVerifier.cpp +++ lib/CodeGen/MachineVerifier.cpp @@ -986,6 +986,58 @@ MI); break; } + case TargetOpcode::G_SEXT: + case TargetOpcode::G_ZEXT: + case TargetOpcode::G_ANYEXT: + case TargetOpcode::G_TRUNC: + case TargetOpcode::G_FPEXT: + case TargetOpcode::G_FPTRUNC: { + // Number of operands and presense of types is already checked (and + // reported in case of any issues), so no need to report them again. As + // we're trying to report as many issues as possible at once, however, the + // instructions aren't guaranteed to have the right number of operands or + // types attached to them at this point + assert(MCID.getNumOperands() == 2 && "Expected 2 operands G_*{EXT,TRUNC}"); + if (MI->getNumOperands() < MCID.getNumOperands()) + break; + LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); + LLT SrcTy = MRI->getType(MI->getOperand(1).getReg()); + if (!DstTy.isValid() || !SrcTy.isValid()) + break; + + LLT DstElTy = DstTy.isVector() ? DstTy.getElementType() : DstTy; + LLT SrcElTy = SrcTy.isVector() ? SrcTy.getElementType() : SrcTy; + if (DstElTy.isPointer() || SrcElTy.isPointer()) + report("Generic extend/truncate can not operate on pointers", MI); + + if (DstTy.isVector() != SrcTy.isVector()) { + report("Generic extend/truncate must be all-vector or all-scalar", MI); + // Generally we try to report as many issues as possible at once, but in + // this case it's not clear what should we be comparing the size of the + // scalar with: the size of the whole vector or its lane. Instead of + // making an arbitrary choice and emitting not so helpful message, let's + // avoid the extra noise and stop here. + break; + } + if (DstTy.isVector() && DstTy.getNumElements() != SrcTy.getNumElements()) + report("Generic vector extend/truncate must preserve number of lanes", + MI); + unsigned DstSize = DstElTy.getSizeInBits(); + unsigned SrcSize = SrcElTy.getSizeInBits(); + switch (MI->getOpcode()) { + default: + if (DstSize <= SrcSize) + report("Generic extend has destination type no larger than source", MI); + break; + case TargetOpcode::G_TRUNC: + case TargetOpcode::G_FPTRUNC: + if (DstSize >= SrcSize) + report("Generic truncate has destination type no smaller than source", + MI); + break; + } + break; + } case TargetOpcode::COPY: { if (foundErrors) break; Index: test/CodeGen/AMDGPU/GlobalISel/regbankselect-trunc.mir =================================================================== --- test/CodeGen/AMDGPU/GlobalISel/regbankselect-trunc.mir +++ test/CodeGen/AMDGPU/GlobalISel/regbankselect-trunc.mir @@ -10,9 +10,9 @@ bb.0: liveins: $sgpr0_sgpr1 ; CHECK-LABEL: name: trunc_i64_to_i32_s - ; CHECK: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0 - ; CHECK: [[TRUNC:%[0-9]+]]:sgpr(s32) = G_TRUNC [[COPY]](s32) - %0:_(s32) = COPY $sgpr0 + ; CHECK: [[COPY:%[0-9]+]]:sgpr(s64) = COPY $sgpr0 + ; CHECK: [[TRUNC:%[0-9]+]]:sgpr(s32) = G_TRUNC [[COPY]](s64) + %0:_(s64) = COPY $sgpr0_sgpr1 %1:_(s32) = G_TRUNC %0 ... @@ -24,8 +24,8 @@ bb.0: liveins: $vgpr0_vgpr1 ; CHECK-LABEL: name: trunc_i64_to_i32_v - ; CHECK: [[COPY:%[0-9]+]]:vgpr(s32) = COPY $vgpr0 - ; CHECK: [[TRUNC:%[0-9]+]]:vgpr(s32) = G_TRUNC [[COPY]](s32) - %0:_(s32) = COPY $vgpr0 + ; CHECK: [[COPY:%[0-9]+]]:vgpr(s64) = COPY $vgpr0 + ; CHECK: [[TRUNC:%[0-9]+]]:vgpr(s32) = G_TRUNC [[COPY]](s64) + %0:_(s64) = COPY $vgpr0_vgpr1 %1:_(s32) = G_TRUNC %0 ... Index: test/CodeGen/MIR/AArch64/parse-low-level-type-invalid0.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/AArch64/parse-low-level-type-invalid0.mir @@ -0,0 +1,10 @@ +# RUN: not llc -mtriple=aarch64-- -run-pass none -o /dev/null %s 2>&1 | FileCheck %s +# When a low-level type is only a single 's'/'p' character +--- +name: test_low_level_type_is_single_s_p +body: | + bb.0: + liveins: $x0 + ; CHECK: [[@LINE+1]]:10: expected integers after 's'/'p' type character + %0:_(s) = COPY $x0 +... Index: test/CodeGen/MIR/AArch64/parse-low-level-type-invalid1.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/AArch64/parse-low-level-type-invalid1.mir @@ -0,0 +1,10 @@ +# RUN: not llc -mtriple=aarch64-- -run-pass none -o /dev/null %s 2>&1 | FileCheck %s +# When a low-level type does not start with 's', 'p', or '<' +--- +name: test_low_level_type_does_not_start_with_s_p_lt +body: | + bb.0: + liveins: $x0 + ; CHECK: [[@LINE+1]]:10: expected sN, pA, , or for GlobalISel type + %0:_(i64) = COPY $x0 +... Index: test/CodeGen/MIR/AArch64/parse-low-level-type-invalid2.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/AArch64/parse-low-level-type-invalid2.mir @@ -0,0 +1,10 @@ +# RUN: not llc -mtriple=aarch64-- -run-pass none -o /dev/null %s 2>&1 | FileCheck %s +# When a low-level type is a vector with only a single 's'/'p' character for element type +--- +name: test_low_level_type_is_single_s_p +body: | + bb.0: + liveins: $q0 + ; CHECK: [[@LINE+1]]:15: expected integers after 's'/'p' type character + %0:_(<2 x p>) = COPY $q0 +... Index: test/CodeGen/MIR/AArch64/parse-low-level-type-invalid3.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/AArch64/parse-low-level-type-invalid3.mir @@ -0,0 +1,10 @@ +# RUN: not llc -mtriple=aarch64-- -run-pass none -o /dev/null %s 2>&1 | FileCheck %s +# When a low-level type is a vector which element type does not start with 's' or 'p' +--- +name: test_low_level_type_does_not_start_with_s_p +body: | + bb.0: + liveins: $q0 + ; CHECK: [[@LINE+1]]:10: expected or for vector type + %0:_(<2 x i64>) = COPY $q0 +... Index: test/CodeGen/MIR/AArch64/print-parse-vector-of-pointers-llt.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/AArch64/print-parse-vector-of-pointers-llt.mir @@ -0,0 +1,11 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple=aarch64-- -run-pass none -o - %s 2>&1 | FileCheck %s +--- +name: test_vector_of_pointers_llt +body: | + bb.0: + liveins: $q0 + ; CHECK-LABEL: name: test_vector_of_pointers_llt + ; CHECK: [[COPY:%[0-9]+]]:_(<2 x p0>) = COPY $q0 + %0:_(<2 x p0>) = COPY $q0 +... Index: test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid0.mir =================================================================== --- test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid0.mir +++ test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid0.mir @@ -7,7 +7,7 @@ body: | bb.0: liveins: $arguments - ; CHECK: [[@LINE+1]]:24: Expected integers after 'i'/'s'/'p' type character + ; CHECK: [[@LINE+1]]:24: expected integers after 'i'/'s'/'p' type character %0:i32 = CONST_I32 i 0, implicit-def dead $arguments RETURN_VOID implicit-def dead $arguments ... Index: test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid1.mir =================================================================== --- test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid1.mir +++ test/CodeGen/MIR/WebAssembly/typed-immediate-operand-invalid1.mir @@ -7,7 +7,7 @@ body: | bb.0: liveins: $arguments - ; CHECK: [[@LINE+1]]:24: A typed immediate operand should start with one of 'i', 's', or 'p' + ; CHECK: [[@LINE+1]]:24: a typed immediate operand should start with one of 'i', 's', or 'p' %0:i32 = CONST_I32 abc 0, implicit-def dead $arguments RETURN_VOID implicit-def dead $arguments ... Index: test/CodeGen/X86/verifier-generic-extend-truncate.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/verifier-generic-extend-truncate.mir @@ -0,0 +1,87 @@ +# RUN: not llc -o - %s -mtriple=x86_64-- -verify-machineinstrs -run-pass=none 2>&1 | FileCheck %s + +# CHECK: Bad machine code: Generic extend/truncate can not operate on pointers +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.1 +# CHECK-NEXT: - instruction: %t_p:_(s32) = G_TRUNC %p:_(p0) + +# CHECK: Bad machine code: Generic extend/truncate must be all-vector or all-scalar +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.2 +# CHECK-NEXT: - instruction: %se_i32:_(<2 x s64>) = G_SEXT %i32:_(s32) + +# CHECK: Bad machine code: Generic vector extend/truncate must preserve number of lanes +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.3 +# CHECK-NEXT: - instruction: %ze_v2i32:_(<4 x s64>) = G_ZEXT %v2i32:_(<2 x s32>) + +# CHECK: Bad machine code: Generic extend has destination type no larger than source +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.4 +# CHECK-NEXT: - instruction: %ae_i32:_(s32) = G_ANYEXT %i32:_(s32) + +# CHECK: Bad machine code: Generic truncate has destination type no smaller than source *** +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.5 +# CHECK-NEXT: - instruction: %ft_f32:_(s64) = G_FPTRUNC %f32:_(s32) + + +# CHECK: Bad machine code: Generic extend/truncate can not operate on pointers +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.6 +# CHECK-NEXT: - instruction: %ze_v2i128:_(<4 x p0>) = G_ZEXT %v2i128:_(<2 x s128>) + +# CHECK: Bad machine code: Generic vector extend/truncate must preserve number of lanes +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.6 +# CHECK-NEXT: - instruction: %ze_v2i128:_(<4 x p0>) = G_ZEXT %v2i128:_(<2 x s128>) + +# CHECK: Bad machine code: Generic extend has destination type no larger than source +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.6 +# CHECK-NEXT: - instruction: %ze_v2i128:_(<4 x p0>) = G_ZEXT %v2i128:_(<2 x s128>) + + +# CHECK: Bad machine code: Generic extend/truncate can not operate on pointers +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.6 +# CHECK-NEXT: - instruction: %fe_v2f128:_(p0) = G_FPEXT %v2f128:_(<2 x s128>) + +# CHECK: Bad machine code: Generic extend/truncate must be all-vector or all-scalar +# CHECK-NEXT: - function: bad_generic_extends_and_truncates +# CHECK-NEXT: - basic block: %bb.6 +# CHECK-NEXT: - instruction: %fe_v2f128:_(p0) = G_FPEXT %v2f128:_(<2 x s128>) + +--- +name: bad_generic_extends_and_truncates +tracksRegLiveness: true +body: | + bb.0: + liveins: $rdi, $esi, $rdx, $xmm0, $ymm1, $ymm2 + + %p:_(p0) = COPY $rdi + %i32:_(s32) = COPY $esi + %v2i32:_(<2 x s32>) = COPY $rdx + %f32:_(s32) = COPY $xmm0 + %v2i128:_(<2 x s128>) = COPY $ymm1 + %v2f128:_(<2 x s128>) = COPY $ymm2 + + bb.1: + %t_p:_(s32) = G_TRUNC %p + + bb.2: + %se_i32:_(<2 x s64>) = G_SEXT %i32 + + bb.3: + %ze_v2i32:_(<4 x s64>) = G_ZEXT %v2i32 + + bb.4: + %ae_i32:_(s32) = G_ANYEXT %i32 + + bb.5: + %ft_f32:_(s64) = G_FPTRUNC %f32 + + bb.6: + %ze_v2i128:_(<4 x p0>) = G_ZEXT %v2i128 + %fe_v2f128:_(p0) = G_FPEXT %v2f128 +...